Browse Source

Protect MarlinSerial against interrupts

Protect MarlinSerial against interrupts
by shielding the CRITICAL_SECTIONs

Now with a test if RX_BUFFER_SIZE is in the required range.
Code in peek() and read() is now optimized for readability and showing the similarity between the two.

Maybe a bit overprotected in checkRx() and store_char(), but now some days without detected errors from this source.
AnHardt 8 years ago
parent
commit
cb88fdd242
2 changed files with 64 additions and 34 deletions
  1. 33
    20
      Marlin/MarlinSerial.cpp
  2. 31
    14
      Marlin/MarlinSerial.h

+ 33
- 20
Marlin/MarlinSerial.cpp View File

@@ -33,16 +33,19 @@
33 33
 #endif
34 34
 
35 35
 FORCE_INLINE void store_char(unsigned char c) {
36
-  uint8_t i = (uint8_t)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
37
-
38
-  // if we should be storing the received character into the location
39
-  // just before the tail (meaning that the head would advance to the
40
-  // current location of the tail), we're about to overflow the buffer
41
-  // and so we don't write the character or advance the head.
42
-  if (i != rx_buffer.tail) {
43
-    rx_buffer.buffer[rx_buffer.head] = c;
44
-    rx_buffer.head = i;
45
-  }
36
+  CRITICAL_SECTION_START;
37
+    uint8_t h = rx_buffer.head;
38
+    uint8_t i = (uint8_t)(h + 1)  & (RX_BUFFER_SIZE - 1);
39
+
40
+    // if we should be storing the received character into the location
41
+    // just before the tail (meaning that the head would advance to the
42
+    // current location of the tail), we're about to overflow the buffer
43
+    // and so we don't write the character or advance the head.
44
+    if (i != rx_buffer.tail) {
45
+      rx_buffer.buffer[h] = c;
46
+      rx_buffer.head = i;
47
+    }
48
+  CRITICAL_SECTION_END;
46 49
 }
47 50
 
48 51
 
