Browse Source

Fix XON/XOFF implementation

Pointed out by @GMagician
etagle 6 years ago
parent
commit
d90e8fcad9

+ 261
- 158
Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp View File

56
     ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
56
     ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
57
     #if TX_BUFFER_SIZE > 0
57
     #if TX_BUFFER_SIZE > 0
58
       ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
58
       ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
59
-      static bool _written;
60
     #endif
59
     #endif
60
+    static bool _written;
61
   #endif
61
   #endif
62
 
62
 
63
   #if ENABLED(SERIAL_XON_XOFF)
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
     // XON / XOFF character definitions
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
     uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR;
68
     uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR;
70
   #endif
69
   #endif
71
 
70
 
91
       static EmergencyParser::State emergency_state; // = EP_RESET
90
       static EmergencyParser::State emergency_state; // = EP_RESET
92
     #endif
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
     // If the character is to be stored at the index just before the tail
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
       rx_buffer.buffer[h] = c;
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
     #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
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
       // Keep track of the maximum count of enqueued bytes
124
       // Keep track of the maximum count of enqueued bytes
117
       NOLESS(rx_max_enqueued, rx_count);
125
       NOLESS(rx_max_enqueued, rx_count);
118
     #endif
126
     #endif
119
 
127
 
120
     #if ENABLED(SERIAL_XON_XOFF)
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
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
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
         if (rx_count >= (RX_BUFFER_SIZE) / 8) {
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
     #endif // SERIAL_XON_XOFF
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
   #if TX_BUFFER_SIZE > 0
232
   #if TX_BUFFER_SIZE > 0
184
 
233
 
185
     // (called with TX irqs disabled)
234
     // (called with TX irqs disabled)
186
     FORCE_INLINE void _tx_udr_empty_irq(void) {
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
       #if ENABLED(SERIAL_XON_XOFF)
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
       #endif
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
       SBI(M_UCSRxA, M_TXCx);
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
     #ifdef M_USARTx_UDRE_vect
285
     #ifdef M_USARTx_UDRE_vect
253
     SBI(M_UCSRxB, M_RXCIEx);
323
     SBI(M_UCSRxB, M_RXCIEx);
254
     #if TX_BUFFER_SIZE > 0
324
     #if TX_BUFFER_SIZE > 0
255
       CBI(M_UCSRxB, M_UDRIEx);
325
       CBI(M_UCSRxB, M_UDRIEx);
256
-      _written = false;
257
     #endif
326
     #endif
327
+    _written = false;
258
   }
328
   }
259
 
329
 
260
   void MarlinSerial::end() {
330
   void MarlinSerial::end() {
281
   }
351
   }
282
 
352
 
283
   int MarlinSerial::read(void) {
353
   int MarlinSerial::read(void) {
284
-    int v;
285
 
354
 
286
     #if RX_BUFFER_SIZE > 256
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
       CBI(M_UCSRxB, M_RXCIEx);
359
       CBI(M_UCSRxB, M_RXCIEx);
290
     #endif
360
     #endif
291
 
361
 
298
 
368
 
299
     ring_buffer_pos_t t = rx_buffer.tail;
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
             xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
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
     return v;
416
     return v;
340
   }
417
   }
367
     #endif
444
     #endif
368
 
445
 
369
     #if ENABLED(SERIAL_XON_XOFF)
446
     #if ENABLED(SERIAL_XON_XOFF)
447
+      // If the XOFF char was sent, or about to be sent...
370
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
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
     #endif
461
     #endif
375
   }
462
   }
383
       // be done. This shortcut helps significantly improve the
470
       // be done. This shortcut helps significantly improve the
384
       // effective datarate at high (>500kbit/s) bitrates, where
471
       // effective datarate at high (>500kbit/s) bitrates, where
385
       // interrupt overhead becomes a slowdown.
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
       if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) {
475
       if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) {
387
         M_UDRx = c;
476
         M_UDRx = c;
388
 
477
 
395
 
484
 
396
       const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
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
       // Store new char. head is always safe to move
505
       // Store new char. head is always safe to move
416
       tx_buffer.buffer[tx_buffer.head] = c;
506
       tx_buffer.buffer[tx_buffer.head] = c;
417
       tx_buffer.head = i;
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
       SBI(M_UCSRxB, M_UDRIEx);
510
       SBI(M_UCSRxB, M_UDRIEx);
421
-      return;
422
     }
