ソースを参照

Templatized serial classes (#11982)

Eduardo José Tagle 6年前
コミット
f6f2246f59

+ 219
- 240
Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp ファイルの表示

29
  * Modified 14 February 2016 by Andreas Hardtung (added tx buffer)
29
  * Modified 14 February 2016 by Andreas Hardtung (added tx buffer)
30
  * Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF)
30
  * Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF)
31
  * Modified 10 June 2018 by Eduardo José Tagle (See #10991)
31
  * Modified 10 June 2018 by Eduardo José Tagle (See #10991)
32
+ * Templatized 01 October 2018 by Eduardo José Tagle to allow multiple instances
32
  */
33
  */
33
 
34
 
34
 #ifdef __AVR__
35
 #ifdef __AVR__
42
   #include "MarlinSerial.h"
43
   #include "MarlinSerial.h"
43
   #include "../../Marlin.h"
44
   #include "../../Marlin.h"
44
 
45
 
45
-  struct ring_buffer_r {
46
-    unsigned char buffer[RX_BUFFER_SIZE];
47
-    volatile ring_buffer_pos_t head, tail;
48
-  };
49
-
50
-  #if TX_BUFFER_SIZE > 0
51
-    struct ring_buffer_t {
52
-      unsigned char buffer[TX_BUFFER_SIZE];
53
-      volatile uint8_t head, tail;
54
-    };
55
-  #endif
56
-
57
-  #if UART_PRESENT(SERIAL_PORT)
58
-    ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
59
-    #if TX_BUFFER_SIZE > 0
60
-      ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
61
-    #endif
62
-    static bool _written;
63
-  #endif
64
-
65
-  #if ENABLED(SERIAL_XON_XOFF)
66
-    constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80,  // XON / XOFF Character was sent
67
-                      XON_XOFF_CHAR_MASK = 0x1F;  // XON / XOFF character to send
68
-    // XON / XOFF character definitions
69
-    constexpr uint8_t XON_CHAR  = 17, XOFF_CHAR = 19;
70
-    uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR;
71
-  #endif
72
-
73
-  #if ENABLED(SERIAL_STATS_DROPPED_RX)
74
-    uint8_t rx_dropped_bytes = 0;
75
-  #endif
76
-
77
-  #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
78
-    uint8_t rx_buffer_overruns = 0;
79
-  #endif
80
-
81
-  #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
82
-    uint8_t rx_framing_errors = 0;
83
-  #endif
84
-
85
-  #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
86
-    ring_buffer_pos_t rx_max_enqueued = 0;
87
-  #endif
46
+  template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_r MarlinSerial<Cfg>::rx_buffer = { 0 };
47
+  template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_t MarlinSerial<Cfg>::tx_buffer = { 0 };
48
+  template<typename Cfg> bool     MarlinSerial<Cfg>::_written = false;
49
+  template<typename Cfg> uint8_t  MarlinSerial<Cfg>::xon_xoff_state = MarlinSerial<Cfg>::XON_XOFF_CHAR_SENT | MarlinSerial<Cfg>::XON_CHAR;
50
+  template<typename Cfg> uint8_t  MarlinSerial<Cfg>::rx_dropped_bytes = 0;
51
+  template<typename Cfg> uint8_t  MarlinSerial<Cfg>::rx_buffer_overruns = 0;
52
+  template<typename Cfg> uint8_t  MarlinSerial<Cfg>::rx_framing_errors = 0;
53
+  template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::rx_max_enqueued = 0;
88
 
54
 
89
   // A SW memory barrier, to ensure GCC does not overoptimize loops
55
   // A SW memory barrier, to ensure GCC does not overoptimize loops
90
   #define sw_barrier() asm volatile("": : :"memory");
56
   #define sw_barrier() asm volatile("": : :"memory");
91
 
57
 
92
-  #if ENABLED(EMERGENCY_PARSER)
93
-    #include "../../feature/emergency_parser.h"
94
-  #endif
58
+  #include "../../feature/emergency_parser.h"
95
 
59
 
96
   // "Atomically" read the RX head index value without disabling interrupts:
60
   // "Atomically" read the RX head index value without disabling interrupts:
97
   // This MUST be called with RX interrupts enabled, and CAN'T be called
61
   // This MUST be called with RX interrupts enabled, and CAN'T be called
98
   // from the RX ISR itself!
62
   // from the RX ISR itself!
99
-  FORCE_INLINE ring_buffer_pos_t atomic_read_rx_head() {
100
-    #if RX_BUFFER_SIZE > 256
63
+  template<typename Cfg>
64
+  FORCE_INLINE typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::atomic_read_rx_head() {
65
+    if (Cfg::RX_SIZE > 256) {
101
       // Keep reading until 2 consecutive reads return the same value,
66
       // Keep reading until 2 consecutive reads return the same value,
102
       // meaning there was no update in-between caused by an interrupt.
67
       // meaning there was no update in-between caused by an interrupt.
103
       // This works because serial RX interrupts happen at a slower rate
68
       // This works because serial RX interrupts happen at a slower rate
111
         sw_barrier();
76
         sw_barrier();
112
       } while (vold != vnew);
77
       } while (vold != vnew);
113
       return vnew;
78
       return vnew;
114
-    #else
79
+    }
80
+    else {
115
       // With an 8bit index, reads are always atomic. No need for special handling
81
       // With an 8bit index, reads are always atomic. No need for special handling
116
       return rx_buffer.head;
82
       return rx_buffer.head;
117
-    #endif
83
+    }
118
   }
84
   }
119
 
85
 
120
-  #if RX_BUFFER_SIZE > 256
121
-    static volatile bool rx_tail_value_not_stable = false;
122
-    static volatile uint16_t rx_tail_value_backup = 0;
123
-  #endif
86
+  template<typename Cfg>
87
+  volatile bool MarlinSerial<Cfg>::rx_tail_value_not_stable = false;
88
+  template<typename Cfg>
89
+  volatile uint16_t MarlinSerial<Cfg>::rx_tail_value_backup = 0;
124
 
90
 
125
   // Set RX tail index, taking into account the RX ISR could interrupt
91
   // Set RX tail index, taking into account the RX ISR could interrupt
126
   //  the write to this variable in the middle - So a backup strategy
92
   //  the write to this variable in the middle - So a backup strategy
127
   //  is used to ensure reads of the correct values.
93
   //  is used to ensure reads of the correct values.
128
   //    -Must NOT be called from the RX ISR -
94
   //    -Must NOT be called from the RX ISR -
129
-  FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value) {
130
-    #if RX_BUFFER_SIZE > 256
95
+  template<typename Cfg>
96
+  FORCE_INLINE void MarlinSerial<Cfg>::atomic_set_rx_tail(typename MarlinSerial<Cfg>::ring_buffer_pos_t value) {
97
+    if (Cfg::RX_SIZE > 256) {
131
       // Store the new value in the backup
98
       // Store the new value in the backup
132
       rx_tail_value_backup = value;
99
       rx_tail_value_backup = value;
133
       sw_barrier();
100
       sw_barrier();
140
       // Signal the new value is completely stored into the value
107
       // Signal the new value is completely stored into the value
141
       rx_tail_value_not_stable = false;
108
       rx_tail_value_not_stable = false;
142
       sw_barrier();
109
       sw_barrier();
143
-    #else
110
+    }
111
+    else
144
       rx_buffer.tail = value;
112
       rx_buffer.tail = value;
145
-    #endif
146
   }
113
   }
147
 
114
 
148
   // Get the RX tail index, taking into account the read could be
115
   // Get the RX tail index, taking into account the read could be
149
   //  interrupting in the middle of the update of that index value
116
   //  interrupting in the middle of the update of that index value
150
   //    -Called from the RX ISR -
117
   //    -Called from the RX ISR -
151
-  FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail() {
152
-    #if RX_BUFFER_SIZE > 256
118
+  template<typename Cfg>
119
+  FORCE_INLINE typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::atomic_read_rx_tail() {
120
+    if (Cfg::RX_SIZE > 256) {
153
       // If the true index is being modified, return the backup value
121
       // If the true index is being modified, return the backup value
154
       if (rx_tail_value_not_stable) return rx_tail_value_backup;
122
       if (rx_tail_value_not_stable) return rx_tail_value_backup;
155
-    #endif
123
+    }
156
     // The true index is stable, return it
124
     // The true index is stable, return it
157
     return rx_buffer.tail;
125
     return rx_buffer.tail;
158
   }
126
   }
159
 
127
 
160
   // (called with RX interrupts disabled)
128
   // (called with RX interrupts disabled)
161
-  FORCE_INLINE void store_rxd_char() {
129
+  template<typename Cfg>
130
+  FORCE_INLINE void MarlinSerial<Cfg>::store_rxd_char() {
162
 
131
 
163
-    #if ENABLED(EMERGENCY_PARSER)
164
-      static EmergencyParser::State emergency_state; // = EP_RESET
165
-    #endif
132
+    static EmergencyParser::State emergency_state; // = EP_RESET
166
 
133
 
167
     // Get the tail - Nothing can alter its value while this ISR is executing, but there's
134
     // Get the tail - Nothing can alter its value while this ISR is executing, but there's
168
     // a chance that this ISR interrupted the main process while it was updating the index.
135
     // a chance that this ISR interrupted the main process while it was updating the index.
173
     ring_buffer_pos_t h = rx_buffer.head;
140
     ring_buffer_pos_t h = rx_buffer.head;
174
 
141
 
175
     // Get the next element
142
     // Get the next element
176
-    ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
143
+    ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
177
 
144
 
178
-    // This must read the M_UCSRxA register before reading the received byte to detect error causes
179
-    #if ENABLED(SERIAL_STATS_DROPPED_RX)
180
-      if (TEST(M_UCSRxA, M_DORx) && !++rx_dropped_bytes) --rx_dropped_bytes;
181
-    #endif
182
-
183
-    #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
184
-      if (TEST(M_UCSRxA, M_DORx) && !++rx_buffer_overruns) --rx_buffer_overruns;
185
-    #endif
186
-
187
-    #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
188
-      if (TEST(M_UCSRxA, M_FEx) && !++rx_framing_errors) --rx_framing_errors;
189
-    #endif
145
+    // This must read the R_UCSRA register before reading the received byte to detect error causes
146
+    if (Cfg::DROPPED_RX && B_DOR && !++rx_dropped_bytes) --rx_dropped_bytes;
147
+    if (Cfg::RX_OVERRUNS && B_DOR && !++rx_buffer_overruns) --rx_buffer_overruns;
148
+    if (Cfg::RX_FRAMING_ERRORS && B_FE && !++rx_framing_errors) --rx_framing_errors;
190
 
149
 
191
     // Read the character from the USART
150
     // Read the character from the USART
192
-    uint8_t c = M_UDRx;
151
+    uint8_t c = R_UDR;
193
 
152
 
194
-    #if ENABLED(EMERGENCY_PARSER)
195
-      emergency_parser.update(emergency_state, c);
196
-    #endif
153
+    if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
197
 
154
 
198
     // If the character is to be stored at the index just before the tail
155
     // If the character is to be stored at the index just before the tail
199
     // (such that the head would advance to the current tail), the RX FIFO is
156
     // (such that the head would advance to the current tail), the RX FIFO is
202
       rx_buffer.buffer[h] = c;
159
       rx_buffer.buffer[h] = c;
203
       h = i;
160
       h = i;
204
     }
161
     }
205
-    #if ENABLED(SERIAL_STATS_DROPPED_RX)
206
-      else if (!++rx_dropped_bytes) --rx_dropped_bytes;
207
-    #endif
162
+    else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
163
+      --rx_dropped_bytes;
208
 
164
 
209
-    #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
165
+    if (Cfg::MAX_RX_QUEUED) {
210
       // Calculate count of bytes stored into the RX buffer
166
       // Calculate count of bytes stored into the RX buffer
211
-      const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
167
+      const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
212
 
168
 
213
       // Keep track of the maximum count of enqueued bytes
169
       // Keep track of the maximum count of enqueued bytes
214
       NOLESS(rx_max_enqueued, rx_count);
170
       NOLESS(rx_max_enqueued, rx_count);
215
-    #endif
171
+    }
216
 
172
 
