Parcourir la source

Fix XON/XOFF implementation

Pointed out by @GMagician
etagle il y a 6 ans
Parent
révision
d90e8fcad9

+ 261
- 158
Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp Voir le fichier

@@ -56,16 +56,15 @@
56 56
     ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
57 57
     #if TX_BUFFER_SIZE > 0
58 58
       ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
59
-      static bool _written;
60 59
     #endif
60
+    static bool _written;
61 61
   #endif
62 62
 
63 63
   #if ENABLED(SERIAL_XON_XOFF)
64
-    constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80;  // XON / XOFF Character was sent
65
-    constexpr uint8_t XON_XOFF_CHAR_MASK = 0x1F;  // XON / XOFF character to send
64
+    constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80,  // XON / XOFF Character was sent
65
+                      XON_XOFF_CHAR_MASK = 0x1F;  // XON / XOFF character to send
66 66
     // XON / XOFF character definitions
67
-    constexpr uint8_t XON_CHAR  = 17;
68
-    constexpr uint8_t XOFF_CHAR = 19;
67
+    constexpr uint8_t XON_CHAR  = 17, XOFF_CHAR = 19;
69 68
     uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR;
70 69
   #endif
71 70
 
@@ -91,125 +90,196 @@
91 90
       static EmergencyParser::State emergency_state; // = EP_RESET
92 91
     #endif
93 92
 
94
-    const ring_buffer_pos_t h = rx_buffer.head,
95
-                            i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
93
+    // Get the tail - Nothing can alter its value while we are at this ISR
94
+    const ring_buffer_pos_t t = rx_buffer.tail;
96 95
 
97
-    // Read the character
98
-    const uint8_t c = M_UDRx;
96
+    // Get the head pointer
97
+    ring_buffer_pos_t h = rx_buffer.head;
98
+
99
+    // Get the next element
100
+    ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
101
+
102
+    // Read the character from the USART
103
+    uint8_t c = M_UDRx;
104
+
105
+    #if ENABLED(EMERGENCY_PARSER)
106
+      emergency_parser.update(emergency_state, c);
107
+    #endif
99 108
 
100 109
     // If the character is to be stored at the index just before the tail
101
-    // (such that the head would advance to the current tail), the buffer is
102
-    // critical, so don't write the character or advance the head.
103
-    if (i != rx_buffer.tail) {
110
+    // (such that the head would advance to the current tail), the RX FIFO is
111
+    // full, so don't write the character or advance the head.
112
+    if (i != t) {
104 113
       rx_buffer.buffer[h] = c;
105
-      rx_buffer.head = i;
106
-    }
107
-    else {
108
-      #if ENABLED(SERIAL_STATS_DROPPED_RX)
109
-        if (!++rx_dropped_bytes) ++rx_dropped_bytes;
110
-      #endif
114
+      h = i;
111 115
     }
116
+    #if ENABLED(SERIAL_STATS_DROPPED_RX)
117
+      else if (!++rx_dropped_bytes) --rx_dropped_bytes;
118
+    #endif
112 119
 
113 120
     #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
114
-      // calculate count of bytes stored into the RX buffer
115
-      ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
121
+      // Calculate count of bytes stored into the RX buffer
122
+      const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
123
+
116 124
       // Keep track of the maximum count of enqueued bytes
117 125
       NOLESS(rx_max_enqueued, rx_count);
118 126
     #endif
119 127
 
120 128
     #if ENABLED(SERIAL_XON_XOFF)
121
-
122
-      // for high speed transfers, we can use XON/XOFF protocol to do
123
-      // software handshake and avoid overruns.
129
+      // If the last char that was sent was an XON
124 130
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
125 131
 
126
-        // calculate count of bytes stored into the RX buffer
127
-        ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
132
+        // Bytes stored into the RX buffer
133
+        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
128 134
 
129
-        // if we are above 12.5% of RX buffer capacity, send XOFF before
130
-        // we run out of RX buffer space .. We need 325 bytes @ 250kbits/s to
131
-        // let the host react and stop sending bytes. This translates to 13mS
132
-        // propagation time.
135
+        // If over 12.5% of RX buffer capacity, send XOFF before running out of
136
+        // RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
137
+        // and stop sending bytes. This translates to 13mS propagation time.
133 138
         if (rx_count >= (RX_BUFFER_SIZE) / 8) {
134 139
 
135
-          // If TX interrupts are disabled and data register is empty,
136
-          // just write the byte to the data register and be done. This
137
-          // shortcut helps significantly improve the effective datarate
138
-          // at high (>500kbit/s) bitrates, where interrupt overhead
139
-          // becomes a slowdown.
140
-          if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) {
141
-
142
-            // Send an XOFF character
143
-            M_UDRx = XOFF_CHAR;
144
-
145
-            // clear the TXC bit -- "can be cleared by writing a one to its bit
146
-            // location". This makes sure flush() won't return until the bytes
147
-            // actually got written
148
-            SBI(M_UCSRxA, M_TXCx);
149
-
150
-            // And remember it was sent
151
-            xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
140
+          // At this point, definitely no TX interrupt was executing, since the TX isr can't be preempted.
141
+          // Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
142
+          // to be in the middle of trying to disable the RX interrupt in the main program, eventually the
143
+          // enabling of the TX interrupt could be undone. The ONLY reliable thing this can do to ensure
144
+          // the sending of the XOFF char is to send it HERE AND NOW.
145
+
146
+          // About to send the XOFF char
147
+          xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
148
+
149
+          // Wait until the TX register becomes empty and send it - Here there could be a problem
150
+          // - While waiting for the TX register to empty, the RX register could receive a new
151
+          //   character. This must also handle that situation!
152
+          while (!TEST(M_UCSRxA, M_UDREx)) {
153
+
154
+            if (TEST(M_UCSRxA,M_RXCx)) {
155
+              // A char arrived while waiting for the TX buffer to be empty - Receive and process it!
156
+
157
+              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
158
+
159
+              // Read the character from the USART
160
+              c = M_UDRx;
161
+
162
+              #if ENABLED(EMERGENCY_PARSER)
163
+                emergency_parser.update(emergency_state, c);
164
+              #endif
165
+
166
+              // If the character is to be stored at the index just before the tail
167
+              // (such that the head would advance to the current tail), the FIFO is
168
+              // full, so don't write the character or advance the head.
169
+              if (i != t) {
170
+                rx_buffer.buffer[h] = c;
171
+                h = i;
172
+              }
173
+              #if ENABLED(SERIAL_STATS_DROPPED_RX)
174
+                else if (!++rx_dropped_bytes) --rx_dropped_bytes;
175
+              #endif
176
+            }
177
+            sw_barrier();
152 178
           }
153
-          else {
154
-            // TX interrupts disabled, but buffer still not empty ... or
155
-            // TX interrupts enabled. Reenable TX ints and schedule XOFF
156
-            // character to be sent
157
-            #if TX_BUFFER_SIZE > 0
158
-              SBI(M_UCSRxB, M_UDRIEx);
159
-              xon_xoff_state = XOFF_CHAR;
160
-            #else
161
-              // We are not using TX interrupts, we will have to send this manually
162
-              while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
163
-              M_UDRx = XOFF_CHAR;
164
-
165
-              // clear the TXC bit -- "can be cleared by writing a one to its bit
166
-              // location". This makes sure flush() won't return until the bytes
167
-              // actually got written
168
-              SBI(M_UCSRxA, M_TXCx);
169
-
170
-              // And remember we already sent it
171
-              xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
172
-            #endif
179
+
180
+          M_UDRx = XOFF_CHAR;
181
+
182
+          // Clear the TXC bit -- "can be cleared by writing a one to its bit
183
+          // location". This makes sure flush() won't return until the bytes
184
+          // actually got written
185
+          SBI(M_UCSRxA, M_TXCx);
186
+
187
+          // At this point there could be a race condition between the write() function
188
+          // and this sending of the XOFF char. This interrupt could happen between the
189
+          // wait to be empty TX buffer loop and the actual write of the character. Since
190
+          // the TX buffer is full because it's sending the XOFF char, the only way to be
191
+          // sure the write() function will succeed is to wait for the XOFF char to be
192
+          // completely sent. Since an extra character could be received during the wait
193
+          // it must also be handled!
194
+          while (!TEST(M_UCSRxA, M_UDREx)) {
195
+
196
+            if (TEST(M_UCSRxA,M_RXCx)) {
197
+              // A char arrived while waiting for the TX buffer to be empty - Receive and process it!
198
+
199
+              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
200
+
201
+              // Read the character from the USART
202
+              c = M_UDRx;
203
+
204
+              #if ENABLED(EMERGENCY_PARSER)
205
+                emergency_parser.update(emergency_state, c);
206
+              #endif
207
+
208
+              // If the character is to be stored at the index just before the tail
209
+              // (such that the head would advance to the current tail), the FIFO is
210
+              // full, so don't write the character or advance the head.
211
+              if (i != t) {
212
+                rx_buffer.buffer[h] = c;
213
+                h = i;
214
+              }
215
+              #if ENABLED(SERIAL_STATS_DROPPED_RX)
216
+                else if (!++rx_dropped_bytes) --rx_dropped_bytes;
217
+              #endif
218
+            }
219
+            sw_barrier();
173 220
           }
221
+
222
+          // At this point everything is ready. The write() function won't
223
+          // have any issues writing to the UART TX register if it needs to!
174 224
         }
175 225
       }
176 226
     #endif // SERIAL_XON_XOFF
177 227
 
178
-    #if ENABLED(EMERGENCY_PARSER)
179
-      emergency_parser.update(emergency_state, c);
180
-    #endif
228
+    // Store the new head value
229
+    rx_buffer.head = h;
181 230
   }