@@ -101,24 +104,32 @@ void MarlinSerial::end() {
101 104
 
102 105
 
103 106
 int MarlinSerial::peek(void) {
104
-  if (rx_buffer.head == rx_buffer.tail) {
105
-    return -1;
107
+  int v;
108
+  CRITICAL_SECTION_START;
109
+  uint8_t t = rx_buffer.tail;
110
+  if (rx_buffer.head == t) {
111
+    v = -1;
106 112
   }
107 113
   else {
108
-    return rx_buffer.buffer[rx_buffer.tail];
114
+    v = rx_buffer.buffer[t];
109 115
   }
116
+  CRITICAL_SECTION_END;
117
+  return v;
110 118
 }
111 119
 
112 120
 int MarlinSerial::read(void) {
113
-  // if the head isn't ahead of the tail, we don't have any characters
114
-  if (rx_buffer.head == rx_buffer.tail) {
115
-    return -1;
121
+  int v;
122
+  CRITICAL_SECTION_START;
123
+  uint8_t t = rx_buffer.tail;
124
+  if (rx_buffer.head == t) {
125
+    v = -1;
116 126
   }
117 127
   else {
118
-    unsigned char c = rx_buffer.buffer[rx_buffer.tail];
119
-    rx_buffer.tail = (uint8_t)(rx_buffer.tail + 1) % RX_BUFFER_SIZE;
120
-    return c;
128
+    v = rx_buffer.buffer[t];
129
+    rx_buffer.tail = (uint8_t)(t + 1) & (RX_BUFFER_SIZE - 1);
121 130
   }
131
+  CRITICAL_SECTION_END;
132
+  return v;
122 133
 }
123 134
 
124 135
 void MarlinSerial::flush() {
@@ -131,7 +142,9 @@ void MarlinSerial::flush() {
131 142
   // the value to rx_buffer_tail; the previous value of rx_buffer_head
132 143
   // may be written to rx_buffer_tail, making it appear as if the buffer
133 144
   // were full, not empty.
134
-  rx_buffer.head = rx_buffer.tail;
145
+  CRITICAL_SECTION_START;
146
+    rx_buffer.head = rx_buffer.tail;
147
+  CRITICAL_SECTION_END;
135 148
 }
136 149
 
137 150
 

+ 31
- 14
Marlin/MarlinSerial.h View File

@@ -23,6 +23,12 @@
23 23
 #define MarlinSerial_h
24 24
 #include "Marlin.h"
25 25
 
26
+#ifndef CRITICAL_SECTION_START
27
+  #define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli();
28
+  #define CRITICAL_SECTION_END    SREG = _sreg;
29
+#endif
30
+
31
+
26 32
 #ifndef SERIAL_PORT
27 33
   #define SERIAL_PORT 0
28 34
 #endif
@@ -69,9 +75,13 @@
69 75
 // using a ring buffer (I think), in which rx_buffer_head is the index of the
70 76
 // location to which to write the next incoming character and rx_buffer_tail
71 77
 // is the index of the location from which to read.
72
-// 256 is the max limit due to uint8_t head and tail. Thats needed to make them atomic.
73
-#define RX_BUFFER_SIZE 128
74
-
78
+// 256 is the max limit due to uint8_t head and tail. Use only powers of 2. (...,16,32,64,128,256)
79
+#ifndef RX_BUFFER_SIZE
80
+  #define RX_BUFFER_SIZE 128
81
+#endif
82
+#if !((RX_BUFFER_SIZE == 256) ||(RX_BUFFER_SIZE == 128) ||(RX_BUFFER_SIZE == 64) ||(RX_BUFFER_SIZE == 32) ||(RX_BUFFER_SIZE == 16) ||(RX_BUFFER_SIZE == 8) ||(RX_BUFFER_SIZE == 4) ||(RX_BUFFER_SIZE == 2))
83
+  #error RX_BUFFER_SIZE has to be a power of 2 and >= 2
84
+#endif
75 85
 
76 86
 struct ring_buffer {
77 87
   unsigned char buffer[RX_BUFFER_SIZE];
@@ -94,7 +104,11 @@ class MarlinSerial { //: public Stream
94 104
     void flush(void);
95 105
 
96 106
     FORCE_INLINE uint8_t available(void) {
97
-      return (uint8_t)(RX_BUFFER_SIZE + rx_buffer.head - rx_buffer.tail) % RX_BUFFER_SIZE;
107
+      CRITICAL_SECTION_START;
108
+        uint8_t h = rx_buffer.head;
109
+        uint8_t t = rx_buffer.tail;
110
+      CRITICAL_SECTION_END;
111
+      return (uint8_t)(RX_BUFFER_SIZE + h - t) & (RX_BUFFER_SIZE - 1);
98 112
     }
99 113
 
100 114
     FORCE_INLINE void write(uint8_t c) {
@@ -106,16 +120,19 @@ class MarlinSerial { //: public Stream
106 120
     FORCE_INLINE void checkRx(void) {
107 121
       if (TEST(M_UCSRxA, M_RXCx)) {
108 122
         unsigned char c  =  M_UDRx;
109
-        uint8_t i = (uint8_t)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
110
-
111
-        // if we should be storing the received character into the location
112
-        // just before the tail (meaning that the head would advance to the
113
-        // current location of the tail), we're about to overflow the buffer
114
-        // and so we don't write the character or advance the head.
115
-        if (i != rx_buffer.tail) {
116
-          rx_buffer.buffer[rx_buffer.head] = c;
117
-          rx_buffer.head = i;
118
-        }
123
+        CRITICAL_SECTION_START;
124
+          uint8_t h = rx_buffer.head;
125
+          uint8_t i = (uint8_t)(h + 1) & (RX_BUFFER_SIZE - 1);
126
+
127
+          // if we should be storing the received character into the location
128
+          // just before the tail (meaning that the head would advance to the
129
+          // current location of the tail), we're about to overflow the buffer
130
+          // and so we don't write the character or advance the head.
131
+          if (i != rx_buffer.tail) {
132
+            rx_buffer.buffer[h] = c;
133
+            rx_buffer.head = i;
134
+          }
135
+        CRITICAL_SECTION_END;
119 136
       }
120 137
     }
121 138
 

Loading…
Cancel
Save