217
-    #if ENABLED(SERIAL_XON_XOFF)
173
+    if (Cfg::XONOFF) {
218
       // If the last char that was sent was an XON
174
       // If the last char that was sent was an XON
219
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
175
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
220
 
176
 
221
         // Bytes stored into the RX buffer
177
         // Bytes stored into the RX buffer
222
-        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
178
+        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
223
 
179
 
224
         // If over 12.5% of RX buffer capacity, send XOFF before running out of
180
         // If over 12.5% of RX buffer capacity, send XOFF before running out of
225
         // RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
181
         // RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
226
         // and stop sending bytes. This translates to 13mS propagation time.
182
         // and stop sending bytes. This translates to 13mS propagation time.
227
-        if (rx_count >= (RX_BUFFER_SIZE) / 8) {
183
+        if (rx_count >= (Cfg::RX_SIZE) / 8) {
228
 
184
 
229
           // At this point, definitely no TX interrupt was executing, since the TX ISR can't be preempted.
185
           // At this point, definitely no TX interrupt was executing, since the TX ISR can't be preempted.
230
           // Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
186
           // Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
238
           // Wait until the TX register becomes empty and send it - Here there could be a problem
194
           // Wait until the TX register becomes empty and send it - Here there could be a problem
239
           // - While waiting for the TX register to empty, the RX register could receive a new
195
           // - While waiting for the TX register to empty, the RX register could receive a new
240
           //   character. This must also handle that situation!
196
           //   character. This must also handle that situation!
241
-          while (!TEST(M_UCSRxA, M_UDREx)) {
197
+          while (!B_UDRE) {
242
 
198
 
243
-            if (TEST(M_UCSRxA,M_RXCx)) {
199
+            if (B_RXC) {
244
               // A char arrived while waiting for the TX buffer to be empty - Receive and process it!
200
               // A char arrived while waiting for the TX buffer to be empty - Receive and process it!
245
 
201
 
246
-              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
202
+              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
247
 
203
 
248
               // Read the character from the USART
204
               // Read the character from the USART
249
-              c = M_UDRx;
205
+              c = R_UDR;
250
 
206
 
251
-              #if ENABLED(EMERGENCY_PARSER)
252
-                emergency_parser.update(emergency_state, c);
253
-              #endif
207
+              if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
254
 
208
 
255
               // If the character is to be stored at the index just before the tail
209
               // If the character is to be stored at the index just before the tail
256
               // (such that the head would advance to the current tail), the FIFO is
210
               // (such that the head would advance to the current tail), the FIFO is
259
                 rx_buffer.buffer[h] = c;
213
                 rx_buffer.buffer[h] = c;
260
                 h = i;
214
                 h = i;
261
               }
215
               }
262
-              #if ENABLED(SERIAL_STATS_DROPPED_RX)
263
-                else if (!++rx_dropped_bytes) --rx_dropped_bytes;
264
-              #endif
216
+              else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
217
+                --rx_dropped_bytes;
265
             }
218
             }
266
             sw_barrier();
219
             sw_barrier();
267
           }
220
           }
268
 
221
 
269
-          M_UDRx = XOFF_CHAR;
222
+          R_UDR = XOFF_CHAR;
270
 
223
 
271
           // Clear the TXC bit -- "can be cleared by writing a one to its bit
224
           // Clear the TXC bit -- "can be cleared by writing a one to its bit
272
           // location". This makes sure flush() won't return until the bytes
225
           // location". This makes sure flush() won't return until the bytes
273
           // actually got written
226
           // actually got written
274
-          SBI(M_UCSRxA, M_TXCx);
227
+          B_TXC = 1;
275
 
228
 
276
           // At this point there could be a race condition between the write() function
229
           // At this point there could be a race condition between the write() function
277
           // and this sending of the XOFF char. This interrupt could happen between the
230
           // and this sending of the XOFF char. This interrupt could happen between the
280
           // sure the write() function will succeed is to wait for the XOFF char to be
233
           // sure the write() function will succeed is to wait for the XOFF char to be
281
           // completely sent. Since an extra character could be received during the wait
234
           // completely sent. Since an extra character could be received during the wait
282
           // it must also be handled!
235
           // it must also be handled!
283
-          while (!TEST(M_UCSRxA, M_UDREx)) {
236
+          while (!B_UDRE) {
284
 
237
 
285
-            if (TEST(M_UCSRxA,M_RXCx)) {
238
+            if (B_RXC) {
286
               // A char arrived while waiting for the TX buffer to be empty - Receive and process it!
239
               // A char arrived while waiting for the TX buffer to be empty - Receive and process it!
287
 
240
 
288
-              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
241
+              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
289
 
242
 
290
               // Read the character from the USART
243
               // Read the character from the USART
291
-              c = M_UDRx;
244
+              c = R_UDR;
292
 
245
 
293
-              #if ENABLED(EMERGENCY_PARSER)
246
+              if (Cfg::EMERGENCYPARSER)
294
                 emergency_parser.update(emergency_state, c);
247
                 emergency_parser.update(emergency_state, c);
295
-              #endif
296
 
248
 
297
               // If the character is to be stored at the index just before the tail
249
               // If the character is to be stored at the index just before the tail
298
               // (such that the head would advance to the current tail), the FIFO is
250
               // (such that the head would advance to the current tail), the FIFO is
301
                 rx_buffer.buffer[h] = c;
253
                 rx_buffer.buffer[h] = c;
302
                 h = i;
254
                 h = i;
303
               }
255
               }
304
-              #if ENABLED(SERIAL_STATS_DROPPED_RX)
305
-                else if (!++rx_dropped_bytes) --rx_dropped_bytes;
306
-              #endif
256
+              else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
257
+                --rx_dropped_bytes;
307
             }
258
             }
308
             sw_barrier();
259
             sw_barrier();
309
           }
260
           }
312
           // have any issues writing to the UART TX register if it needs to!
263
           // have any issues writing to the UART TX register if it needs to!
313
         }
264
         }
314
       }
265
       }
315
-    #endif // SERIAL_XON_XOFF
266
+    }
316
 
267
 
317
     // Store the new head value - The main loop will retry until the value is stable
268
     // Store the new head value - The main loop will retry until the value is stable
318
     rx_buffer.head = h;
269
     rx_buffer.head = h;
319
   }
270
   }
320
 
271
 
321
-  #if TX_BUFFER_SIZE > 0
322
-
323
-    // (called with TX irqs disabled)
324
-    FORCE_INLINE void _tx_udr_empty_irq(void) {
325
-
272
+  // (called with TX irqs disabled)
273
+  template<typename Cfg>
274
+  FORCE_INLINE void MarlinSerial<Cfg>::_tx_udr_empty_irq(void) {
275
+    if (Cfg::TX_SIZE > 0) {
326
       // Read positions
276
       // Read positions
327
       uint8_t t = tx_buffer.tail;
277
       uint8_t t = tx_buffer.tail;
328
       const uint8_t h = tx_buffer.head;
278
       const uint8_t h = tx_buffer.head;
329
 
279
 
330
-      #if ENABLED(SERIAL_XON_XOFF)
280
+      if (Cfg::XONOFF) {
331
         // If an XON char is pending to be sent, do it now
281
         // If an XON char is pending to be sent, do it now
332
         if (xon_xoff_state == XON_CHAR) {
282
         if (xon_xoff_state == XON_CHAR) {
333
 
283
 
334
           // Send the character
284
           // Send the character
335
-          M_UDRx = XON_CHAR;
285
+          R_UDR = XON_CHAR;
336
 
286
 
337
           // clear the TXC bit -- "can be cleared by writing a one to its bit
287
           // clear the TXC bit -- "can be cleared by writing a one to its bit
338
           // location". This makes sure flush() won't return until the bytes
288
           // location". This makes sure flush() won't return until the bytes
339
           // actually got written
289
           // actually got written
340
-          SBI(M_UCSRxA, M_TXCx);
290
+          B_TXC = 1;
341
 
291
 
342
           // Remember we sent it.
292
           // Remember we sent it.
343
           xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
293
           xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
344
 
294
 
345
           // If nothing else to transmit, just disable TX interrupts.
295
           // If nothing else to transmit, just disable TX interrupts.
346
-          if (h == t) CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
296
+          if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
347
 
297
 
348
           return;
298
           return;
349
         }
299
         }
350
-      #endif
300
+      }
351
 
301
 
352
       // If nothing to transmit, just disable TX interrupts. This could
302
       // If nothing to transmit, just disable TX interrupts. This could
353
       // happen as the result of the non atomicity of the disabling of RX
303
       // happen as the result of the non atomicity of the disabling of RX
354
       // interrupts that could end reenabling TX interrupts as a side effect.
304
       // interrupts that could end reenabling TX interrupts as a side effect.
355
       if (h == t) {
305
       if (h == t) {
356
-        CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
306
+        B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
357
         return;
307
         return;
358
       }
308
       }
359
 
309
 
360
       // There is something to TX, Send the next byte
310
       // There is something to TX, Send the next byte
361
       const uint8_t c = tx_buffer.buffer[t];
311
       const uint8_t c = tx_buffer.buffer[t];
362
-      t = (t + 1) & (TX_BUFFER_SIZE - 1);
363
-      M_UDRx = c;
312
+      t = (t + 1) & (Cfg::TX_SIZE - 1);
313
+      R_UDR = c;
364
       tx_buffer.tail = t;
314
       tx_buffer.tail = t;
365
 
315
 
366
       // Clear the TXC bit (by writing a one to its bit location).
316
       // Clear the TXC bit (by writing a one to its bit location).
367
       // Ensures flush() won't return until the bytes are actually written/
317
       // Ensures flush() won't return until the bytes are actually written/
368
-      SBI(M_UCSRxA, M_TXCx);
318
+      B_TXC = 1;
369
 
319
 
370
       // Disable interrupts if there is nothing to transmit following this byte
320
       // Disable interrupts if there is nothing to transmit following this byte
371
-      if (h == t) CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
321
+      if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
372
     }
322
     }
373
-
374
-    #ifdef M_USARTx_UDRE_vect
375
-      ISR(M_USARTx_UDRE_vect) { _tx_udr_empty_irq(); }
376
-    #endif
377
-
378
-  #endif // TX_BUFFER_SIZE
379
-
380
-  #ifdef M_USARTx_RX_vect
381
-    ISR(M_USARTx_RX_vect) { store_rxd_char(); }
382
-  #endif
323
+  }
383
 
324
 
384
   // Public Methods
325
   // Public Methods
385
-
386
-  void MarlinSerial::begin(const long baud) {
326
+  template<typename Cfg>
327
+  void MarlinSerial<Cfg>::begin(const long baud) {
387
     uint16_t baud_setting;
328
     uint16_t baud_setting;
388
     bool useU2X = true;
329
     bool useU2X = true;
389
 
330
 
394
       if (baud == 57600) useU2X = false;
335
       if (baud == 57600) useU2X = false;
395
     #endif
336
     #endif
396
 
337
 
338
+    R_UCSRA = 0;
397
     if (useU2X) {
339
     if (useU2X) {
398
-      M_UCSRxA = _BV(M_U2Xx);
340
+      B_U2X = 1;
399
       baud_setting = (F_CPU / 4 / baud - 1) / 2;
341
       baud_setting = (F_CPU / 4 / baud - 1) / 2;
400
     }
342
     }
401
-    else {
402
-      M_UCSRxA = 0;
343
+    else
403
       baud_setting = (F_CPU / 8 / baud - 1) / 2;
344
       baud_setting = (F_CPU / 8 / baud - 1) / 2;
404
-    }
405
 
345
 
406
     // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
346
     // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
407
-    M_UBRRxH = baud_setting >> 8;
408
-    M_UBRRxL = baud_setting;
409
-
410
-    SBI(M_UCSRxB, M_RXENx);
411
-    SBI(M_UCSRxB, M_TXENx);
412
-    SBI(M_UCSRxB, M_RXCIEx);
413
-    #if TX_BUFFER_SIZE > 0
414
-      CBI(M_UCSRxB, M_UDRIEx);
415
-    #endif
347
+    R_UBRRH = baud_setting >> 8;
348
+    R_UBRRL = baud_setting;
349
+
350
+    B_RXEN = 1;
351
+    B_TXEN = 1;
352
+    B_RXCIE = 1;
353
+    if (Cfg::TX_SIZE > 0) B_UDRIE = 0;
416
     _written = false;
354
     _written = false;
417
   }
355
   }
418
 
356
 
419
-  void MarlinSerial::end() {
420
-    CBI(M_UCSRxB, M_RXENx);
421
-    CBI(M_UCSRxB, M_TXENx);
422
-    CBI(M_UCSRxB, M_RXCIEx);
423
-    CBI(M_UCSRxB, M_UDRIEx);
357
+  template<typename Cfg>
358
+  void MarlinSerial<Cfg>::end() {
359
+    B_RXEN = 0;
360
+    B_TXEN = 0;
361
+    B_RXCIE = 0;
362
+    B_UDRIE = 0;
424
   }
363
   }
425
 
364
 
426
-  int MarlinSerial::peek(void) {
365
+  template<typename Cfg>
366
+  int MarlinSerial<Cfg>::peek(void) {
427
     const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail;
367
     const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail;
428
     return h == t ? -1 : rx_buffer.buffer[t];
368
     return h == t ? -1 : rx_buffer.buffer[t];
429
   }
369
   }
430
 
370
 