182 231
 
183 232
   #if TX_BUFFER_SIZE > 0
184 233
 
185 234
     // (called with TX irqs disabled)
186 235
     FORCE_INLINE void _tx_udr_empty_irq(void) {
187
-      // If interrupts are enabled, there must be more data in the output
188
-      // buffer.
236
+
237
+      // Read positions
238
+      uint8_t t = tx_buffer.tail;
239
+      const uint8_t h = tx_buffer.head;
189 240
 
190 241
       #if ENABLED(SERIAL_XON_XOFF)
191
-        // Do a priority insertion of an XON/XOFF char, if needed.
192
-        const uint8_t state = xon_xoff_state;
193
-        if (!(state & XON_XOFF_CHAR_SENT)) {
194
-          M_UDRx = state & XON_XOFF_CHAR_MASK;
195
-          xon_xoff_state = state | XON_XOFF_CHAR_SENT;
242
+        // If an XON char is pending to be sent, do it now
243
+        if (xon_xoff_state == XON_CHAR) {
244
+
245
+          // Send the character
246
+          M_UDRx = XON_CHAR;
247
+
248
+          // clear the TXC bit -- "can be cleared by writing a one to its bit
249
+          // location". This makes sure flush() won't return until the bytes
250
+          // actually got written
251
+          SBI(M_UCSRxA, M_TXCx);
252
+
253
+          // Remember we sent it.
254
+          xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
255
+
256
+          // If nothing else to transmit, just disable TX interrupts.
257
+          if (h == t) CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
258
+
259
+          return;
196 260
         }
197
-        else
198 261
       #endif
199
-      { // Send the next byte
200
-        const uint8_t t = tx_buffer.tail, c = tx_buffer.buffer[t];
201
-        tx_buffer.tail = (t + 1) & (TX_BUFFER_SIZE - 1);
202
-        M_UDRx = c;
262
+
263
+      // If nothing to transmit, just disable TX interrupts. This could
264
+      // happen as the result of the non atomicity of the disabling of RX
265
+      // interrupts that could end reenabling TX interrupts as a side effect.
266
+      if (h == t) {
267
+        CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
268
+        return;
203 269
       }
204 270
 
205
-      // clear the TXC bit -- "can be cleared by writing a one to its bit
206
-      // location". This makes sure flush() won't return until the bytes
207
-      // actually got written
271
+      // There is something to TX, Send the next byte
272
+      const uint8_t c = tx_buffer.buffer[t];
273
+      t = (t + 1) & (TX_BUFFER_SIZE - 1);
274
+      M_UDRx = c;
275
+      tx_buffer.tail = t;
276
+
277
+      // Clear the TXC bit (by writing a one to its bit location).
278
+      // Ensures flush() won't return until the bytes are actually written/
208 279
       SBI(M_UCSRxA, M_TXCx);
209 280
 
210
-      // Disable interrupts if the buffer is empty
211
-      if (tx_buffer.head == tx_buffer.tail)
212
-        CBI(M_UCSRxB, M_UDRIEx);
281
+      // Disable interrupts if there is nothing to transmit following this byte
282
+      if (h == t) CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
213 283
     }
214 284
 
215 285
     #ifdef M_USARTx_UDRE_vect
@@ -253,8 +323,8 @@
253 323
     SBI(M_UCSRxB, M_RXCIEx);
254 324
     #if TX_BUFFER_SIZE > 0
255 325
       CBI(M_UCSRxB, M_UDRIEx);
256
-      _written = false;
257 326
     #endif
327
+    _written = false;
258 328
   }
259 329
 
260 330
   void MarlinSerial::end() {
@@ -281,11 +351,11 @@
281 351
   }
282 352
 
283 353
   int MarlinSerial::read(void) {
284
-    int v;
285 354
 
286 355
     #if RX_BUFFER_SIZE > 256
287
-      // Disable RX interrupts to ensure atomic reads
288
-      const bool isr_enabled = TEST(M_UCSRxB, M_RXCIEx);
356
+      // Disable RX interrupts to ensure atomic reads - This could reenable TX interrupts,
357
+      //  but this situation is explicitly handled at the TX isr, so no problems there
358
+      bool isr_enabled = TEST(M_UCSRxB, M_RXCIEx);
289 359
       CBI(M_UCSRxB, M_RXCIEx);
290 360
     #endif
291 361
 
@@ -298,43 +368,50 @@
298 368
 
299 369
     ring_buffer_pos_t t = rx_buffer.tail;
300 370
 
301
-    if (h == t)
302
-      v = -1;
303
-    else {
304
-      v = rx_buffer.buffer[t];
305
-      t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
306
-
307
-      #if RX_BUFFER_SIZE > 256
308
-        // Disable RX interrupts to ensure atomic write to tail, so
309
-        // the RX isr can't read partially updated values
310
-        const bool isr_enabled = TEST(M_UCSRxB, M_RXCIEx);
311
-        CBI(M_UCSRxB, M_RXCIEx);
312
-      #endif
371
+    // If nothing to read, return now
372
+    if (h == t) return -1;
313 373
 
314
-      // Advance tail
315
-      rx_buffer.tail = t;
374
+    // Get the next char
375
+    const int v = rx_buffer.buffer[t];
376
+    t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
316 377
 
317
-      #if RX_BUFFER_SIZE > 256
318
-        // End critical section
319
-        if (isr_enabled) SBI(M_UCSRxB, M_RXCIEx);
320
-      #endif
378
+    #if RX_BUFFER_SIZE > 256
379
+      // Disable RX interrupts to ensure atomic write to tail, so
380
+      // the RX isr can't read partially updated values - This could
381
+      // reenable TX interrupts, but this situation is explicitly
382
+      // handled at the TX isr, so no problems there
383
+      isr_enabled = TEST(M_UCSRxB, M_RXCIEx);
384
+      CBI(M_UCSRxB, M_RXCIEx);
385
+    #endif
321 386
 
322
-      #if ENABLED(SERIAL_XON_XOFF)
323
-        if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
387
+    // Advance tail
388
+    rx_buffer.tail = t;
324 389
 
325
-          // Get count of bytes in the RX buffer
326
-          ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
390
+    #if RX_BUFFER_SIZE > 256
391
+      // End critical section
392
+      if (isr_enabled) SBI(M_UCSRxB, M_RXCIEx);
393
+    #endif
327 394
 
328
-          // When below 10% of RX buffer capacity, send XON before
329
-          // running out of RX buffer bytes
330
-          if (rx_count < (RX_BUFFER_SIZE) / 10) {
395
+    #if ENABLED(SERIAL_XON_XOFF)
396
+      // If the XOFF char was sent, or about to be sent...
397
+      if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
398
+        // Get count of bytes in the RX buffer
399
+        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
400
+        if (rx_count < (RX_BUFFER_SIZE) / 10) {
401
+          #if TX_BUFFER_SIZE > 0
402
+            // Signal we want an XON character to be sent.
403
+            xon_xoff_state = XON_CHAR;
404
+            // Enable TX isr. Non atomic, but it will eventually enable them
405
+            SBI(M_UCSRxB, M_UDRIEx);
406
+          #else
407
+            // If not using TX interrupts, we must send the XON char now
331 408
             xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
332
-            write(XON_CHAR);
333
-            return v;
334
-          }
409
+            while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
410
+            M_UDRx = XON_CHAR;
411
+          #endif
335 412
         }
336
-      #endif
337
-    }
413
+      }
414
+    #endif
338 415
 
339 416
     return v;
340 417
   }