511
     }
423
 
512
 
424
     void MarlinSerial::flushTX(void) {
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
           if (TEST(M_UCSRxA, M_UDREx))
525
           if (TEST(M_UCSRxA, M_UDREx))
438
             _tx_udr_empty_irq();
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
       // the hardware finished transmission (TXC is set).
538
       // the hardware finished transmission (TXC is set).
444
     }
539
     }
445
 
540
 
446
   #else // TX_BUFFER_SIZE == 0
541
   #else // TX_BUFFER_SIZE == 0
447
 
542
 
448
     void MarlinSerial::write(const uint8_t c) {
543
     void MarlinSerial::write(const uint8_t c) {
544
+      _written = true;
449
       while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
545
       while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
450
       M_UDRx = c;
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
   #endif // TX_BUFFER_SIZE == 0
560
   #endif // TX_BUFFER_SIZE == 0
454
 
561
 
455
   /**
562
   /**
473
   }
580
   }
474
 
581
 
475
   void MarlinSerial::print(long n, int base) {
582
   void MarlinSerial::print(long n, int base) {
476
-    if (base == 0)
477
-      write(n);
583
+    if (base == 0) write(n);
478
     else if (base == 10) {
584
     else if (base == 10) {
479
-      if (n < 0) {
480
-        print('-');
481
-        n = -n;
482
-      }
585
+      if (n < 0) { print('-'); n = -n; }
483
       printNumber(n, 10);
586
       printNumber(n, 10);
484
     }
587
     }
485
     else
588
     else

+ 6
- 7
Marlin/src/HAL/HAL_AVR/MarlinSerial.h View File

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

+ 253
- 147
Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp View File

74
   ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
74
   ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
75
   #if TX_BUFFER_SIZE > 0
75
   #if TX_BUFFER_SIZE > 0
76
     ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
76
     ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
77
-    static bool _written;
78
   #endif
77
   #endif
78
+  static bool _written;
79
 
79
 
80
   #if ENABLED(SERIAL_XON_XOFF)
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
     // XON / XOFF character definitions
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
     uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR;
85
     uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR;
87
 
86
 
88
     // Validate that RX buffer size is at least 4096 bytes- According to several experiments, on
87
     // Validate that RX buffer size is at least 4096 bytes- According to several experiments, on
110
     #include "../../feature/emergency_parser.h"
109
     #include "../../feature/emergency_parser.h"
111
   #endif
110
   #endif
112
 
111
 
112
+  // (called with RX interrupts disabled)
113
   FORCE_INLINE void store_rxd_char() {
113
   FORCE_INLINE void store_rxd_char() {
114
 
114
 
115
     #if ENABLED(EMERGENCY_PARSER)
115
     #if ENABLED(EMERGENCY_PARSER)
116
       static EmergencyParser::State emergency_state; // = EP_RESET
116
       static EmergencyParser::State emergency_state; // = EP_RESET
117
     #endif
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
     // If the character is to be stored at the index just before the tail
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
       rx_buffer.buffer[h] = c;
139
       rx_buffer.buffer[h] = c;
130
-      rx_buffer.head = i;
140
+      h = i;
131
     }
141
     }
132
     #if ENABLED(SERIAL_STATS_DROPPED_RX)
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
     #endif
144
     #endif
135
 
145
 
136
     #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
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
       // Keep track of the maximum count of enqueued bytes
150
       // Keep track of the maximum count of enqueued bytes
140
       NOLESS(rx_max_enqueued, rx_count);
151
       NOLESS(rx_max_enqueued, rx_count);
141
     #endif
152
     #endif
142
 
153
 
143
     #if ENABLED(SERIAL_XON_XOFF)
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
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
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
         if (rx_count >= (RX_BUFFER_SIZE) / 8) {
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
     #endif // SERIAL_XON_XOFF
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
   #if TX_BUFFER_SIZE > 0
254
   #if TX_BUFFER_SIZE > 0
197
 
255
 
198
     FORCE_INLINE void _tx_thr_empty_irq(void) {
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
       #if ENABLED(SERIAL_XON_XOFF)
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
       #endif
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
         HWUART->UART_IDR = UART_IDR_TXRDY;
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
   #endif // TX_BUFFER_SIZE > 0
296
   #endif // TX_BUFFER_SIZE > 0
223
 
297
 
224
   static void UART_ISR(void) {
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
     #if TX_BUFFER_SIZE > 0
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
     #endif
307
     #endif
236
 
308
 
237
     // Acknowledge errors
309
     // Acknowledge errors
312
   }
384
   }
313
 
385
 
314
   int MarlinSerial::read(void) {
386
   int MarlinSerial::read(void) {
315
-    int v;
316
-    
387
+
317
     const ring_buffer_pos_t h = rx_buffer.head;
388
     const ring_buffer_pos_t h = rx_buffer.head;
318
     ring_buffer_pos_t t = rx_buffer.tail;
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
             xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
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
     return v;
421
     return v;
346
   }
422
   }
347
 
423
 
355
 
431
 
356
     #if ENABLED(SERIAL_XON_XOFF)
432
     #if ENABLED(SERIAL_XON_XOFF)
357
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
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
     #endif
446
     #endif
362
   }
447
   }
364
   #if TX_BUFFER_SIZE > 0
449
   #if TX_BUFFER_SIZE > 0
365
     void MarlinSerial::write(const uint8_t c) {
450
     void MarlinSerial::write(const uint8_t c) {
366
       _written = true;
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
       // interrupt overhead becomes a slowdown.
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
       if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
460
       if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
374
         HWUART->UART_THR = c;
461
         HWUART->UART_THR = c;
375
         return;
462
         return;
376
       }
463
       }
377
-      
464
+
378
       const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
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
       tx_buffer.buffer[tx_buffer.head] = c;
484
       tx_buffer.buffer[tx_buffer.head] = c;
398
       tx_buffer.head = i;
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
       HWUART->UART_IER = UART_IER_TXRDY;
488
       HWUART->UART_IER = UART_IER_TXRDY;
402
-      return;
403
     }
489
     }
404
 
490
 
405
     void MarlinSerial::flushTX(void) {
491
     void MarlinSerial::flushTX(void) {
406
       // TX
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
       if (!_written) return;
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
   #else // TX_BUFFER_SIZE == 0
519
   #else // TX_BUFFER_SIZE == 0
422
 
520
 
423
     void MarlinSerial::write(const uint8_t c) {
521
     void MarlinSerial::write(const uint8_t c) {
522
+      _written = true;
424
       while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
523
       while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
425
       HWUART->UART_THR = c;
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
   #endif // TX_BUFFER_SIZE == 0
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
   void MarlinSerial::print(char c, int base) {
546
   void MarlinSerial::print(char c, int base) {
435
     print((long)c, base);
547
     print((long)c, base);
448
   }
560
   }
449
 
561
 
450
   void MarlinSerial::print(long n, int base) {
562
   void MarlinSerial::print(long n, int base) {
451
-    if (base == 0)
452
-      write(n);
563
+    if (base == 0) write(n);
453
     else if (base == 10) {
564
     else if (base == 10) {
454
-      if (n < 0) {
455
-        print('-');
456
-        n = -n;
457
-      }
565
+      if (n < 0) { print('-'); n = -n; }
458
       printNumber(n, 10);
566
       printNumber(n, 10);
459
     }
567
     }
460
     else
568
     else
546
 
654
 
547
     // Round correctly so that print(1.999, 2) prints as "2.00"
655
     // Round correctly so that print(1.999, 2) prints as "2.00"
548
     double rounding = 0.5;
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
     number += rounding;
658
     number += rounding;
553
 
659
 
554
     // Extract the integer part of the number and print it
660
     // Extract the integer part of the number and print it

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

85
   static void flush(void);
85
   static void flush(void);
86
   static ring_buffer_pos_t available(void);
86
   static ring_buffer_pos_t available(void);
87
   static void write(const uint8_t c);
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
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
90
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
93
     FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; }
91
     FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; }

Loading…
Cancel
Save