431
-  int MarlinSerial::read(void) {
371
+  template<typename Cfg>
372
+  int MarlinSerial<Cfg>::read(void) {
432
     const ring_buffer_pos_t h = atomic_read_rx_head();
373
     const ring_buffer_pos_t h = atomic_read_rx_head();
433
 
374
 
434
     // Read the tail. Main thread owns it, so it is safe to directly read it
375
     // Read the tail. Main thread owns it, so it is safe to directly read it
439
 
380
 
440
     // Get the next char
381
     // Get the next char
441
     const int v = rx_buffer.buffer[t];
382
     const int v = rx_buffer.buffer[t];
442
-    t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
383
+    t = (ring_buffer_pos_t)(t + 1) & (Cfg::RX_SIZE - 1);
443
 
384
 
444
     // Advance tail - Making sure the RX ISR will always get an stable value, even
385
     // Advance tail - Making sure the RX ISR will always get an stable value, even
445
     // if it interrupts the writing of the value of that variable in the middle.
386
     // if it interrupts the writing of the value of that variable in the middle.
446
     atomic_set_rx_tail(t);
387
     atomic_set_rx_tail(t);
447
 
388
 
448
-    #if ENABLED(SERIAL_XON_XOFF)
389
+    if (Cfg::XONOFF) {
449
       // If the XOFF char was sent, or about to be sent...
390
       // If the XOFF char was sent, or about to be sent...
450
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
391
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
451
         // Get count of bytes in the RX buffer
392
         // Get count of bytes in the RX buffer
452
-        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
453
-        if (rx_count < (RX_BUFFER_SIZE) / 10) {
454
-          #if TX_BUFFER_SIZE > 0
393
+        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
394
+        if (rx_count < (Cfg::RX_SIZE) / 10) {
395
+          if (Cfg::TX_SIZE > 0) {
455
             // Signal we want an XON character to be sent.
396
             // Signal we want an XON character to be sent.
456
             xon_xoff_state = XON_CHAR;
397
             xon_xoff_state = XON_CHAR;
457
             // Enable TX ISR. Non atomic, but it will eventually enable them
398
             // Enable TX ISR. Non atomic, but it will eventually enable them
458
-            SBI(M_UCSRxB, M_UDRIEx);
459
-          #else
399
+            B_UDRIE = 1;
400
+          }
401
+          else {
460
             // If not using TX interrupts, we must send the XON char now
402
             // If not using TX interrupts, we must send the XON char now
461
             xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
403
             xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
462
-            while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
463
-            M_UDRx = XON_CHAR;
464
-          #endif
404
+            while (!B_UDRE) sw_barrier();
405
+            R_UDR = XON_CHAR;
406
+          }
465
         }
407
         }
466
       }
408
       }
467
-    #endif
409
+    }
468
 
410
 
469
     return v;
411
     return v;
470
   }
412
   }
471
 
413
 
472
-  ring_buffer_pos_t MarlinSerial::available(void) {
414
+  template<typename Cfg>
415
+  typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::available(void) {
473
     const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail;
416
     const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail;
474
-    return (ring_buffer_pos_t)(RX_BUFFER_SIZE + h - t) & (RX_BUFFER_SIZE - 1);
417
+    return (ring_buffer_pos_t)(Cfg::RX_SIZE + h - t) & (Cfg::RX_SIZE - 1);
475
   }
418
   }
476
 
419
 
477
-  void MarlinSerial::flush(void) {
420
+  template<typename Cfg>
421
+  void MarlinSerial<Cfg>::flush(void) {
478
 
422
 
479
     // Set the tail to the head:
423
     // Set the tail to the head:
480
     //  - Read the RX head index in a safe way. (See atomic_read_rx_head.)
424
     //  - Read the RX head index in a safe way. (See atomic_read_rx_head.)
482
     //    if it interrupts the writing of the value of that variable in the middle.
426
     //    if it interrupts the writing of the value of that variable in the middle.
483
     atomic_set_rx_tail(atomic_read_rx_head());
427
     atomic_set_rx_tail(atomic_read_rx_head());
484
 
428
 
485
-    #if ENABLED(SERIAL_XON_XOFF)
429
+    if (Cfg::XONOFF) {
486
       // If the XOFF char was sent, or about to be sent...
430
       // If the XOFF char was sent, or about to be sent...
487
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
431
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
488
-        #if TX_BUFFER_SIZE > 0
432
+        if (Cfg::TX_SIZE > 0) {
489
           // Signal we want an XON character to be sent.
433
           // Signal we want an XON character to be sent.
490
           xon_xoff_state = XON_CHAR;
434
           xon_xoff_state = XON_CHAR;
491
           // Enable TX ISR. Non atomic, but it will eventually enable it.
435
           // Enable TX ISR. Non atomic, but it will eventually enable it.
492
-          SBI(M_UCSRxB, M_UDRIEx);
493
-        #else
436
+          B_UDRIE = 1;
437
+        }
438
+        else {
494
           // If not using TX interrupts, we must send the XON char now
439
           // If not using TX interrupts, we must send the XON char now
495
           xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
440
           xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
496
-          while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
497
-          M_UDRx = XON_CHAR;
498
-        #endif
441
+          while (!B_UDRE) sw_barrier();
442
+          R_UDR = XON_CHAR;
443
+        }
499
       }
444
       }
500
-    #endif
445
+    }
501
   }
446
   }
502
 
447
 