@@ -367,9 +444,19 @@
367 444
     #endif
368 445
 
369 446
     #if ENABLED(SERIAL_XON_XOFF)
447
+      // If the XOFF char was sent, or about to be sent...
370 448
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
371
-        xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
372
-        write(XON_CHAR);
449
+        #if TX_BUFFER_SIZE > 0
450
+          // Signal we want an XON character to be sent.
451
+          xon_xoff_state = XON_CHAR;
452
+          // Enable TX isr. Non atomic, but it will eventually enable it.
453
+          SBI(M_UCSRxB, M_UDRIEx);
454
+        #else
455
+          // If not using TX interrupts, we must send the XON char now
456
+          xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
457
+          while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
458
+          M_UDRx = XON_CHAR;
459
+        #endif
373 460
       }
374 461
     #endif
375 462
   }
@@ -383,6 +470,8 @@
383 470
       // be done. This shortcut helps significantly improve the
384 471
       // effective datarate at high (>500kbit/s) bitrates, where
385 472
       // interrupt overhead becomes a slowdown.
473
+      // Yes, there is a race condition between the sending of the
474
+      // XOFF char at the RX isr, but it is properly handled there
386 475
       if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) {
387 476
         M_UDRx = c;
388 477
 
@@ -395,61 +484,79 @@
395 484
 
396 485
       const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
397 486
 
398
-      // If the output buffer is full, there's nothing for it other than to
399
-      // wait for the interrupt handler to empty it a bit
400
-      while (i == tx_buffer.tail) {
401
-        if (!ISRS_ENABLED()) {
402
-          // Interrupts are disabled, so we'll have to poll the data
403
-          // register empty flag ourselves. If it is set, pretend an
404
-          // interrupt has happened and call the handler to free up
405
-          // space for us.
406
-          if (TEST(M_UCSRxA, M_UDREx))
407
-            _tx_udr_empty_irq();
408
-        }
409
-        // (else , the interrupt handler will free up space for us)
487
+      // If global interrupts are disabled (as the result of being called from an ISR)...
488
+      if (!ISRS_ENABLED()) {
489
+
490
+        // Make room by polling if it is possible to transmit, and do so!
491
+        while (i == tx_buffer.tail) {
410 492
 
411
-        // Make sure compiler rereads tx_buffer.tail
412
-        sw_barrier();
493
+          // If we can transmit another byte, do it.
494
+          if (TEST(M_UCSRxA, M_UDREx)) _tx_udr_empty_irq();
495
+
496
+          // Make sure compiler rereads tx_buffer.tail
497
+          sw_barrier();
498
+        }
499
+      }
500
+      else {
501
+        // Interrupts are enabled, just wait until there is space
502
+        while (i == tx_buffer.tail) { sw_barrier(); }
413 503
       }
414 504
 
415 505
       // Store new char. head is always safe to move
416 506
       tx_buffer.buffer[tx_buffer.head] = c;
417 507
       tx_buffer.head = i;
418 508
 
419
-      // Enable TX isr
509
+      // Enable TX isr - Non atomic, but it will eventually enable TX isr
420 510
       SBI(M_UCSRxB, M_UDRIEx);
421
-      return;
422 511
     }
423 512
 
424 513
     void MarlinSerial::flushTX(void) {
425
-      // TX
426
-      // If we have never written a byte, no need to flush. This special
427
-      // case is needed since there is no way to force the TXC (transmit
428
-      // complete) bit to 1 during initialization
429
-      if (!_written)
430
-        return;
514
+      // No bytes written, no need to flush. This special case is needed since there's
515
+      // no way to force the TXC (transmit complete) bit to 1 during initialization.
516
+      if (!_written) return;
517
+
518
+      // If global interrupts are disabled (as the result of being called from an ISR)...
519
+      if (!ISRS_ENABLED()) {
431 520
 
432
-      while (TEST(M_UCSRxB, M_UDRIEx) || !TEST(M_UCSRxA, M_TXCx)) {
433
-        if (!ISRS_ENABLED()) {
434
-          // Interrupts are globally disabled, but the DR empty
435
-          // interrupt should be enabled, so poll the DR empty flag to
436
-          // prevent deadlock
521
+        // Wait until everything was transmitted - We must do polling, as interrupts are disabled
522
+        while (tx_buffer.head != tx_buffer.tail || !TEST(M_UCSRxA, M_TXCx)) {
523
+
524
+          // If there is more space, send an extra character
437 525
           if (TEST(M_UCSRxA, M_UDREx))
438 526
             _tx_udr_empty_irq();
527
+
528
+          sw_barrier();
439 529
         }
440
-        sw_barrier();
530
+
531
+      }
532
+      else {
533
+        // Wait until everything was transmitted
534
+        while (tx_buffer.head != tx_buffer.tail || !TEST(M_UCSRxA, M_TXCx)) sw_barrier();
441 535
       }
442
-      // If we get here, nothing is queued anymore (DRIE is disabled) and
536
+
537
+      // At this point nothing is queued anymore (DRIE is disabled) and
443 538
       // the hardware finished transmission (TXC is set).
444 539
     }
445 540
 
446 541
   #else // TX_BUFFER_SIZE == 0
447 542
 
448 543
     void MarlinSerial::write(const uint8_t c) {
544
+      _written = true;
449 545
       while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
450 546
       M_UDRx = c;
451 547
     }
452 548
 
549
+    void MarlinSerial::flushTX(void) {
550
+      // No bytes written, no need to flush. This special case is needed since there's
551
+      // no way to force the TXC (transmit complete) bit to 1 during initialization.
552
+      if (!_written) return;
553
+
554
+      // Wait until everything was transmitted
555
+      while (!TEST(M_UCSRxA, M_TXCx)) sw_barrier();
556
+
557
+      // At this point nothing is queued anymore (DRIE is disabled) and
558
+      // the hardware finished transmission (TXC is set).
559
+    }
453 560
   #endif // TX_BUFFER_SIZE == 0
454 561
 
455 562
   /**
@@ -473,13 +580,9 @@
473 580
   }
474 581
 
475 582
   void MarlinSerial::print(long n, int base) {
476
-    if (base == 0)
477
-      write(n);
583
+    if (base == 0) write(n);
478 584
     else if (base == 10) {
479
-      if (n < 0) {
480
-        print('-');
481
-        n = -n;
482
-      }
585
+      if (n < 0) { print('-'); n = -n; }
483 586
       printNumber(n, 10);
484 587
     }
485 588
     else

+ 6
- 7
Marlin/src/HAL/HAL_AVR/MarlinSerial.h Voir le fichier

@@ -75,6 +75,7 @@
75 75
 #define HEX 16
76 76
 #define OCT 8
77 77
 #define BIN 2
78
+#define BYTE 0
78 79
 
79 80
 #ifndef USBCON
80 81
   // We're using a ring buffer (I think), in which rx_buffer_head is the index of the
@@ -105,9 +106,7 @@
105 106
       static void flush(void);
106 107
       static ring_buffer_pos_t available(void);
107 108
       static void write(const uint8_t c);
108
-      #if TX_BUFFER_SIZE > 0
109
-        static void flushTX(void);
110
-      #endif
109
+      static void flushTX(void);
111 110
 
112 111
       #if ENABLED(SERIAL_STATS_DROPPED_RX)
113 112
         FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; }
@@ -122,8 +121,8 @@
122 121
       FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
123 122
       FORCE_INLINE static void print(const char* str) { write(str); }
124 123
 
125
-      static void print(char, int = 0);
126
-      static void print(unsigned char, int = 0);
124
+      static void print(char, int = BYTE);
125
+      static void print(unsigned char, int = BYTE);
127 126
       static void print(int, int = DEC);
128 127
       static void print(unsigned int, int = DEC);
129 128
       static void print(long, int = DEC);
@@ -132,8 +131,8 @@
132 131
 
133 132
       static void println(const String& s);
134 133
       static void println(const char[]);
135
-      static void println(char, int = 0);
136
-      static void println(unsigned char, int = 0);
134
+      static void println(char, int = BYTE);
135
+      static void println(unsigned char, int = BYTE);
137 136
       static void println(int, int = DEC);
138 137
       static void println(unsigned int, int = DEC);
139 138
       static void println(long, int = DEC);

+ 253
- 147
Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp Voir le fichier

@@ -74,15 +74,14 @@
74 74
   ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
75 75
   #if TX_BUFFER_SIZE > 0
76 76
     ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
77
-    static bool _written;
78 77
   #endif
78
+  static bool _written;
79 79
 
80 80
   #if ENABLED(SERIAL_XON_XOFF)
81
-    constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80;  // XON / XOFF Character was sent
82
-    constexpr uint8_t XON_XOFF_CHAR_MASK = 0x1F;  // XON / XOFF character to send
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 83
     // XON / XOFF character definitions
84
-    constexpr uint8_t XON_CHAR  = 17;
85
-    constexpr uint8_t XOFF_CHAR = 19;
84
+    constexpr uint8_t XON_CHAR  = 17, XOFF_CHAR = 19;
86 85
     uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR;
87 86
 
88 87
     // Validate that RX buffer size is at least 4096 bytes- According to several experiments, on
@@ -110,128 +109,201 @@
110 109
     #include "../../feature/emergency_parser.h"
111 110
   #endif
112 111
 
112
+  // (called with RX interrupts disabled)
113 113
   FORCE_INLINE void store_rxd_char() {
114 114
 
115 115
     #if ENABLED(EMERGENCY_PARSER)
116 116
       static EmergencyParser::State emergency_state; // = EP_RESET
117 117
     #endif
118 118
 
119
-    const ring_buffer_pos_t h = rx_buffer.head,
120
-                            i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
119
+    // Get the tail - Nothing can alter its value while we are at this ISR
120
+    const ring_buffer_pos_t t = rx_buffer.tail;
121 121
 
122
-      // Read the character
123
-    const uint8_t c = HWUART->UART_RHR;
122
+    // Get the head pointer
123
+    ring_buffer_pos_t h = rx_buffer.head;
124
+
125
+    // Get the next element
126
+    ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
127
+
128
+    // Read the character from the USART
129
+    uint8_t c = HWUART->UART_RHR;
130
+
131
+    #if ENABLED(EMERGENCY_PARSER)
132
+      emergency_parser.update(emergency_state, c);
133
+    #endif
124 134
 
125 135
     // If the character is to be stored at the index just before the tail
126
-    // (such that the head would advance to the current tail), the buffer is
127
-    // critical, so don't write the character or advance the head.
128
-    if (i != rx_buffer.tail) {
136
+    // (such that the head would advance to the current tail), the RX FIFO is
137
+    // full, so don't write the character or advance the head.
138
+    if (i != t) {
129 139
       rx_buffer.buffer[h] = c;
130
-      rx_buffer.head = i;
140
+      h = i;
131 141
     }
132 142
     #if ENABLED(SERIAL_STATS_DROPPED_RX)
133
-      else if (!++rx_dropped_bytes) ++rx_dropped_bytes;
143
+      else if (!++rx_dropped_bytes) --rx_dropped_bytes;
134 144
     #endif
135 145
 
136 146
     #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
137
-      // calculate count of bytes stored into the RX buffer
138
-      ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
147
+      const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
148
+      // Calculate count of bytes stored into the RX buffer
149
+
139 150
       // Keep track of the maximum count of enqueued bytes
140 151
       NOLESS(rx_max_enqueued, rx_count);
141 152
     #endif
142 153
 
143 154
     #if ENABLED(SERIAL_XON_XOFF)
144
-
145
-      // for high speed transfers, we can use XON/XOFF protocol to do
146
-      // software handshake and avoid overruns.
155
+      // If the last char that was sent was an XON
147 156
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
148 157
 
149
-        // calculate count of bytes stored into the RX buffer
150
-        ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
158
+        // Bytes stored into the RX buffer
159
+        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
151 160
 
152
-        // if we are above 12.5% of RX buffer capacity, send XOFF before
153
-        // we run out of RX buffer space .. We need 325 bytes @ 250kbits/s to
154
-        // let the host react and stop sending bytes. This translates to 13mS
155
-        // propagation time.
161
+        // If over 12.5% of RX buffer capacity, send XOFF before running out of
162
+        // RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
163
+        // and stop sending bytes. This translates to 13mS propagation time.
156 164
         if (rx_count >= (RX_BUFFER_SIZE) / 8) {
157
-          
158
-          // If TX interrupts are disabled and data register is empty,
159
-          // just write the byte to the data register and be done. This
160
-          // shortcut helps significantly improve the effective datarate
161
-          // at high (>500kbit/s) bitrates, where interrupt overhead
162
-          // becomes a slowdown.
163
-          if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
164
-            
165
-            // Send an XOFF character
166
-            HWUART->UART_THR = XOFF_CHAR;
167
-
168
-            // And remember it was sent
169
-            xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
165
+
166
+          // At this point, definitely no TX interrupt was executing, since the TX isr can't be preempted.
167
+          // Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
168
+          // to be in the middle of trying to disable the RX interrupt in the main program, eventually the
169
+          // enabling of the TX interrupt could be undone. The ONLY reliable thing this can do to ensure
170
+          // the sending of the XOFF char is to send it HERE AND NOW.
171
+
172
+          // About to send the XOFF char
173
+          xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
174
+
175
+          // Wait until the TX register becomes empty and send it - Here there could be a problem
176
+          // - While waiting for the TX register to empty, the RX register could receive a new
177
+          //   character. This must also handle that situation!
178
+          uint32_t status;
179
+          while (!((status = HWUART->UART_SR) & UART_SR_TXRDY)) {
180
+
181
+            if (status & UART_SR_RXRDY) {
182
+              // We received a char while waiting for the TX buffer to be empty - Receive and process it!
183
+
184
+              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
185
+
186
+              // Read the character from the USART
187
+              c = HWUART->UART_RHR;
188
+
189
+              #if ENABLED(EMERGENCY_PARSER)
190
+                emergency_parser.update(emergency_state, c);
191
+              #endif
192
+
193
+              // If the character is to be stored at the index just before the tail
194
+              // (such that the head would advance to the current tail), the FIFO is
195
+              // full, so don't write the character or advance the head.
196
+              if (i != t) {
197
+                rx_buffer.buffer[h] = c;
198
+                h = i;
199
+              }
200
+              #if ENABLED(SERIAL_STATS_DROPPED_RX)
201
+                else if (!++rx_dropped_bytes) --rx_dropped_bytes;
202
+              #endif
203
+            }
204
+            sw_barrier();
170 205
           }
171
-          else {
172
-            // TX interrupts disabled, but buffer still not empty ... or
173
-            // TX interrupts enabled. Reenable TX ints and schedule XOFF
174
-            // character to be sent
175
-            #if TX_BUFFER_SIZE > 0
176
-              HWUART->UART_IER = UART_IER_TXRDY;
177
-              xon_xoff_state = XOFF_CHAR;
178
-            #else
179
-              // We are not using TX interrupts, we will have to send this manually
180
-              while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
181
-              HWUART->UART_THR = XOFF_CHAR;
182
-              
183
-              // And remember we already sent it
184
-              xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
185
-            #endif
206
+
207
+          HWUART->UART_THR = XOFF_CHAR;
208
+
209
+          // At this point there could be a race condition between the write() function
210
+          // and this sending of the XOFF char. This interrupt could happen between the
211
+          // wait to be empty TX buffer loop and the actual write of the character. Since
212
+          // the TX buffer is full because it's sending the XOFF char, the only way to be
213
+          // sure the write() function will succeed is to wait for the XOFF char to be
214
+          // completely sent. Since an extra character could be received during the wait
215
+          // it must also be handled!
216
+          while (!((status = HWUART->UART_SR) & UART_SR_TXRDY)) {
217
+
218
+            if (status & UART_SR_RXRDY) {
219
+              // A char arrived while waiting for the TX buffer to be empty - Receive and process it!
220
+
221
+              i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
222
+
223
+              // Read the character from the USART
224
+              c = HWUART->UART_RHR;
225
+
226
+              #if ENABLED(EMERGENCY_PARSER)
227
+                emergency_parser.update(emergency_state, c);
228
+              #endif
229
+
230
+              // If the character is to be stored at the index just before the tail
231
+              // (such that the head would advance to the current tail), the FIFO is
232
+              // full, so don't write the character or advance the head.
233
+              if (i != t) {
234
+                rx_buffer.buffer[h] = c;
235
+                h = i;
236
+              }
237
+              #if ENABLED(SERIAL_STATS_DROPPED_RX)
238
+                else if (!++rx_dropped_bytes) --rx_dropped_bytes;
239
+              #endif
240
+            }
241
+            sw_barrier();
186 242
           }
243
+
244
+          // At this point everything is ready. The write() function won't
245
+          // have any issues writing to the UART TX register if it needs to!
187 246
         }
188 247
       }
189 248
     #endif // SERIAL_XON_XOFF
190 249
 
191
-    #if ENABLED(EMERGENCY_PARSER)
192
-      emergency_parser.update(emergency_state, c);
193
-    #endif
250
+    // Store the new head value
251
+    rx_buffer.head = h;
194 252
   }
195 253
 
196 254
   #if TX_BUFFER_SIZE > 0
197 255
 
198 256
     FORCE_INLINE void _tx_thr_empty_irq(void) {
199
-      // If interrupts are enabled, there must be more data in the output
200
-      // buffer.
257
+      // Read positions
258
+      uint8_t t = tx_buffer.tail;
259
+      const uint8_t h = tx_buffer.head;
201 260
 
202 261
       #if ENABLED(SERIAL_XON_XOFF)
203
-        // Do a priority insertion of an XON/XOFF char, if needed.
204
-        const uint8_t state = xon_xoff_state;
205
-        if (!(state & XON_XOFF_CHAR_SENT)) {
206
-          HWUART->UART_THR = state & XON_XOFF_CHAR_MASK;
207
-          xon_xoff_state = state | XON_XOFF_CHAR_SENT;
262
+        // If an XON char is pending to be sent, do it now
263
+        if (xon_xoff_state == XON_CHAR) {
264
+
265
+          // Send the character
266
+          HWUART->UART_THR = XON_CHAR;
267
+
268
+          // Remember we sent it.
269
+          xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
270
+
271
+          // If nothing else to transmit, just disable TX interrupts.
272
+          if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY;
273
+
274
+          return;
208 275
         }
209
-        else
210 276
       #endif
211
-        { // Send the next byte
212
-          const uint8_t t = tx_buffer.tail, c = tx_buffer.buffer[t];
213
-          tx_buffer.tail = (t + 1) & (TX_BUFFER_SIZE - 1);
214
-          HWUART->UART_THR = c;
215
-        }
216 277
 
217
-      // Disable interrupts if the buffer is empty
218
-      if (tx_buffer.head == tx_buffer.tail)
278
+      // If nothing to transmit, just disable TX interrupts. This could
279
+      // happen as the result of the non atomicity of the disabling of RX
280
+      // interrupts that could end reenabling TX interrupts as a side effect.
281
+      if (h == t) {
219 282
         HWUART->UART_IDR = UART_IDR_TXRDY;
283
+        return;
284
+      }
285
+
286
+      // There is something to TX, Send the next byte
287
+      const uint8_t c = tx_buffer.buffer[t];
288
+      t = (t + 1) & (TX_BUFFER_SIZE - 1);
289
+      HWUART->UART_THR = c;
290
+      tx_buffer.tail = t;
291
+
292
+      // Disable interrupts if there is nothing to transmit following this byte
293
+      if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY;
220 294
     }
221 295
 
222 296
   #endif // TX_BUFFER_SIZE > 0
223 297
 
224 298
   static void UART_ISR(void) {
225
-    uint32_t status = HWUART->UART_SR;
299
+    const uint32_t status = HWUART->UART_SR;
226 300
 
227
-    // Did we receive data?
228
-    if (status & UART_SR_RXRDY)
229
-      store_rxd_char();
301
+    // Data received?
302
+    if (status & UART_SR_RXRDY) store_rxd_char();
230 303
 
231 304
     #if TX_BUFFER_SIZE > 0
232
-      // Do we have something to send, and TX interrupts are enabled (meaning something to send) ?
233
-      if ((status & UART_SR_TXRDY) && (HWUART->UART_IMR & UART_IMR_TXRDY))
234
-        _tx_thr_empty_irq();
305
+      // Something to send, and TX interrupts are enabled (meaning something to send)?
306
+      if ((status & UART_SR_TXRDY) && (HWUART->UART_IMR & UART_IMR_TXRDY)) _tx_thr_empty_irq();
235 307
     #endif
236 308
 
237 309
     // Acknowledge errors
@@ -312,36 +384,40 @@
312 384
   }
313 385
 
314 386
   int MarlinSerial::read(void) {
315
-    int v;
316
-    
387
+
317 388
     const ring_buffer_pos_t h = rx_buffer.head;
318 389
     ring_buffer_pos_t t = rx_buffer.tail;
319
-    
320
-    if (h == t)
321
-      v = -1;
322
-    else {
323
-      v = rx_buffer.buffer[t];
324
-      t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
325
-      
326
-      // Advance tail
327
-      rx_buffer.tail = t;
328 390
 
329
-      #if ENABLED(SERIAL_XON_XOFF)
330
-        if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
331
-          
332
-          // Get count of bytes in the RX buffer
333
-          ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
334
-          
335
-          // When below 10% of RX buffer capacity, send XON before
336
-          // running out of RX buffer bytes
337
-          if (rx_count < (RX_BUFFER_SIZE) / 10) {
391
+    if (h == t) return -1;
392
+
393
+    int v = rx_buffer.buffer[t];
394
+    t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
395
+
396
+    // Advance tail
397
+    rx_buffer.tail = t;
398
+
399
+    #if ENABLED(SERIAL_XON_XOFF)
400
+      // If the XOFF char was sent, or about to be sent...
401
+      if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
402
+        // Get count of bytes in the RX buffer
403
+        const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
404
+        // When below 10% of RX buffer capacity, send XON before running out of RX buffer bytes
405
+        if (rx_count < (RX_BUFFER_SIZE) / 10) {
406
+          #if TX_BUFFER_SIZE > 0
407
+            // Signal we want an XON character to be sent.
408
+            xon_xoff_state = XON_CHAR;
409
+            // Enable TX isr.
410
+            HWUART->UART_IER = UART_IER_TXRDY;
411
+          #else
412
+            // If not using TX interrupts, we must send the XON char now
338 413
             xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
339
-            write(XON_CHAR);
340
-            return v;
341
-          }
414
+            while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
415
+            HWUART->UART_THR = XON_CHAR;
416
+          #endif
342 417
         }
343
-      #endif
344
-    }
418
+      }
419
+    #endif
420
+
345 421
     return v;
346 422
   }
347 423
 
@@ -355,8 +431,17 @@
355 431
 
356 432
     #if ENABLED(SERIAL_XON_XOFF)
357 433
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
358
-        xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
359
-        write(XON_CHAR);
434
+        #if TX_BUFFER_SIZE > 0
435
+          // Signal we want an XON character to be sent.
436
+          xon_xoff_state = XON_CHAR;
437
+          // Enable TX isr.
438
+          HWUART->UART_IER = UART_IER_TXRDY;
439
+        #else
440
+          // If not using TX interrupts, we must send the XON char now
441
+          xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
442
+          while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
443
+          HWUART->UART_THR = XON_CHAR;
444
+        #endif
360 445
       }
361 446
     #endif
362 447
   }
@@ -364,72 +449,99 @@
364 449
   #if TX_BUFFER_SIZE > 0
365 450
     void MarlinSerial::write(const uint8_t c) {
366 451
       _written = true;
367
-      
368
-      // If the TX interrupts are disabled and the data register 
369
-      // is empty, just write the byte to the data register and 
370
-      // be done. This shortcut helps significantly improve the 
371
-      // effective datarate at high (>500kbit/s) bitrates, where 
452
+
453
+      // If the TX interrupts are disabled and the data register
454
+      // is empty, just write the byte to the data register and
455
+      // be done. This shortcut helps significantly improve the
456
+      // effective datarate at high (>500kbit/s) bitrates, where
372 457
       // interrupt overhead becomes a slowdown.
458
+      // Yes, there is a race condition between the sending of the
459
+      // XOFF char at the RX isr, but it is properly handled there
373 460
       if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
374 461
         HWUART->UART_THR = c;
375 462
         return;
376 463
       }
377
-      
464
+
378 465
       const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
379 466
 
380
-      // If the output buffer is full, there's nothing for it other than to
381
-      // wait for the interrupt handler to empty it a bit
382
-      while (i == tx_buffer.tail) {
383
-        if (!ISRS_ENABLED()) {
384
-          // Interrupts are disabled, so we'll have to poll the data
385
-          // register empty flag ourselves. If it is set, pretend an
386
-          // interrupt has happened and call the handler to free up
387
-          // space for us.
388
-          if (HWUART->UART_SR & UART_SR_TXRDY)
389
-            _tx_thr_empty_irq();
467
+      // If global interrupts are disabled (as the result of being called from an ISR)...
468
+      if (!ISRS_ENABLED()) {
469
+
470
+        // Make room by polling if it is possible to transmit, and do so!
471
+        while (i == tx_buffer.tail) {
472
+          // If we can transmit another byte, do it.
473
+          if (HWUART->UART_SR & UART_SR_TXRDY) _tx_thr_empty_irq();
474
+          // Make sure compiler rereads tx_buffer.tail
475
+          sw_barrier();
390 476
         }
391
-        // (else , the interrupt handler will free up space for us)
392
-        
393
-        // Make sure compiler rereads tx_buffer.tail
394
-        sw_barrier();
477
+      }
478
+      else {
479
+        // Interrupts are enabled, just wait until there is space
480
+        while (i == tx_buffer.tail) sw_barrier();
395 481
       }
396 482
 
483
+      // Store new char. head is always safe to move
397 484
       tx_buffer.buffer[tx_buffer.head] = c;
398 485
       tx_buffer.head = i;
399
-      
400
-      // Enable TX isr
486
+
487
+      // Enable TX isr - Non atomic, but it will eventually enable TX isr
401 488
       HWUART->UART_IER = UART_IER_TXRDY;
402
-      return;
403 489
     }
404 490
 
405 491
     void MarlinSerial::flushTX(void) {
406 492
       // TX
407
-      // If we have never written a byte, no need to flush.
493
+
494
+      // If we have never written a byte, no need to flush. This special
495
+      // case is needed since there is no way to force the TXC (transmit
496
+      // complete) bit to 1 during initialization
408 497
       if (!_written) return;
409 498
 
410
-      while ((HWUART->UART_IMR & UART_IMR_TXRDY) || !(HWUART->UART_SR & UART_SR_TXEMPTY)) {
411
-        if (!ISRS_ENABLED()) {
412
-          if (HWUART->UART_SR & UART_SR_TXRDY)
413
-            _tx_thr_empty_irq();
499
+      // If global interrupts are disabled (as the result of being called from an ISR)...
500
+      if (!ISRS_ENABLED()) {
501
+
502
+        // Wait until everything was transmitted - We must do polling, as interrupts are disabled
503
+        while (tx_buffer.head != tx_buffer.tail || !(HWUART->UART_SR & UART_SR_TXEMPTY)) {
504
+          // If there is more space, send an extra character
505
+          if (HWUART->UART_SR & UART_SR_TXRDY) _tx_thr_empty_irq();
506
+          sw_barrier();
414 507
         }
415
-        sw_barrier();
508
+
509
+      }
510
+      else {
511
+        // Wait until everything was transmitted
512
+        while (tx_buffer.head != tx_buffer.tail || !(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier();
416 513
       }
417
-      // If we get here, nothing is queued anymore (TX interrupts are disabled) and
418
-      // the hardware finished tranmission (TXEMPTY is set).
514
+
515
+      // At this point nothing is queued anymore (DRIE is disabled) and
516
+      // the hardware finished transmission (TXC is set).
419 517
     }
420 518
 
421 519
   #else // TX_BUFFER_SIZE == 0
422 520
 
423 521
     void MarlinSerial::write(const uint8_t c) {
522
+      _written = true;
424 523
       while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
425 524
       HWUART->UART_THR = c;
426 525
     }
427 526
 
527
+    void MarlinSerial::flushTX(void) {
528
+      // TX
529
+
530
+      // No bytes written, no need to flush. This special case is needed since there's
531
+      // no way to force the TXC (transmit complete) bit to 1 during initialization.
532
+      if (!_written) return;
533
+
534
+      // Wait until everything was transmitted
535
+      while (!(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier();
536
+
537
+      // At this point nothing is queued anymore (DRIE is disabled) and
538
+      // the hardware finished transmission (TXC is set).
539
+    }
428 540
   #endif // TX_BUFFER_SIZE == 0
429 541
 
430 542
   /**
431
-  * Imports from print.h
432
-  */
543
+   * Imports from print.h
544
+   */
433 545
 
434 546
   void MarlinSerial::print(char c, int base) {
435 547
     print((long)c, base);
@@ -448,13 +560,9 @@
448 560
   }
449 561
 
450 562
   void MarlinSerial::print(long n, int base) {
451
-    if (base == 0)
452
-      write(n);
563
+    if (base == 0) write(n);
453 564
     else if (base == 10) {
454
-      if (n < 0) {
455
-        print('-');
456
-        n = -n;
457
-      }
565
+      if (n < 0) { print('-'); n = -n; }
458 566
       printNumber(n, 10);
459 567
     }
460 568
     else
@@ -546,9 +654,7 @@
546 654
 
547 655
     // Round correctly so that print(1.999, 2) prints as "2.00"
548 656
     double rounding = 0.5;
549
-    for (uint8_t i = 0; i < digits; ++i)
550
-      rounding *= 0.1;
551
-
657
+    for (uint8_t i = 0; i < digits; ++i) rounding *= 0.1;
552 658
     number += rounding;
553 659
 
554 660
     // Extract the integer part of the number and print it

+ 1
- 3
Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h Voir le fichier

@@ -85,9 +85,7 @@ public:
85 85
   static void flush(void);
86 86
   static ring_buffer_pos_t available(void);
87 87
   static void write(const uint8_t c);
88
-  #if TX_BUFFER_SIZE > 0
89
-    static void flushTX(void);
90
-  #endif
88
+  static void flushTX(void);
91 89
 
92 90
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
93 91
     FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; }

Chargement…
Annuler
Enregistrer