Browse Source

Merge pull request #2994 from AnHardt/Inerrup-save-serial

Interrupt safe serial --- Guard against non-atomic variable changes from interrupt routines
Scott Lahteine 9 years ago
parent
commit
f5972c4d2c
2 changed files with 67 additions and 36 deletions
  1. 33
    20
      Marlin/MarlinSerial.cpp
  2. 34
    16
      Marlin/MarlinSerial.h

+ 33
- 20
Marlin/MarlinSerial.cpp View File

33
 #endif
33
 #endif
34
 
34
 
35
 FORCE_INLINE void store_char(unsigned char c) {
35
 FORCE_INLINE void store_char(unsigned char c) {
36
-  int i = (unsigned int)(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
 
104
 
102
 
105
 
103
 int MarlinSerial::peek(void) {
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
   else {
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
 int MarlinSerial::read(void) {
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
   else {
127
   else {
118
-    unsigned char c = rx_buffer.buffer[rx_buffer.tail];
119
-    rx_buffer.tail = (unsigned int)(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
 void MarlinSerial::flush() {
135
 void MarlinSerial::flush() {
131
   // the value to rx_buffer_tail; the previous value of rx_buffer_head
142
   // the value to rx_buffer_tail; the previous value of rx_buffer_head
132
   // may be written to rx_buffer_tail, making it appear as if the buffer
143
   // may be written to rx_buffer_tail, making it appear as if the buffer
133
   // were full, not empty.
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
 

+ 34
- 16
Marlin/MarlinSerial.h View File

23
 #define MarlinSerial_h
23
 #define MarlinSerial_h
24
 #include "Marlin.h"
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
 #ifndef SERIAL_PORT
32
 #ifndef SERIAL_PORT
27
   #define SERIAL_PORT 0
33
   #define SERIAL_PORT 0
28
 #endif
34
 #endif
69
 // using a ring buffer (I think), in which rx_buffer_head is the index of the
75
 // using a ring buffer (I think), in which rx_buffer_head is the index of the
70
 // location to which to write the next incoming character and rx_buffer_tail
76
 // location to which to write the next incoming character and rx_buffer_tail
71
 // is the index of the location from which to read.
77
 // is the index of the location from which to read.
72
-#define RX_BUFFER_SIZE 128
73
-
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
74
 
85
 
75
 struct ring_buffer {
86
 struct ring_buffer {
76
   unsigned char buffer[RX_BUFFER_SIZE];
87
   unsigned char buffer[RX_BUFFER_SIZE];
77
-  int head;
78
-  int tail;
88
+  volatile uint8_t head;
89
+  volatile uint8_t tail;
79
 };
90
 };
80
 
91
 
81
 #if UART_PRESENT(SERIAL_PORT)
92
 #if UART_PRESENT(SERIAL_PORT)
92
     int read(void);
103
     int read(void);
93
     void flush(void);
104
     void flush(void);
94
 
105
 
95
-    FORCE_INLINE int available(void) {
96
-      return (unsigned int)(RX_BUFFER_SIZE + rx_buffer.head - rx_buffer.tail) % RX_BUFFER_SIZE;
106
+    FORCE_INLINE uint8_t available(void) {
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);
97
     }
112
     }
98
 
113
 
99
     FORCE_INLINE void write(uint8_t c) {
114
     FORCE_INLINE void write(uint8_t c) {
105
     FORCE_INLINE void checkRx(void) {
120
     FORCE_INLINE void checkRx(void) {
106
       if (TEST(M_UCSRxA, M_RXCx)) {
121
       if (TEST(M_UCSRxA, M_RXCx)) {
107
         unsigned char c  =  M_UDRx;
122
         unsigned char c  =  M_UDRx;
108
-        int i = (unsigned int)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
109
-
110
-        // if we should be storing the received character into the location
111
-        // just before the tail (meaning that the head would advance to the
112
-        // current location of the tail), we're about to overflow the buffer
113
-        // and so we don't write the character or advance the head.
114
-        if (i != rx_buffer.tail) {
115
-          rx_buffer.buffer[rx_buffer.head] = c;
116
-          rx_buffer.head = i;
117
-        }
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;
118
       }
136
       }
119
     }
137
     }
120
 
138
 

Loading…
Cancel
Save