503
-  #if TX_BUFFER_SIZE > 0
504
-    void MarlinSerial::write(const uint8_t c) {
448
+  template<typename Cfg>
449
+  void MarlinSerial<Cfg>::write(const uint8_t c) {
450
+    if (Cfg::TX_SIZE == 0) {
451
+
452
+      _written = true;
453
+      while (!B_UDRE) sw_barrier();
454
+      R_UDR = c;
455
+
456
+    }
457
+    else {
458
+
505
       _written = true;
459
       _written = true;
506
 
460
 
507
       // If the TX interrupts are disabled and the data register
461
       // If the TX interrupts are disabled and the data register
511
       // interrupt overhead becomes a slowdown.
465
       // interrupt overhead becomes a slowdown.
512
       // Yes, there is a race condition between the sending of the
466
       // Yes, there is a race condition between the sending of the
513
       // XOFF char at the RX ISR, but it is properly handled there
467
       // XOFF char at the RX ISR, but it is properly handled there
514
-      if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) {
515
-        M_UDRx = c;
468
+      if (!B_UDRIE && B_UDRE) {
469
+        R_UDR = c;
516
 
470
 
517
         // clear the TXC bit -- "can be cleared by writing a one to its bit
471
         // clear the TXC bit -- "can be cleared by writing a one to its bit
518
         // location". This makes sure flush() won't return until the bytes
472
         // location". This makes sure flush() won't return until the bytes
519
         // actually got written
473
         // actually got written
520
-        SBI(M_UCSRxA, M_TXCx);
474
+        B_TXC = 1;
521
         return;
475
         return;
522
       }
476
       }
523
 
477
 
524
-      const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
478
+      const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
525
 
479
 
526
       // If global interrupts are disabled (as the result of being called from an ISR)...
480
       // If global interrupts are disabled (as the result of being called from an ISR)...
527
       if (!ISRS_ENABLED()) {
481
       if (!ISRS_ENABLED()) {
530
         while (i == tx_buffer.tail) {
484
         while (i == tx_buffer.tail) {
531
 
485
 
532
           // If we can transmit another byte, do it.
486
           // If we can transmit another byte, do it.
533
-          if (TEST(M_UCSRxA, M_UDREx)) _tx_udr_empty_irq();
487
+          if (B_UDRE) _tx_udr_empty_irq();
534
 
488
 
535
           // Make sure compiler rereads tx_buffer.tail
489
           // Make sure compiler rereads tx_buffer.tail
536
           sw_barrier();
490
           sw_barrier();
538
       }
492
       }
539
       else {
493
       else {
540
         // Interrupts are enabled, just wait until there is space
494
         // Interrupts are enabled, just wait until there is space
541
-        while (i == tx_buffer.tail) { sw_barrier(); }
495
+        while (i == tx_buffer.tail) sw_barrier();
542
       }
496
       }
543
 
497
 
544
       // Store new char. head is always safe to move
498
       // Store new char. head is always safe to move
546
       tx_buffer.head = i;
500
       tx_buffer.head = i;
547
 
501
 
548
       // Enable TX ISR - Non atomic, but it will eventually enable TX ISR
502
       // Enable TX ISR - Non atomic, but it will eventually enable TX ISR
549
-      SBI(M_UCSRxB, M_UDRIEx);
503
+      B_UDRIE = 1;
550
     }
504
     }
505
+  }
506
+
507
+  template<typename Cfg>
508
+  void MarlinSerial<Cfg>::flushTX(void) {
509
+
510
+    if (Cfg::TX_SIZE == 0) {
511
+      // No bytes written, no need to flush. This special case is needed since there's
512
+      // no way to force the TXC (transmit complete) bit to 1 during initialization.
513
+      if (!_written) return;
514
+
515
+      // Wait until everything was transmitted
516
+      while (!B_TXC) sw_barrier();
517
+
518
+      // At this point nothing is queued anymore (DRIE is disabled) and
519
+      // the hardware finished transmission (TXC is set).
520
+
521
+    }
522
+    else {
551
 
523
 
552
-    void MarlinSerial::flushTX(void) {
553
       // No bytes written, no need to flush. This special case is needed since there's
524
       // No bytes written, no need to flush. This special case is needed since there's
554
       // no way to force the TXC (transmit complete) bit to 1 during initialization.
525
       // no way to force the TXC (transmit complete) bit to 1 during initialization.
555
       if (!_written) return;
526
       if (!_written) return;
558
       if (!ISRS_ENABLED()) {
529
       if (!ISRS_ENABLED()) {
559
 
530
 
560
         // Wait until everything was transmitted - We must do polling, as interrupts are disabled
531
         // Wait until everything was transmitted - We must do polling, as interrupts are disabled
561
-        while (tx_buffer.head != tx_buffer.tail || !TEST(M_UCSRxA, M_TXCx)) {
532
+        while (tx_buffer.head != tx_buffer.tail || !B_TXC) {
562
 
533
 
563
           // If there is more space, send an extra character
534
           // If there is more space, send an extra character
564
-          if (TEST(M_UCSRxA, M_UDREx))
565
-            _tx_udr_empty_irq();
535
+          if (B_UDRE) _tx_udr_empty_irq();
566
 
536
 
567
           sw_barrier();
537
           sw_barrier();
568
         }
538
         }
570
       }
540
       }
571
       else {
541
       else {
572
         // Wait until everything was transmitted
542
         // Wait until everything was transmitted
573
-        while (tx_buffer.head != tx_buffer.tail || !TEST(M_UCSRxA, M_TXCx)) sw_barrier();
543
+        while (tx_buffer.head != tx_buffer.tail || !B_TXC) sw_barrier();
574
       }
544
       }
575
 
545
 
576
       // At this point nothing is queued anymore (DRIE is disabled) and
546
       // At this point nothing is queued anymore (DRIE is disabled) and
577
       // the hardware finished transmission (TXC is set).
547
       // the hardware finished transmission (TXC is set).
578
     }
548
     }
579
-
580
-  #else // TX_BUFFER_SIZE == 0
581
-
582
-    void MarlinSerial::write(const uint8_t c) {
583
-      _written = true;
584
-      while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
585
-      M_UDRx = c;
586
-    }
587
-
588
-    void MarlinSerial::flushTX(void) {
589
-      // No bytes written, no need to flush. This special case is needed since there's
590
-      // no way to force the TXC (transmit complete) bit to 1 during initialization.
591
-      if (!_written) return;
592
-
593
-      // Wait until everything was transmitted
594
-      while (!TEST(M_UCSRxA, M_TXCx)) sw_barrier();
595
-
596
-      // At this point nothing is queued anymore (DRIE is disabled) and
597
-      // the hardware finished transmission (TXC is set).
598
-    }
599
-  #endif // TX_BUFFER_SIZE == 0
549
+  }
600
 
550
 
601
   /**
551
   /**
602
    * Imports from print.h
552
    * Imports from print.h
603
    */
553
    */
604
 
554
 
605
-  void MarlinSerial::print(char c, int base) {
555
+  template<typename Cfg>
556
+  void MarlinSerial<Cfg>::print(char c, int base) {
606
     print((long)c, base);
557
     print((long)c, base);
607
   }
558
   }
608
 
559
 
609
-  void MarlinSerial::print(unsigned char b, int base) {
560
+  template<typename Cfg>
561
+  void MarlinSerial<Cfg>::print(unsigned char b, int base) {
610
     print((unsigned long)b, base);
562
     print((unsigned long)b, base);
611
   }
563
   }
612
 
564
 
613
-  void MarlinSerial::print(int n, int base) {
565
+  template<typename Cfg>
566
+  void MarlinSerial<Cfg>::print(int n, int base) {
614
     print((long)n, base);
567
     print((long)n, base);
615
   }
568
   }
616
 
569
 
617
-  void MarlinSerial::print(unsigned int n, int base) {
570
+  template<typename Cfg>
571
+  void MarlinSerial<Cfg>::print(unsigned int n, int base) {
618
     print((unsigned long)n, base);
572
     print((unsigned long)n, base);
619
   }
573
   }
620
 
574
 
621
-  void MarlinSerial::print(long n, int base) {
575
+  template<typename Cfg>
576
+  void MarlinSerial<Cfg>::print(long n, int base) {
622
     if (base == 0) write(n);
577
     if (base == 0) write(n);
623
     else if (base == 10) {
578
     else if (base == 10) {
624
       if (n < 0) { print('-'); n = -n; }
579
       if (n < 0) { print('-'); n = -n; }
628
       printNumber(n, base);
583
       printNumber(n, base);
629
   }
584
   }
630
 
585
 
631
-  void MarlinSerial::print(unsigned long n, int base) {
586
+  template<typename Cfg>
587
+  void MarlinSerial<Cfg>::print(unsigned long n, int base) {
632
     if (base == 0) write(n);
588
     if (base == 0) write(n);
633
     else printNumber(n, base);
589
     else printNumber(n, base);
634
   }
590
   }
635
 
591
 
636
-  void MarlinSerial::print(double n, int digits) {
592
+  template<typename Cfg>
593
+  void MarlinSerial<Cfg>::print(double n, int digits) {
637
     printFloat(n, digits);
594
     printFloat(n, digits);
638
   }
595
   }
639
 
596
 
640
-  void MarlinSerial::println(void) {
597
+  template<typename Cfg>
598
+  void MarlinSerial<Cfg>::println(void) {
641
     print('\r');
599
     print('\r');
642
     print('\n');
600
     print('\n');
643
   }
601
   }
644
 
602
 
645
-  void MarlinSerial::println(const String& s) {
603
+  template<typename Cfg>
604
+  void MarlinSerial<Cfg>::println(const String& s) {
646
     print(s);
605
     print(s);
647
     println();
606
     println();
648
   }
607
   }
649
 
608
 
650
-  void MarlinSerial::println(const char c[]) {
609
+  template<typename Cfg>
610
+  void MarlinSerial<Cfg>::println(const char c[]) {
651
     print(c);
611
     print(c);
652
     println();
612
     println();
653
   }
613
   }
654
 
614
 
655
-  void MarlinSerial::println(char c, int base) {
615
+  template<typename Cfg>
616
+  void MarlinSerial<Cfg>::println(char c, int base) {
656
     print(c, base);
617
     print(c, base);
657
     println();
618
     println();
658
   }
619
   }
659
 
620
 
660
-  void MarlinSerial::println(unsigned char b, int base) {
621
+  template<typename Cfg>
622
+  void MarlinSerial<Cfg>::println(unsigned char b, int base) {
661
     print(b, base);
623
     print(b, base);
662
     println();
624
     println();
663
   }
625
   }
664
 
626
 
665
-  void MarlinSerial::println(int n, int base) {
627
+  template<typename Cfg>
628
+  void MarlinSerial<Cfg>::println(int n, int base) {
666
     print(n, base);
629
     print(n, base);
667
     println();
630
     println();
668
   }
631
   }
669
 
632
 
670
-  void MarlinSerial::println(unsigned int n, int base) {
633
+  template<typename Cfg>
634
+  void MarlinSerial<Cfg>::println(unsigned int n, int base) {
671
     print(n, base);
635
     print(n, base);
672
     println();
636
     println();
673
   }
637
   }
674
 
638
 
675
-  void MarlinSerial::println(long n, int base) {
639
+  template<typename Cfg>
640
+  void MarlinSerial<Cfg>::println(long n, int base) {
676
     print(n, base);
641
     print(n, base);
677
     println();
642
     println();
678
   }
643
   }
679
 
644
 
680
-  void MarlinSerial::println(unsigned long n, int base) {
645
+  template<typename Cfg>
646
+  void MarlinSerial<Cfg>::println(unsigned long n, int base) {
681
     print(n, base);
647
     print(n, base);
682
     println();
648
     println();
683
   }
649
   }
684
 
650
 
685
-  void MarlinSerial::println(double n, int digits) {
651
+  template<typename Cfg>
652
+  void MarlinSerial<Cfg>::println(double n, int digits) {
686
     print(n, digits);
653
     print(n, digits);
687
     println();
654
     println();
688
   }
655
   }
689
 
656
 
690
   // Private Methods
657
   // Private Methods
691
 
658
 
692
-  void MarlinSerial::printNumber(unsigned long n, uint8_t base) {
659
+  template<typename Cfg>
660
+  void MarlinSerial<Cfg>::printNumber(unsigned long n, uint8_t base) {
693
     if (n) {
661
     if (n) {
694
       unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
662
       unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
695
       int8_t i = 0;
663
       int8_t i = 0;
704
       print('0');
672
       print('0');
705
   }
673
   }
706
 
674
 
707
-  void MarlinSerial::printFloat(double number, uint8_t digits) {
675
+  template<typename Cfg>
676
+  void MarlinSerial<Cfg>::printFloat(double number, uint8_t digits) {
708
     // Handle negative numbers
677
     // Handle negative numbers
709
     if (number < 0.0) {
678
     if (number < 0.0) {
710
       print('-');
679
       print('-');
713
 
682
 
714
     // Round correctly so that print(1.999, 2) prints as "2.00"
683
     // Round correctly so that print(1.999, 2) prints as "2.00"
715
     double rounding = 0.5;
684
     double rounding = 0.5;
716
-    for (uint8_t i = 0; i < digits; ++i)
717
-      rounding *= 0.1;
718
-
685
+    for (uint8_t i = 0; i < digits; ++i) rounding *= 0.1;
719
     number += rounding;
686
     number += rounding;
720
 
687
 
721
     // Extract the integer part of the number and print it
688
     // Extract the integer part of the number and print it
736
     }
703
     }
737
   }
704
   }
738
 
705
 
706
+  // Hookup ISR handlers
707
+  ISR(SERIAL_REGNAME(USART,SERIAL_PORT,_RX_vect)) {
708
+    MarlinSerial<MarlinSerialCfg>::store_rxd_char();
709
+  }
710
+
711
+  ISR(SERIAL_REGNAME(USART,SERIAL_PORT,_UDRE_vect)) {
712
+    MarlinSerial<MarlinSerialCfg>::_tx_udr_empty_irq();
713
+  }
714
+
739
   // Preinstantiate
715
   // Preinstantiate
740
-  MarlinSerial customizedSerial;
716
+  template class MarlinSerial<MarlinSerialCfg>;
717
+
718
+  // Instantiate
719
+  MarlinSerial<MarlinSerialCfg> customizedSerial;
741
 
720
 
742
 #endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H)
721
 #endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H)
743
 
722
 

+ 176
- 73
Marlin/src/HAL/HAL_AVR/MarlinSerial.h ファイルの表示

27
  * Modified 28 September 2010 by Mark Sproul
27
  * Modified 28 September 2010 by Mark Sproul
28
  * Modified 14 February 2016 by Andreas Hardtung (added tx buffer)
28
  * Modified 14 February 2016 by Andreas Hardtung (added tx buffer)
29
  * Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF)
29
  * Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF)
30
+ * Templatized 01 October 2018 by Eduardo José Tagle to allow multiple instances
30
  */
31
  */
31
 
32
 
32
 #ifndef _MARLINSERIAL_H_
33
 #ifndef _MARLINSERIAL_H_
33
 #define _MARLINSERIAL_H_
34
 #define _MARLINSERIAL_H_
34
 
35
 
35
-#include "../../inc/MarlinConfigPre.h"
36
+#include "../shared/MarlinSerial.h"
36
 
37
 
37
 #include <WString.h>
38
 #include <WString.h>
38
 
39
 
40
   #define SERIAL_PORT 0
41
   #define SERIAL_PORT 0
41
 #endif
42
 #endif
42
 
43
 
43
-// The presence of the UBRRH register is used to detect a UART.
44
-#define UART_PRESENT(port) ((port == 0 && (defined(UBRRH) || defined(UBRR0H))) || \
45
-                            (port == 1 && defined(UBRR1H)) || (port == 2 && defined(UBRR2H)) || \
46
-                            (port == 3 && defined(UBRR3H)))
47
-
48
-// These are macros to build serial port register names for the selected SERIAL_PORT (C preprocessor
49
-// requires two levels of indirection to expand macro values properly)
50
-#define SERIAL_REGNAME(registerbase,number,suffix) SERIAL_REGNAME_INTERNAL(registerbase,number,suffix)
51
-#if SERIAL_PORT == 0 && (!defined(UBRR0H) || !defined(UDR0)) // use un-numbered registers if necessary
52
-  #define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##suffix
53
-#else
54
-  #define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix
55
-#endif
44
+#ifndef USBCON
56
 
45
 
57
-// Registers used by MarlinSerial class (expanded depending on selected serial port)
58
-#define M_UCSRxA           SERIAL_REGNAME(UCSR,SERIAL_PORT,A) // defines M_UCSRxA to be UCSRnA where n is the serial port number
59
-#define M_UCSRxB           SERIAL_REGNAME(UCSR,SERIAL_PORT,B)
60
-#define M_RXENx            SERIAL_REGNAME(RXEN,SERIAL_PORT,)
61
-#define M_TXENx            SERIAL_REGNAME(TXEN,SERIAL_PORT,)
62
-#define M_TXCx             SERIAL_REGNAME(TXC,SERIAL_PORT,)
63
-#define M_RXCIEx           SERIAL_REGNAME(RXCIE,SERIAL_PORT,)
64
-#define M_UDREx            SERIAL_REGNAME(UDRE,SERIAL_PORT,)
65
-#define M_FEx              SERIAL_REGNAME(FE,SERIAL_PORT,)
66
-#define M_DORx             SERIAL_REGNAME(DOR,SERIAL_PORT,)
67
-#define M_UPEx             SERIAL_REGNAME(UPE,SERIAL_PORT,)
68
-#define M_UDRIEx           SERIAL_REGNAME(UDRIE,SERIAL_PORT,)
69
-#define M_UDRx             SERIAL_REGNAME(UDR,SERIAL_PORT,)
70
-#define M_UBRRxH           SERIAL_REGNAME(UBRR,SERIAL_PORT,H)
71
-#define M_UBRRxL           SERIAL_REGNAME(UBRR,SERIAL_PORT,L)
72
-#define M_RXCx             SERIAL_REGNAME(RXC,SERIAL_PORT,)
73
-#define M_USARTx_RX_vect   SERIAL_REGNAME(USART,SERIAL_PORT,_RX_vect)
74
-#define M_U2Xx             SERIAL_REGNAME(U2X,SERIAL_PORT,)
75
-#define M_USARTx_UDRE_vect SERIAL_REGNAME(USART,SERIAL_PORT,_UDRE_vect)
76
-
77
-#define DEC 10
78
-#define HEX 16
79
-#define OCT 8
80
-#define BIN 2
81
-#define BYTE 0
46
+  // The presence of the UBRRH register is used to detect a UART.
47
+  #define UART_PRESENT(port) ((port == 0 && (defined(UBRRH) || defined(UBRR0H))) || \
48
+                              (port == 1 && defined(UBRR1H)) || (port == 2 && defined(UBRR2H)) || \
49
+                              (port == 3 && defined(UBRR3H)))
82
 
50
 
83
-#ifndef USBCON
84
-  // We're using a ring buffer (I think), in which rx_buffer_head is the index of the
85
-  // location to which to write the next incoming character and rx_buffer_tail is the
86
-  // index of the location from which to read.
87
-  #if RX_BUFFER_SIZE > 256
88
-    typedef uint16_t ring_buffer_pos_t;
51
+  // These are macros to build serial port register names for the selected SERIAL_PORT (C preprocessor
52
+  // requires two levels of indirection to expand macro values properly)
53
+  #define SERIAL_REGNAME(registerbase,number,suffix) SERIAL_REGNAME_INTERNAL(registerbase,number,suffix)
54
+  #if SERIAL_PORT == 0 && (!defined(UBRR0H) || !defined(UDR0)) // use un-numbered registers if necessary
55
+    #define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##suffix
89
   #else
56
   #else
90
-    typedef uint8_t ring_buffer_pos_t;
57
+    #define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix
91
   #endif
58
   #endif
92
 
59
 
93
-  #if ENABLED(SERIAL_STATS_DROPPED_RX)
94
-    extern uint8_t rx_dropped_bytes;
95
-  #endif
60
+  // Registers used by MarlinSerial class (expanded depending on selected serial port)
96
 
61
 
97
-  #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
98
-    extern uint8_t rx_buffer_overruns;
99
-  #endif
62
+  // Templated 8bit register (generic)
63
+  #define UART_REGISTER_DECL_BASE(registerbase, suffix) \
64
+    template<int portNr> struct R_##registerbase##x##suffix {}
100
 
65
 
101
-  #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
102
-    extern uint8_t rx_framing_errors;
103
-  #endif
66
+  // Templated 8bit register (specialization for each port)
67
+  #define UART_REGISTER_DECL(port, registerbase, suffix) \
68
+    template<> struct R_##registerbase##x##suffix<port> { \
69
+      constexpr R_##registerbase##x##suffix(int) {} \
70
+      FORCE_INLINE void operator=(uint8_t newVal) const { SERIAL_REGNAME(registerbase,port,suffix) = newVal; } \
71
+      FORCE_INLINE operator uint8_t() const { return SERIAL_REGNAME(registerbase,port,suffix); } \
72
+    }
73
+
74
+  // Templated 1bit register (generic)
75
+  #define UART_BIT_DECL_BASE(registerbase, suffix, bit) \
76
+    template<int portNr>struct B_##bit##x {}
77
+
78
+  // Templated 1bit register (specialization for each port)
79
+  #define UART_BIT_DECL(port, registerbase, suffix, bit) \
80
+    template<> struct B_##bit##x<port> { \
81
+      constexpr B_##bit##x(int) {} \
82
+      FORCE_INLINE void operator=(int newVal) const { \
83
+        if (newVal) \
84
+          SBI(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); \
85
+        else \
86
+          CBI(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); \
87
+      } \
88
+      FORCE_INLINE operator bool() const { return TEST(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); } \
89
+    }
90
+
91
+  #define UART_DECL_BASE() \
92
+    UART_REGISTER_DECL_BASE(UCSR,A);\
93
+    UART_REGISTER_DECL_BASE(UDR,);\
94
+    UART_REGISTER_DECL_BASE(UBRR,H);\
95
+    UART_REGISTER_DECL_BASE(UBRR,L);\
96
+    UART_BIT_DECL_BASE(UCSR,B,RXEN);\
97
+    UART_BIT_DECL_BASE(UCSR,B,TXEN);\
98
+    UART_BIT_DECL_BASE(UCSR,A,TXC);\
99
+    UART_BIT_DECL_BASE(UCSR,B,RXCIE);\
100
+    UART_BIT_DECL_BASE(UCSR,A,UDRE);\
101
+    UART_BIT_DECL_BASE(UCSR,A,FE);\
102
+    UART_BIT_DECL_BASE(UCSR,A,DOR);\
103
+    UART_BIT_DECL_BASE(UCSR,B,UDRIE);\
104
+    UART_BIT_DECL_BASE(UCSR,A,RXC);\
105
+    UART_BIT_DECL_BASE(UCSR,A,U2X)
104
 
106
 
105
-  #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
106
-    extern ring_buffer_pos_t rx_max_enqueued;
107
+  #define UART_DECL(port) \
108
+    UART_REGISTER_DECL(port,UCSR,A);\
109
+    UART_REGISTER_DECL(port,UDR,);\
110
+    UART_REGISTER_DECL(port,UBRR,H);\
111
+    UART_REGISTER_DECL(port,UBRR,L);\
112
+    UART_BIT_DECL(port,UCSR,B,RXEN);\
113
+    UART_BIT_DECL(port,UCSR,B,TXEN);\
114
+    UART_BIT_DECL(port,UCSR,A,TXC);\
115
+    UART_BIT_DECL(port,UCSR,B,RXCIE);\
116
+    UART_BIT_DECL(port,UCSR,A,UDRE);\
117
+    UART_BIT_DECL(port,UCSR,A,FE);\
118
+    UART_BIT_DECL(port,UCSR,A,DOR);\
119
+    UART_BIT_DECL(port,UCSR,B,UDRIE);\
120
+    UART_BIT_DECL(port,UCSR,A,RXC);\
121
+    UART_BIT_DECL(port,UCSR,A,U2X)
122
+
123
+  // Declare empty templates
124
+  UART_DECL_BASE();
125
+
126
+  // And all the specializations for each possible serial port
127
+  #if UART_PRESENT(0)
128
+    UART_DECL(0);
129
+  #endif
130
+  #if UART_PRESENT(1)
131
+    UART_DECL(1);
132
+  #endif
133
+  #if UART_PRESENT(2)
134
+    UART_DECL(2);
107
   #endif
135
   #endif
136
+  #if UART_PRESENT(3)
137
+    UART_DECL(3);
138
+  #endif
139
+
140
+  #define DEC 10
141
+  #define HEX 16
142
+  #define OCT 8
143
+  #define BIN 2
144
+  #define BYTE 0
108
 
145
 
146
+  // Templated type selector
147
+  template<bool b, typename T, typename F> struct TypeSelector { typedef T type;} ;
148
+  template<typename T, typename F> struct TypeSelector<false, T, F> { typedef F type; };
149
+
150
+  template<typename Cfg>
109
   class MarlinSerial {
151
   class MarlinSerial {
152
+  protected:
153
+    // Registers
154
+    static constexpr R_UCSRxA<Cfg::PORT> R_UCSRA = 0;
155
+    static constexpr R_UDRx<Cfg::PORT>   R_UDR   = 0;
156
+    static constexpr R_UBRRxH<Cfg::PORT> R_UBRRH = 0;
157
+    static constexpr R_UBRRxL<Cfg::PORT> R_UBRRL = 0;
158
+
159
+    // Bits
160
+    static constexpr B_RXENx<Cfg::PORT>  B_RXEN  = 0;
161
+    static constexpr B_TXENx<Cfg::PORT>  B_TXEN  = 0;
162
+    static constexpr B_TXCx<Cfg::PORT>   B_TXC   = 0;
163
+    static constexpr B_RXCIEx<Cfg::PORT> B_RXCIE = 0;
164
+    static constexpr B_UDREx<Cfg::PORT>  B_UDRE  = 0;
165
+    static constexpr B_FEx<Cfg::PORT>    B_FE    = 0;
166
+    static constexpr B_DORx<Cfg::PORT>   B_DOR   = 0;
167
+    static constexpr B_UDRIEx<Cfg::PORT> B_UDRIE = 0;
168
+    static constexpr B_RXCx<Cfg::PORT>   B_RXC   = 0;
169
+    static constexpr B_U2Xx<Cfg::PORT>   B_U2X   = 0;
170
+
171
+    // Base size of type on buffer size
172
+    typedef typename TypeSelector<(Cfg::RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t;
173
+
174
+    struct ring_buffer_r {
175
+      volatile ring_buffer_pos_t head, tail;
176
+      unsigned char buffer[Cfg::RX_SIZE];
177
+    };
178
+
179
+    struct ring_buffer_t {
180
+      volatile uint8_t head, tail;
181
+      unsigned char buffer[Cfg::TX_SIZE];
182
+    };
183
+
184
+    static ring_buffer_r rx_buffer;
185
+    static ring_buffer_t tx_buffer;
186
+    static bool _written;
187
+
188
+    static constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80,  // XON / XOFF Character was sent
189
+                             XON_XOFF_CHAR_MASK = 0x1F;  // XON / XOFF character to send
190
+
191
+    // XON / XOFF character definitions
192
+    static constexpr uint8_t XON_CHAR  = 17, XOFF_CHAR = 19;
193
+    static uint8_t xon_xoff_state,
194
+                   rx_dropped_bytes,
195
+                   rx_buffer_overruns,
196
+                   rx_framing_errors;
197
+    static ring_buffer_pos_t rx_max_enqueued;
198
+
199
+    static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_head();
200
+
201
+    static volatile bool rx_tail_value_not_stable;
202
+    static volatile uint16_t rx_tail_value_backup;
203
+
204
+    static FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value);
205
+    static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail();
206
+
207
+    public:
208
+
209
+    FORCE_INLINE static void store_rxd_char();
210
+    FORCE_INLINE static void _tx_udr_empty_irq(void);
110
 
211
 
111
     public:
212
     public:
112
       MarlinSerial() {};
213
       MarlinSerial() {};
119
       static void write(const uint8_t c);
220
       static void write(const uint8_t c);
120
       static void flushTX(void);
221
       static void flushTX(void);
121
 
222
 
122
-      #if ENABLED(SERIAL_STATS_DROPPED_RX)
123
-        FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; }
124
-      #endif
125
-
126
-      #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
127
-        FORCE_INLINE static uint32_t buffer_overruns() { return rx_buffer_overruns; }
128
-      #endif
129
-
130
-      #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
131
-        FORCE_INLINE static uint32_t framing_errors() { return rx_framing_errors; }
132
-      #endif
133
-
134
-      #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
135
-        FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return rx_max_enqueued; }
136
-      #endif
223
+      FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; }
224
+      FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
225
+      FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
226
+      FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
137
 
227
 
138
       FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
228
       FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
139
       FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
229
       FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
165
       static void printFloat(double, uint8_t);
255
       static void printFloat(double, uint8_t);
166
   };
256
   };
167
 
257
 
168
-  extern MarlinSerial customizedSerial;
258
+  // Serial port configuration
259
+  struct MarlinSerialCfg {
260
+    static constexpr int PORT               = SERIAL_PORT;
261
+    static constexpr unsigned int RX_SIZE   = RX_BUFFER_SIZE;
262
+    static constexpr unsigned int TX_SIZE   = TX_BUFFER_SIZE;
263
+    static constexpr bool XONOFF            = bSERIAL_XON_XOFF;
264
+    static constexpr bool EMERGENCYPARSER   = bEMERGENCY_PARSER;
265
+    static constexpr bool DROPPED_RX        = bSERIAL_STATS_DROPPED_RX;
266
+    static constexpr bool RX_OVERRUNS       = bSERIAL_STATS_RX_BUFFER_OVERRUNS;
267
+    static constexpr bool RX_FRAMING_ERRORS = bSERIAL_STATS_RX_FRAMING_ERRORS;
268
+    static constexpr bool MAX_RX_QUEUED     = bSERIAL_STATS_MAX_RX_QUEUED;
269
+  };
270
+
271
+  extern MarlinSerial<MarlinSerialCfg> customizedSerial;
169
 
272
 
170
 #endif // !USBCON
273
 #endif // !USBCON
171
 
274
 

+ 2
- 2
Marlin/src/HAL/HAL_DUE/MarlinSerialUSB_Due.h ファイルの表示

52
   static void write(const uint8_t c);
52
   static void write(const uint8_t c);
53
 
53
 
54
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
54
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
55
-  FORCE_INLINE static uint32_t dropped() { return 0; }
55
+    FORCE_INLINE static uint32_t dropped() { return 0; }
56
   #endif
56
   #endif
57
 
57
 
58
   #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
58
   #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
59
-  FORCE_INLINE static int rxMaxEnqueued() { return 0; }
59
+    FORCE_INLINE static int rxMaxEnqueued() { return 0; }
60
   #endif
60
   #endif
61
 
61
 
62
   FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
62
   FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }

+ 150
- 212
Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp ファイルの表示

29
 
29
 
30
 #include "../../inc/MarlinConfig.h"
30
 #include "../../inc/MarlinConfig.h"
31
 
31
 
32
-#include "MarlinSerial_Due.h"
33
-#include "InterruptVectors_Due.h"
34
-#include "../../Marlin.h"
35
-
36
 // If not using the USB port as serial port
32
 // If not using the USB port as serial port
37
 #if SERIAL_PORT >= 0
33
 #if SERIAL_PORT >= 0
38
 
34
 
39
-  // Based on selected port, use the proper configuration
40
-  #if SERIAL_PORT == 0
41
-    #define HWUART UART
42
-    #define HWUART_IRQ UART_IRQn
43
-    #define HWUART_IRQ_ID ID_UART
44
-  #elif SERIAL_PORT == 1
45
-    #define HWUART ((Uart*)USART0)
46
-    #define HWUART_IRQ USART0_IRQn
47
-    #define HWUART_IRQ_ID ID_USART0
48
-  #elif SERIAL_PORT == 2
49
-    #define HWUART ((Uart*)USART1)
50
-    #define HWUART_IRQ USART1_IRQn
51
-    #define HWUART_IRQ_ID ID_USART1
52
-  #elif SERIAL_PORT == 3
53
-    #define HWUART ((Uart*)USART2)
54
-    #define HWUART_IRQ USART2_IRQn
55
-    #define HWUART_IRQ_ID ID_USART2
56
-  #elif SERIAL_PORT == 4
57
-    #define HWUART ((Uart*)USART3)
58
-    #define HWUART_IRQ USART3_IRQn
59
-    #define HWUART_IRQ_ID ID_USART3
60
-  #endif
61
-
62
-  struct ring_buffer_r {
63
-    unsigned char buffer[RX_BUFFER_SIZE];
64
-    volatile ring_buffer_pos_t head, tail;
65
-  };
66
-
67
-  #if TX_BUFFER_SIZE > 0
68
-    struct ring_buffer_t {
69
-      unsigned char buffer[TX_BUFFER_SIZE];
70
-      volatile uint8_t head, tail;
71
-    };
72
-  #endif
73
-
74
-  ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
75
-  #if TX_BUFFER_SIZE > 0
76
-    ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
77
-  #endif
78
-  static bool _written;
79
-
80
-  #if ENABLED(SERIAL_XON_XOFF)
81
-    constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80,  // XON / XOFF Character was sent
82
-                      XON_XOFF_CHAR_MASK = 0x1F;  // XON / XOFF character to send
83
-    // XON / XOFF character definitions
84
-    constexpr uint8_t XON_CHAR  = 17, XOFF_CHAR = 19;
85
-    uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR;
86
-
87
-    // Validate that RX buffer size is at least 4096 bytes- According to several experiments, on
88
-    // the original Arduino Due that uses a ATmega16U2 as USB to serial bridge, due to the introduced
89
-    // latencies, at least 2959 bytes of RX buffering (when transmitting at 250kbits/s) are required
90
-    // to avoid overflows.
91
-
92
-    #if RX_BUFFER_SIZE < 4096
93
-      #error Arduino DUE requires at least 4096 bytes of RX buffer to avoid buffer overflows when using XON/XOFF handshake
94
-    #endif
95
-  #endif
96
-
97
-  #if ENABLED(SERIAL_STATS_DROPPED_RX)
98
-    uint8_t rx_dropped_bytes = 0;
99
-  #endif
100
-
101
-  #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
102
-    uint8_t rx_buffer_overruns = 0;
103
-  #endif
104
-
105
-  #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
106
-    uint8_t rx_framing_errors = 0;
107
-  #endif
108
-
109
-  #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
110
-    ring_buffer_pos_t rx_max_enqueued = 0;
111
-  #endif
35
+  #include "MarlinSerial_Due.h"
36
+  #include "InterruptVectors_Due.h"
37
+  #include "../../Marlin.h"
38
+
39
+  template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_r MarlinSerial<Cfg>::rx_buffer = { 0 };
40
+  template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_t MarlinSerial<Cfg>::tx_buffer = { 0 };
41
+  template<typename Cfg> bool     MarlinSerial<Cfg>::_written = false;
42
+  template<typename Cfg> uint8_t  MarlinSerial<Cfg>::xon_xoff_state = MarlinSerial<Cfg>::XON_XOFF_CHAR_SENT | MarlinSerial<Cfg>::XON_CHAR;
43
+  template<typename Cfg> uint8_t  MarlinSerial<Cfg>::rx_dropped_bytes = 0;
44
+  template<typename Cfg> uint8_t  MarlinSerial<Cfg>::rx_buffer_overruns = 0;
45
+  template<typename Cfg> uint8_t  MarlinSerial<Cfg>::rx_framing_errors = 0;
46
+  template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::rx_max_enqueued = 0;
112
 
47
 
113
   // A SW memory barrier, to ensure GCC does not overoptimize loops
48
   // A SW memory barrier, to ensure GCC does not overoptimize loops
114
   #define sw_barrier() asm volatile("": : :"memory");
49
   #define sw_barrier() asm volatile("": : :"memory");
115
 
50
 
116
-  #if ENABLED(EMERGENCY_PARSER)
117
-    #include "../../feature/emergency_parser.h"
118
-  #endif
51
+  #include "../../feature/emergency_parser.h"
119
 
52
 
120
   // (called with RX interrupts disabled)
53
   // (called with RX interrupts disabled)
121
-  FORCE_INLINE void store_rxd_char() {
54
+  template<typename Cfg>
55
+  FORCE_INLINE void MarlinSerial<Cfg>::store_rxd_char() {
122
 
56
 
123
-    #if ENABLED(EMERGENCY_PARSER)
124
-      static EmergencyParser::State emergency_state; // = EP_RESET
125
-    #endif
57
+    static EmergencyParser::State emergency_state; // = EP_RESET
126
 
58
 
127
     // Get the tail - Nothing can alter its value while we are at this ISR
59
     // Get the tail - Nothing can alter its value while we are at this ISR
128
     const ring_buffer_pos_t t = rx_buffer.tail;
60
     const ring_buffer_pos_t t = rx_buffer.tail;
131
     ring_buffer_pos_t h = rx_buffer.head;
63
     ring_buffer_pos_t h = rx_buffer.head;
132
 
64
 
133
     // Get the next element
65
     // Get the next element
134
-    ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
66
+    ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
135
 
67
 
136
     // Read the character from the USART
68
     // Read the character from the USART
137
     uint8_t c = HWUART->UART_RHR;
69
     uint8_t c = HWUART->UART_RHR;
138
 
70
 
139
-    #if ENABLED(EMERGENCY_PARSER)
140
-      emergency_parser.update(emergency_state, c);
141
-    #endif
71
+    if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
142
 
72
 
143
     // If the character is to be stored at the index just before the tail
73
     // If the character is to be stored at the index just before the tail
144
     // (such that the head would advance to the current tail), the RX FIFO is
74
     // (such that the head would advance to the current tail), the RX FIFO is
147
       rx_buffer.buffer[h] = c;
77
       rx_buffer.buffer[h] = c;
148
       h = i;
78
       h = i;
149
     }
79
     }
150
-    #if ENABLED(SERIAL_STATS_DROPPED_RX)
151
-      else if (!++rx_dropped_bytes) --rx_dropped_bytes;
152
-    #endif
80
+    else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
81
+      --rx_dropped_bytes;
153
 
82
 
154
-    #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
155
-      const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
156
-      // Calculate count of bytes stored into the RX buffer
83
+    const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
84
+    // Calculate count of bytes stored into the RX buffer
157
 
85
 
158
-      // Keep track of the maximum count of enqueued bytes
159
-      NOLESS(rx_max_enqueued, rx_count);
160
-    #endif
86
+    // Keep track of the maximum count of enqueued bytes
87
+    if (Cfg::MAX_RX_QUEUED) NOLESS(rx_max_enqueued, rx_count);
161
 
88
 
162
-    #if ENABLED(SERIAL_XON_XOFF)
89
+    if (Cfg::XONOFF) {
163
       // If the last char that was sent was an XON
90
       // If the last char that was sent was an XON
164
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
91
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
165
 
92
 
166
         // Bytes stored into the RX buffer
93
         // Bytes stored into the RX buffer
167
-        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
94
+        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
168
 
95
 
169
         // If over 12.5% of RX buffer capacity, send XOFF before running out of
96
         // If over 12.5% of RX buffer capacity, send XOFF before running out of
170
         // RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
97
         // RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
171
         // and stop sending bytes. This translates to 13mS propagation time.
98
         // and stop sending bytes. This translates to 13mS propagation time.
172
-        if (rx_count >= (RX_BUFFER_SIZE) / 8) {
99
+        if (rx_count >= (Cfg::RX_SIZE) / 8) {
173
 
100
 
174
           // At this point, definitely no TX interrupt was executing, since the TX isr can't be preempted.
101
           // At this point, definitely no TX interrupt was executing, since the TX isr can't be preempted.
175
           // Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
102
           // Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
189
             if (status & UART_SR_RXRDY) {
116
             if (status & UART_SR_RXRDY) {
190
               // We received a char while waiting for the TX buffer to be empty - Receive and process it!
117
               // We received a char while waiting for the TX buffer to be empty - Receive and process it!
191
 
118
 
192
-              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
119
+              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
193
 
120
 
194
               // Read the character from the USART
121
               // Read the character from the USART
195
               c = HWUART->UART_RHR;
122
               c = HWUART->UART_RHR;
196
 
123
 
197
-              #if ENABLED(EMERGENCY_PARSER)
198
-                emergency_parser.update(emergency_state, c);
199
-              #endif
124
+              if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
200
 
125
 
201
               // If the character is to be stored at the index just before the tail
126
               // If the character is to be stored at the index just before the tail
202
               // (such that the head would advance to the current tail), the FIFO is
127
               // (such that the head would advance to the current tail), the FIFO is
205
                 rx_buffer.buffer[h] = c;
130
                 rx_buffer.buffer[h] = c;
206
                 h = i;
131
                 h = i;
207
               }
132
               }
208
-              #if ENABLED(SERIAL_STATS_DROPPED_RX)
209
-                else if (!++rx_dropped_bytes) --rx_dropped_bytes;
210
-              #endif
133
+              else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
134
+                --rx_dropped_bytes;
211
             }
135
             }
212
             sw_barrier();
136
             sw_barrier();
213
           }
137
           }
226
             if (status & UART_SR_RXRDY) {
150
             if (status & UART_SR_RXRDY) {
227
               // A char arrived while waiting for the TX buffer to be empty - Receive and process it!
151
               // A char arrived while waiting for the TX buffer to be empty - Receive and process it!
228
 
152
 
229
-              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
153
+              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
230
 
154
 
231
               // Read the character from the USART
155
               // Read the character from the USART
232
               c = HWUART->UART_RHR;
156
               c = HWUART->UART_RHR;
233
 
157
 
234
-              #if ENABLED(EMERGENCY_PARSER)
235
-                emergency_parser.update(emergency_state, c);
236
-              #endif
158
+              if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
237
 
159
 
238
               // If the character is to be stored at the index just before the tail
160
               // If the character is to be stored at the index just before the tail
239
               // (such that the head would advance to the current tail), the FIFO is
161
               // (such that the head would advance to the current tail), the FIFO is
242
                 rx_buffer.buffer[h] = c;
164
                 rx_buffer.buffer[h] = c;
243
                 h = i;
165
                 h = i;
244
               }
166
               }
245
-              #if ENABLED(SERIAL_STATS_DROPPED_RX)
246
-                else if (!++rx_dropped_bytes) --rx_dropped_bytes;
247
-              #endif
167
+              else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
168
+                --rx_dropped_bytes;
248
             }
169
             }
249
             sw_barrier();
170
             sw_barrier();
250
           }
171
           }
253
           // have any issues writing to the UART TX register if it needs to!
174
           // have any issues writing to the UART TX register if it needs to!
254
         }
175
         }
255
       }
176
       }
256
-    #endif // SERIAL_XON_XOFF
177
+    }
257
 
178
 
258
     // Store the new head value
179
     // Store the new head value
259
     rx_buffer.head = h;
180
     rx_buffer.head = h;
260
   }
181
   }
261
 
182
 
262
-  #if TX_BUFFER_SIZE > 0
263
-
264
-    FORCE_INLINE void _tx_thr_empty_irq(void) {
183
+  template<typename Cfg>
184
+  FORCE_INLINE void MarlinSerial<Cfg>::_tx_thr_empty_irq(void) {
185
+    if (Cfg::TX_SIZE > 0) {
265
       // Read positions
186
       // Read positions
266
       uint8_t t = tx_buffer.tail;
187
       uint8_t t = tx_buffer.tail;
267
       const uint8_t h = tx_buffer.head;
188
       const uint8_t h = tx_buffer.head;
268
 
189
 
269
-      #if ENABLED(SERIAL_XON_XOFF)
190
+      if (Cfg::XONOFF) {
270
         // If an XON char is pending to be sent, do it now
191
         // If an XON char is pending to be sent, do it now
271
         if (xon_xoff_state == XON_CHAR) {
192
         if (xon_xoff_state == XON_CHAR) {
272
 
193
 
281
 
202
 
282
           return;
203
           return;
283
         }
204
         }
284
-      #endif
205
+      }
285
 
206
 
286
       // If nothing to transmit, just disable TX interrupts. This could
207
       // If nothing to transmit, just disable TX interrupts. This could
287
       // happen as the result of the non atomicity of the disabling of RX
208
       // happen as the result of the non atomicity of the disabling of RX
293
 
214
 
294
       // There is something to TX, Send the next byte
215
       // There is something to TX, Send the next byte
295
       const uint8_t c = tx_buffer.buffer[t];
216
       const uint8_t c = tx_buffer.buffer[t];
296
-      t = (t + 1) & (TX_BUFFER_SIZE - 1);
217
+      t = (t + 1) & (Cfg::TX_SIZE - 1);
297
       HWUART->UART_THR = c;
218
       HWUART->UART_THR = c;
298
       tx_buffer.tail = t;
219
       tx_buffer.tail = t;
299
 
220
 
300
       // Disable interrupts if there is nothing to transmit following this byte
221
       // Disable interrupts if there is nothing to transmit following this byte
301
       if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY;
222
       if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY;
302
     }
223
     }
224
+  }
303
 
225
 
304
-  #endif // TX_BUFFER_SIZE > 0
305
-
306
-  static void UART_ISR(void) {
226
+  template<typename Cfg>
227
+  void MarlinSerial<Cfg>::UART_ISR(void) {
307
     const uint32_t status = HWUART->UART_SR;
228
     const uint32_t status = HWUART->UART_SR;
308
 
229
 
309
     // Data received?
230
     // Data received?
310
     if (status & UART_SR_RXRDY) store_rxd_char();
231
     if (status & UART_SR_RXRDY) store_rxd_char();
311
 
232
 
312
-    #if TX_BUFFER_SIZE > 0
233
+    if (Cfg::TX_SIZE > 0) {
313
       // Something to send, and TX interrupts are enabled (meaning something to send)?
234
       // Something to send, and TX interrupts are enabled (meaning something to send)?
314
       if ((status & UART_SR_TXRDY) && (HWUART->UART_IMR & UART_IMR_TXRDY)) _tx_thr_empty_irq();
235
       if ((status & UART_SR_TXRDY) && (HWUART->UART_IMR & UART_IMR_TXRDY)) _tx_thr_empty_irq();
315
-    #endif
236
+    }
316
 
237
 
317
     // Acknowledge errors
238
     // Acknowledge errors
318
     if ((status & UART_SR_OVRE) || (status & UART_SR_FRAME)) {
239
     if ((status & UART_SR_OVRE) || (status & UART_SR_FRAME)) {
319
-
320
-      #if ENABLED(SERIAL_STATS_DROPPED_RX)
321
-        if (status & UART_SR_OVRE && !++rx_dropped_bytes) --rx_dropped_bytes;
322
-      #endif
323
-
324
-      #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
325
-        if (status & UART_SR_OVRE && !++rx_buffer_overruns) --rx_buffer_overruns;
326
-      #endif
327
-
328
-      #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
329
-        if (status & UART_SR_FRAME && !++rx_framing_errors) --rx_framing_errors;
330
-      #endif
240
+      if (Cfg::DROPPED_RX && (status & UART_SR_OVRE) && !++rx_dropped_bytes) --rx_dropped_bytes;
241
+      if (Cfg::RX_OVERRUNS && (status & UART_SR_OVRE) && !++rx_buffer_overruns) --rx_buffer_overruns;
242
+      if (Cfg::RX_FRAMING_ERRORS && (status & UART_SR_FRAME) && !++rx_framing_errors) --rx_framing_errors;
331
 
243
 
332
       // TODO: error reporting outside ISR
244
       // TODO: error reporting outside ISR
333
       HWUART->UART_CR = UART_CR_RSTSTA;
245
       HWUART->UART_CR = UART_CR_RSTSTA;
335
   }
247
   }
336
 
248
 
337
   // Public Methods
249
   // Public Methods
338
-
339
-  void MarlinSerial::begin(const long baud_setting) {
250
+  template<typename Cfg>
251
+  void MarlinSerial<Cfg>::begin(const long baud_setting) {
340
 
252
 
341
     // Disable UART interrupt in NVIC
253
     // Disable UART interrupt in NVIC
342
     NVIC_DisableIRQ( HWUART_IRQ );
254
     NVIC_DisableIRQ( HWUART_IRQ );
382
     // Enable receiver and transmitter
294
     // Enable receiver and transmitter
383
     HWUART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
295
     HWUART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
384
 
296
 
385
-    #if TX_BUFFER_SIZE > 0
386
-      _written = false;
387
-    #endif
297
+    if (Cfg::TX_SIZE > 0) _written = false;
388
   }
298
   }
389
 
299
 
390
-  void MarlinSerial::end() {
300
+  template<typename Cfg>
301
+  void MarlinSerial<Cfg>::end() {
391
     // Disable UART interrupt in NVIC
302
     // Disable UART interrupt in NVIC
392
     NVIC_DisableIRQ( HWUART_IRQ );
303
     NVIC_DisableIRQ( HWUART_IRQ );
393
 
304
 
399
     pmc_disable_periph_clk( HWUART_IRQ_ID );
310
     pmc_disable_periph_clk( HWUART_IRQ_ID );
400
   }
311
   }
401
 
312
 
402
-  int MarlinSerial::peek(void) {
313
+  template<typename Cfg>
314
+  int MarlinSerial<Cfg>::peek(void) {
403
     const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail];
315
     const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail];
404
     return v;
316
     return v;
405
   }
317
   }
406
 
318
 
407
-  int MarlinSerial::read(void) {
319
+  template<typename Cfg>
320
+  int MarlinSerial<Cfg>::read(void) {
408
 
321
 
409
     const ring_buffer_pos_t h = rx_buffer.head;
322
     const ring_buffer_pos_t h = rx_buffer.head;
410
     ring_buffer_pos_t t = rx_buffer.tail;
323
     ring_buffer_pos_t t = rx_buffer.tail;
412
     if (h == t) return -1;
325
     if (h == t) return -1;
413
 
326
 
414
     int v = rx_buffer.buffer[t];
327
     int v = rx_buffer.buffer[t];
415
-    t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
328
+    t = (ring_buffer_pos_t)(t + 1) & (Cfg::RX_SIZE - 1);
416
 
329
 
417
     // Advance tail
330
     // Advance tail
418
     rx_buffer.tail = t;
331
     rx_buffer.tail = t;
419
 
332
 
420
-    #if ENABLED(SERIAL_XON_XOFF)
333
+    if (Cfg::XONOFF) {
421
       // If the XOFF char was sent, or about to be sent...
334
       // If the XOFF char was sent, or about to be sent...
422
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
335
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
423
         // Get count of bytes in the RX buffer
336
         // Get count of bytes in the RX buffer
424
-        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
337
+        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
425
         // When below 10% of RX buffer capacity, send XON before running out of RX buffer bytes
338
         // When below 10% of RX buffer capacity, send XON before running out of RX buffer bytes
426
-        if (rx_count < (RX_BUFFER_SIZE) / 10) {
427
-          #if TX_BUFFER_SIZE > 0
339
+        if (rx_count < (Cfg::RX_SIZE) / 10) {
340
+          if (Cfg::TX_SIZE > 0) {
428
             // Signal we want an XON character to be sent.
341
             // Signal we want an XON character to be sent.
429
             xon_xoff_state = XON_CHAR;
342
             xon_xoff_state = XON_CHAR;
430
             // Enable TX isr.
343
             // Enable TX isr.
431
             HWUART->UART_IER = UART_IER_TXRDY;
344
             HWUART->UART_IER = UART_IER_TXRDY;
432
-          #else
345
+          }
346
+          else {
433
             // If not using TX interrupts, we must send the XON char now
347
             // If not using TX interrupts, we must send the XON char now
434
             xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
348
             xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
435
             while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
349
             while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
436
             HWUART->UART_THR = XON_CHAR;
350
             HWUART->UART_THR = XON_CHAR;
437
-          #endif
351
+          }
438
         }
352
         }
439
       }
353
       }
440
-    #endif
354
+    }
441
 
355
 
442
     return v;
356
     return v;
443
   }
357
   }
444
 
358
 
445
-  ring_buffer_pos_t MarlinSerial::available(void) {
359
+  template<typename Cfg>
360
+  typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::available(void) {
446
     const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail;
361
     const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail;
447
-    return (ring_buffer_pos_t)(RX_BUFFER_SIZE + h - t) & (RX_BUFFER_SIZE - 1);
362
+    return (ring_buffer_pos_t)(Cfg::RX_SIZE + h - t) & (Cfg::RX_SIZE - 1);
448
   }
363
   }
449
 
364
 
450
-  void MarlinSerial::flush(void) {
365
+  template<typename Cfg>
366
+  void MarlinSerial<Cfg>::flush(void) {
451
     rx_buffer.tail = rx_buffer.head;
367
     rx_buffer.tail = rx_buffer.head;
452
 
368
 
453
-    #if ENABLED(SERIAL_XON_XOFF)
369
+    if (Cfg::XONOFF) {
454
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
370
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
455
-        #if TX_BUFFER_SIZE > 0
371
+        if (Cfg::TX_SIZE > 0) {
456
           // Signal we want an XON character to be sent.
372
           // Signal we want an XON character to be sent.
457
           xon_xoff_state = XON_CHAR;
373
           xon_xoff_state = XON_CHAR;
458
           // Enable TX isr.
374
           // Enable TX isr.
459
           HWUART->UART_IER = UART_IER_TXRDY;
375
           HWUART->UART_IER = UART_IER_TXRDY;
460
-        #else
376
+        }
377
+        else {
461
           // If not using TX interrupts, we must send the XON char now
378
           // If not using TX interrupts, we must send the XON char now
462
           xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
379
           xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
463
           while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
380
           while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
464
           HWUART->UART_THR = XON_CHAR;
381
           HWUART->UART_THR = XON_CHAR;
465
-        #endif
382
+        }
466
       }
383
       }
467
-    #endif
384
+    }
468
   }
385
   }
469
 
386
 
470
-  #if TX_BUFFER_SIZE > 0
471
-    void MarlinSerial::write(const uint8_t c) {
472
-      _written = true;
387
+  template<typename Cfg>
388
+  void MarlinSerial<Cfg>::write(const uint8_t c) {
389
+    _written = true;
390
+
391
+    if (Cfg::TX_SIZE == 0) {
392
+      while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
393
+      HWUART->UART_THR = c;
394
+    }
395
+    else {
473
 
396
 
474
       // If the TX interrupts are disabled and the data register
397
       // If the TX interrupts are disabled and the data register
475
       // is empty, just write the byte to the data register and
398
       // is empty, just write the byte to the data register and
483
         return;
406
         return;
484
       }
407
       }
485
 
408
 
486
-      const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
409
+      const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
487
 
410
 
488
       // If global interrupts are disabled (as the result of being called from an ISR)...
411
       // If global interrupts are disabled (as the result of being called from an ISR)...
489
       if (!ISRS_ENABLED()) {
412
       if (!ISRS_ENABLED()) {
508
       // Enable TX isr - Non atomic, but it will eventually enable TX isr
431
       // Enable TX isr - Non atomic, but it will eventually enable TX isr
509
       HWUART->UART_IER = UART_IER_TXRDY;
432
       HWUART->UART_IER = UART_IER_TXRDY;
510
     }
433
     }
434
+  }
511
 
435
 
512
-    void MarlinSerial::flushTX(void) {
513
-      // TX
436
+  template<typename Cfg>
437
+  void MarlinSerial<Cfg>::flushTX(void) {
438
+    // TX
514
 
439
 
440
+    if (Cfg::TX_SIZE == 0) {
441
+      // No bytes written, no need to flush. This special case is needed since there's
442
+      // no way to force the TXC (transmit complete) bit to 1 during initialization.
443
+      if (!_written) return;
444
+
445
+      // Wait until everything was transmitted
446
+      while (!(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier();
447
+
448
+      // At this point nothing is queued anymore (DRIE is disabled) and
449
+      // the hardware finished transmission (TXC is set).
450
+
451
+    }
452
+    else {
515
       // If we have never written a byte, no need to flush. This special
453
       // If we have never written a byte, no need to flush. This special
516
       // case is needed since there is no way to force the TXC (transmit
454
       // case is needed since there is no way to force the TXC (transmit
517
       // complete) bit to 1 during initialization
455
       // complete) bit to 1 during initialization
536
       // At this point nothing is queued anymore (DRIE is disabled) and
474
       // At this point nothing is queued anymore (DRIE is disabled) and
537
       // the hardware finished transmission (TXC is set).
475
       // the hardware finished transmission (TXC is set).
538
     }
476
     }
539
-
540
-  #else // TX_BUFFER_SIZE == 0
541
-
542
-    void MarlinSerial::write(const uint8_t c) {
543
-      _written = true;
544
-      while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
545
-      HWUART->UART_THR = c;
546
-    }
547
-
548
-    void MarlinSerial::flushTX(void) {
549
-      // TX
550
-
551
-      // No bytes written, no need to flush. This special case is needed since there's
552
-      // no way to force the TXC (transmit complete) bit to 1 during initialization.
553
-      if (!_written) return;
554
-
555
-      // Wait until everything was transmitted
556
-      while (!(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier();
557
-
558
-      // At this point nothing is queued anymore (DRIE is disabled) and
559
-      // the hardware finished transmission (TXC is set).
560
-    }
561
-  #endif // TX_BUFFER_SIZE == 0
477
+  }
562
 
478
 
563
   /**
479
   /**
564
    * Imports from print.h
480
    * Imports from print.h
565
    */
481
    */
566
 
482
 
567
-  void MarlinSerial::print(char c, int base) {
483
+  template<typename Cfg>
484
+  void MarlinSerial<Cfg>::print(char c, int base) {
568
     print((long)c, base);
485
     print((long)c, base);
569
   }
486
   }
570
 
487
 
571
-  void MarlinSerial::print(unsigned char b, int base) {
488
+  template<typename Cfg>
489
+  void MarlinSerial<Cfg>::print(unsigned char b, int base) {
572
     print((unsigned long)b, base);
490
     print((unsigned long)b, base);
573
   }
491
   }
574
 
492
 
575
-  void MarlinSerial::print(int n, int base) {
493
+  template<typename Cfg>
494
+  void MarlinSerial<Cfg>::print(int n, int base) {
576
     print((long)n, base);
495
     print((long)n, base);
577
   }
496
   }
578
 
497
 
579
-  void MarlinSerial::print(unsigned int n, int base) {
498
+  template<typename Cfg>
499
+  void MarlinSerial<Cfg>::print(unsigned int n, int base) {
580
     print((unsigned long)n, base);
500
     print((unsigned long)n, base);
581
   }
501
   }
582
 
502
 
583
-  void MarlinSerial::print(long n, int base) {
503
+  template<typename Cfg>
504
+  void MarlinSerial<Cfg>::print(long n, int base) {
584
     if (base == 0) write(n);
505
     if (base == 0) write(n);
585
     else if (base == 10) {
506
     else if (base == 10) {
586
       if (n < 0) { print('-'); n = -n; }
507
       if (n < 0) { print('-'); n = -n; }
590
       printNumber(n, base);
511
       printNumber(n, base);
591
   }
512
   }
592
 
513
 
593
-  void MarlinSerial::print(unsigned long n, int base) {
514
+  template<typename Cfg>
515
+  void MarlinSerial<Cfg>::print(unsigned long n, int base) {
594
     if (base == 0) write(n);
516
     if (base == 0) write(n);
595
     else printNumber(n, base);
517
     else printNumber(n, base);
596
   }
518
   }
597
 
519
 
598
-  void MarlinSerial::print(double n, int digits) {
520
+  template<typename Cfg>
521
+  void MarlinSerial<Cfg>::print(double n, int digits) {
599
     printFloat(n, digits);
522
     printFloat(n, digits);
600
   }
523
   }
601
 
524
 
602
-  void MarlinSerial::println(void) {
525
+  template<typename Cfg>
526
+  void MarlinSerial<Cfg>::println(void) {
603
     print('\r');
527
     print('\r');
604
     print('\n');
528
     print('\n');
605
   }
529
   }
606
 
530
 
607
-  void MarlinSerial::println(const String& s) {
531
+  template<typename Cfg>
532
+  void MarlinSerial<Cfg>::println(const String& s) {
608
     print(s);
533
     print(s);
609
     println();
534
     println();
610
   }
535
   }
611
 
536
 
612
-  void MarlinSerial::println(const char c[]) {
537
+  template<typename Cfg>
538
+  void MarlinSerial<Cfg>::println(const char c[]) {
613
     print(c);
539
     print(c);
614
     println();
540
     println();
615
   }
541
   }
616
 
542
 
617
-  void MarlinSerial::println(char c, int base) {
543
+  template<typename Cfg>
544
+  void MarlinSerial<Cfg>::println(char c, int base) {
618
     print(c, base);
545
     print(c, base);
619
     println();
546
     println();
620
   }
547
   }
621
 
548
 
622
-  void MarlinSerial::println(unsigned char b, int base) {
549
+  template<typename Cfg>
550
+  void MarlinSerial<Cfg>::println(unsigned char b, int base) {
623
     print(b, base);
551
     print(b, base);
624
     println();
552
     println();
625
   }
553
   }
626
 
554
 
627
-  void MarlinSerial::println(int n, int base) {
555
+  template<typename Cfg>
556
+  void MarlinSerial<Cfg>::println(int n, int base) {
628
     print(n, base);
557
     print(n, base);
629
     println();
558
     println();
630
   }
559
   }
631
 
560
 
632
-  void MarlinSerial::println(unsigned int n, int base) {
561
+  template<typename Cfg>
562
+  void MarlinSerial<Cfg>::println(unsigned int n, int base) {
633
     print(n, base);
563
     print(n, base);
634
     println();
564
     println();
635
   }
565
   }
636
 
566
 
637
-  void MarlinSerial::println(long n, int base) {
567
+  template<typename Cfg>
568
+  void MarlinSerial<Cfg>::println(long n, int base) {
638
     print(n, base);
569
     print(n, base);
639
     println();
570
     println();
640
   }
571
   }
641
 
572
 
642
-  void MarlinSerial::println(unsigned long n, int base) {
573
+  template<typename Cfg>
574
+  void MarlinSerial<Cfg>::println(unsigned long n, int base) {
643
     print(n, base);
575
     print(n, base);
644
     println();
576
     println();
645
   }
577
   }
646
 
578
 
647
-  void MarlinSerial::println(double n, int digits) {
579
+  template<typename Cfg>
580
+  void MarlinSerial<Cfg>::println(double n, int digits) {
648
     print(n, digits);
581
     print(n, digits);
649
     println();
582
     println();
650
   }
583
   }
651
 
584
 
652
   // Private Methods
585
   // Private Methods
653
-
654
-  void MarlinSerial::printNumber(unsigned long n, uint8_t base) {
586
+  template<typename Cfg>
587
+  void MarlinSerial<Cfg>::printNumber(unsigned long n, uint8_t base) {
655
     if (n) {
588
     if (n) {
656
       unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
589
       unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
657
       int8_t i = 0;
590
       int8_t i = 0;
666
       print('0');
599
       print('0');
667
   }
600
   }
668
 
601
 
669
-  void MarlinSerial::printFloat(double number, uint8_t digits) {
602
+  template<typename Cfg>
603
+  void MarlinSerial<Cfg>::printFloat(double number, uint8_t digits) {
670
     // Handle negative numbers
604
     // Handle negative numbers
671
     if (number < 0.0) {
605
     if (number < 0.0) {
672
       print('-');
606
       print('-');
697
   }
631
   }
698
 
632
 
699
   // Preinstantiate
633
   // Preinstantiate
700
-  MarlinSerial customizedSerial;
634
+  template class MarlinSerial<MarlinSerialCfg>;
635
+
636
+  // Instantiate
637
+  MarlinSerial<MarlinSerialCfg> customizedSerial;
638
+
701
 #endif
639
 #endif
702
 
640
 
703
 #endif // ARDUINO_ARCH_SAM
641
 #endif // ARDUINO_ARCH_SAM

+ 70
- 37
Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h ファイルの表示

29
 #ifndef MARLINSERIAL_DUE_H
29
 #ifndef MARLINSERIAL_DUE_H
30
 #define MARLINSERIAL_DUE_H
30
 #define MARLINSERIAL_DUE_H
31
 
31
 
32
-#include "../../inc/MarlinConfig.h"
32
+#include "../shared/MarlinSerial.h"
33
 
33
 
34
 #if SERIAL_PORT >= 0
34
 #if SERIAL_PORT >= 0
35
 
35
 
60
 //  #error "TX_BUFFER_SIZE must be 0, a power of 2 greater than 1, and no greater than 256."
60
 //  #error "TX_BUFFER_SIZE must be 0, a power of 2 greater than 1, and no greater than 256."
61
 //#endif
61
 //#endif
62
 
62
 
63
-#if RX_BUFFER_SIZE > 256
64
-  typedef uint16_t ring_buffer_pos_t;
65
-#else
66
-  typedef uint8_t ring_buffer_pos_t;
67
-#endif
68
-
69
-#if ENABLED(SERIAL_STATS_DROPPED_RX)
70
-  extern uint8_t rx_dropped_bytes;
71
-#endif
72
-
73
-#if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
74
-  extern uint8_t rx_buffer_overruns;
75
-#endif
76
-
77
-#if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
78
-  extern uint8_t rx_framing_errors;
79
-#endif
63
+// Templated type selector
64
+template<bool b, typename T, typename F> struct TypeSelector { typedef T type;} ;
65
+template<typename T, typename F> struct TypeSelector<false, T, F> { typedef F type; };
80
 
66
 
81
-#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
82
-  extern ring_buffer_pos_t rx_max_enqueued;
83
-#endif
67
+// Templated structure wrapper
68
+template<typename S, unsigned int addr> struct StructWrapper {
69
+  constexpr StructWrapper(int) {}
70
+  FORCE_INLINE S* operator->() const { return (S*)addr; }
71
+};
84
 
72
 
73
+template<typename Cfg>
85
 class MarlinSerial {
74
 class MarlinSerial {
75
+protected:
76
+  // Information for all supported UARTs
77
+  static constexpr uint32_t BASES[] = {0x400E0800U, 0x40098000U, 0x4009C000U, 0x400A0000U, 0x400A4000U};
78
+  static constexpr IRQn_Type IRQS[] = {  UART_IRQn, USART0_IRQn, USART1_IRQn, USART2_IRQn, USART3_IRQn};
79
+  static constexpr int    IRQ_IDS[] = {    ID_UART,   ID_USART0,   ID_USART1,   ID_USART2,   ID_USART3};
80
+
81
+  // Alias for shorter code
82
+  static constexpr StructWrapper<Uart,BASES[Cfg::PORT]> HWUART = 0;
83
+  static constexpr IRQn_Type HWUART_IRQ = IRQS[Cfg::PORT];
84
+  static constexpr int HWUART_IRQ_ID = IRQ_IDS[Cfg::PORT];
85
+
86
+  // Base size of type on buffer size
87
+  typedef typename TypeSelector<(Cfg::RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t;
88
+
89
+  struct ring_buffer_r {
90
+    volatile ring_buffer_pos_t head, tail;
91
+    unsigned char buffer[Cfg::RX_SIZE];
92
+  };
93
+
94
+  struct ring_buffer_t {
95
+    volatile uint8_t head, tail;
96
+    unsigned char buffer[Cfg::TX_SIZE];
97
+  };
98
+
99
+  static ring_buffer_r rx_buffer;
100
+  static ring_buffer_t tx_buffer;
101
+  static bool _written;
102
+
103
+  static constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80,  // XON / XOFF Character was sent
104
+                           XON_XOFF_CHAR_MASK = 0x1F;  // XON / XOFF character to send
105
+
106
+  // XON / XOFF character definitions
107
+  static constexpr uint8_t XON_CHAR  = 17, XOFF_CHAR = 19;
108
+  static uint8_t xon_xoff_state,
109
+                 rx_dropped_bytes,
110
+                 rx_buffer_overruns,
111
+                 rx_framing_errors;
112
+  static ring_buffer_pos_t rx_max_enqueued;
113
+
114
+  FORCE_INLINE static void store_rxd_char();
115
+  FORCE_INLINE static void _tx_thr_empty_irq(void);
116
+  static void UART_ISR(void);
86
 
117
 
87
 public:
118
 public:
88
   MarlinSerial() {};
119
   MarlinSerial() {};
95
   static void write(const uint8_t c);
126
   static void write(const uint8_t c);
96
   static void flushTX(void);
127
   static void flushTX(void);
97
 
128
 
98
-  #if ENABLED(SERIAL_STATS_DROPPED_RX)
99
-    FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; }
100
-  #endif
101
-
102
-  #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
103
-    FORCE_INLINE static uint32_t buffer_overruns() { return rx_buffer_overruns; }
104
-  #endif
105
-
106
-  #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
107
-    FORCE_INLINE static uint32_t framing_errors() { return rx_framing_errors; }
108
-  #endif
109
-
110
-  #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
111
-    FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return rx_max_enqueued; }
112
-  #endif
129
+  FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; }
130
+  FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
131
+  FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
132
+  FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
113
 
133
 
114
   FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
134
   FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
115
   FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
135
   FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
141
   static void printFloat(double, uint8_t);
161
   static void printFloat(double, uint8_t);
142
 };
162
 };
143
 
163
 
144
-extern MarlinSerial customizedSerial;
164
+// Serial port configuration
165
+struct MarlinSerialCfg {
166
+  static constexpr int PORT               = SERIAL_PORT;
167
+  static constexpr unsigned int RX_SIZE   = RX_BUFFER_SIZE;
168
+  static constexpr unsigned int TX_SIZE   = TX_BUFFER_SIZE;
169
+  static constexpr bool XONOFF            = bSERIAL_XON_XOFF;
170
+  static constexpr bool EMERGENCYPARSER   = bEMERGENCY_PARSER;
171
+  static constexpr bool DROPPED_RX        = bSERIAL_STATS_DROPPED_RX;
172
+  static constexpr bool RX_OVERRUNS       = bSERIAL_STATS_RX_BUFFER_OVERRUNS;
173
+  static constexpr bool RX_FRAMING_ERRORS = bSERIAL_STATS_RX_FRAMING_ERRORS;
174
+  static constexpr bool MAX_RX_QUEUED     = bSERIAL_STATS_MAX_RX_QUEUED;
175
+};
176
+
177
+extern MarlinSerial<MarlinSerialCfg> customizedSerial;
145
 
178
 
146
 #endif // SERIAL_PORT >= 0
179
 #endif // SERIAL_PORT >= 0
147
 
180
 

+ 61
- 0
Marlin/src/HAL/shared/MarlinSerial.h ファイルの表示

1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#pragma once
23
+
24
+/**
25
+ * HAL/shared/MarlinSerial.h
26
+ */
27
+
28
+#include "../../inc/MarlinConfigPre.h"
29
+
30
+constexpr bool
31
+  bSERIAL_XON_XOFF = (false
32
+    #if ENABLED(SERIAL_XON_XOFF)
33
+      || true
34
+    #endif
35
+  ),
36
+  bEMERGENCY_PARSER = (false
37
+    #if ENABLED(EMERGENCY_PARSER)
38
+      || true
39
+    #endif
40
+  ),
41
+  bSERIAL_STATS_DROPPED_RX = (false
42
+    #if ENABLED(SERIAL_STATS_DROPPED_RX)
43
+      || true
44
+    #endif
45
+  ),
46
+  bSERIAL_STATS_RX_BUFFER_OVERRUNS = (false
47
+    #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
48
+      || true
49
+    #endif
50
+  ),
51
+  bSERIAL_STATS_RX_FRAMING_ERRORS = (false
52
+    #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
53
+      || true
54
+    #endif
55
+  ),
56
+  bSERIAL_STATS_MAX_RX_QUEUED = (false
57
+    #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
58
+      || true
59
+    #endif
60
+  );
61
+

読み込み中…
キャンセル
保存