|
11 | 11 | * |
12 | 12 | * @file |
13 | 13 | * @author Martine Lenders <[email protected]> |
| 14 | + * @author Benjamin Valentin <[email protected]> |
14 | 15 | */ |
15 | 16 |
|
16 | 17 | #include <assert.h> |
@@ -52,27 +53,89 @@ static void _slip_rx_cb(void *arg, uint8_t byte) |
52 | 53 | { |
53 | 54 | slipdev_t *dev = arg; |
54 | 55 |
|
55 | | - if (IS_USED(MODULE_SLIPDEV_STDIO)) { |
56 | | - if (dev->state == SLIPDEV_STATE_STDIN) { |
| 56 | + switch (dev->state) { |
| 57 | +#if IS_USED(MODULE_SLIPDEV_STDIO) |
| 58 | + case SLIPDEV_STATE_STDIN: |
| 59 | + switch (byte) { |
| 60 | + case SLIPDEV_ESC: |
| 61 | + dev->state = SLIPDEV_STATE_STDIN_ESC; |
| 62 | + break; |
| 63 | + case SLIPDEV_END: |
| 64 | + dev->state = SLIPDEV_STATE_NONE; |
| 65 | + byte = 0; |
| 66 | + /* fall-through */ |
| 67 | + default: |
57 | 68 | isrpipe_write_one(&slipdev_stdio_isrpipe, byte); |
58 | | - goto check_end; |
| 69 | + break; |
59 | 70 | } |
60 | | - else if ((byte == SLIPDEV_STDIO_START) && |
61 | | - (dev->config.uart == STDIO_UART_DEV) && |
62 | | - (dev->state == SLIPDEV_STATE_NONE)) { |
| 71 | + return; |
| 72 | + case SLIPDEV_STATE_STDIN_ESC: |
| 73 | + switch (byte) { |
| 74 | + case SLIPDEV_END_ESC: |
| 75 | + byte = SLIPDEV_END; |
| 76 | + break; |
| 77 | + case SLIPDEV_ESC_ESC: |
| 78 | + byte = SLIPDEV_ESC; |
| 79 | + break; |
| 80 | + } |
| 81 | + dev->state = SLIPDEV_STATE_STDIN; |
| 82 | + isrpipe_write_one(&slipdev_stdio_isrpipe, byte); |
| 83 | + return; |
| 84 | +#endif |
| 85 | + case SLIPDEV_STATE_NONE: |
| 86 | + /* is diagnostic frame? */ |
| 87 | + if (IS_USED(MODULE_SLIPDEV_STDIO) && |
| 88 | + (byte == SLIPDEV_STDIO_START) && |
| 89 | + (dev->config.uart == STDIO_UART_DEV)) { |
63 | 90 | dev->state = SLIPDEV_STATE_STDIN; |
64 | 91 | return; |
65 | 92 | } |
66 | | - } |
67 | | - dev->state = SLIPDEV_STATE_NET; |
68 | | - tsrb_add_one(&dev->inbuf, byte); |
69 | | -check_end: |
70 | | - if (byte == SLIPDEV_END) { |
71 | | - if (dev->state == SLIPDEV_STATE_NET) { |
72 | | - dev->rx_queued++; |
| 93 | + |
| 94 | + /* ignore empty frame */ |
| 95 | + if (byte == SLIPDEV_END) { |
| 96 | + return; |
| 97 | + } |
| 98 | + |
| 99 | + /* try to create new frame */ |
| 100 | + if (!crb_start_chunk(&dev->rb)) { |
| 101 | + return; |
| 102 | + } |
| 103 | + dev->state = SLIPDEV_STATE_NET; |
| 104 | + /* fall-through */ |
| 105 | + case SLIPDEV_STATE_NET: |
| 106 | + switch (byte) { |
| 107 | + case SLIPDEV_ESC: |
| 108 | + dev->state = SLIPDEV_STATE_NET_ESC; |
| 109 | + return; |
| 110 | + case SLIPDEV_END: |
| 111 | + crb_end_chunk(&dev->rb, true); |
73 | 112 | netdev_trigger_event_isr(&dev->netdev); |
| 113 | + dev->state = SLIPDEV_STATE_NONE; |
| 114 | + return; |
74 | 115 | } |
| 116 | + break; |
| 117 | + /* escaped byte received */ |
| 118 | + case SLIPDEV_STATE_NET_ESC: |
| 119 | + switch (byte) { |
| 120 | + case SLIPDEV_END_ESC: |
| 121 | + byte = SLIPDEV_END; |
| 122 | + break; |
| 123 | + case SLIPDEV_ESC_ESC: |
| 124 | + byte = SLIPDEV_ESC; |
| 125 | + break; |
| 126 | + } |
| 127 | + dev->state = SLIPDEV_STATE_NET; |
| 128 | + break; |
| 129 | + } |
| 130 | + |
| 131 | + assert(dev->state == SLIPDEV_STATE_NET); |
| 132 | + |
| 133 | + /* discard frame if byte can't be added */ |
| 134 | + if (!crb_add_byte(&dev->rb, byte)) { |
| 135 | + DEBUG("slipdev: rx buffer full, drop frame\n"); |
| 136 | + crb_end_chunk(&dev->rb, false); |
75 | 137 | dev->state = SLIPDEV_STATE_NONE; |
| 138 | + return; |
76 | 139 | } |
77 | 140 | } |
78 | 141 |
|
@@ -100,7 +163,7 @@ static int _init(netdev_t *netdev) |
100 | 163 | DEBUG("slipdev: initializing device %p on UART %i with baudrate %" PRIu32 "\n", |
101 | 164 | (void *)dev, dev->config.uart, dev->config.baudrate); |
102 | 165 | /* initialize buffers */ |
103 | | - tsrb_init(&dev->inbuf, dev->rxmem, sizeof(dev->rxmem)); |
| 166 | + crb_init(&dev->rb, dev->rxmem, sizeof(dev->rxmem)); |
104 | 167 | if (uart_init(dev->config.uart, dev->config.baudrate, _slip_rx_cb, |
105 | 168 | dev) != UART_OK) { |
106 | 169 | LOG_ERROR("slipdev: error initializing UART %i with baudrate %" PRIu32 "\n", |
@@ -134,41 +197,6 @@ void slipdev_write_bytes(uart_t uart, const uint8_t *data, size_t len) |
134 | 197 | } |
135 | 198 | } |
136 | 199 |
|
137 | | -static unsigned _copy_byte(uint8_t *buf, uint8_t byte, bool *escaped) |
138 | | -{ |
139 | | - *buf = byte; |
140 | | - *escaped = false; |
141 | | - return 1U; |
142 | | -} |
143 | | - |
144 | | -unsigned slipdev_unstuff_readbyte(uint8_t *buf, uint8_t byte, bool *escaped) |
145 | | -{ |
146 | | - unsigned res = 0U; |
147 | | - |
148 | | - switch (byte) { |
149 | | - case SLIPDEV_ESC: |
150 | | - *escaped = true; |
151 | | - /* Intentionally falls through */ |
152 | | - case SLIPDEV_END: |
153 | | - break; |
154 | | - case SLIPDEV_END_ESC: |
155 | | - if (*escaped) { |
156 | | - return _copy_byte(buf, SLIPDEV_END, escaped); |
157 | | - } |
158 | | - /* Intentionally falls through */ |
159 | | - /* to default when !(*escaped) */ |
160 | | - case SLIPDEV_ESC_ESC: |
161 | | - if (*escaped) { |
162 | | - return _copy_byte(buf, SLIPDEV_ESC, escaped); |
163 | | - } |
164 | | - /* Intentionally falls through */ |
165 | | - /* to default when !(*escaped) */ |
166 | | - default: |
167 | | - return _copy_byte(buf, byte, escaped); |
168 | | - } |
169 | | - return res; |
170 | | -} |
171 | | - |
172 | 200 | static int _check_state(slipdev_t *dev) |
173 | 201 | { |
174 | 202 | /* power states not supported when multiplexing stdio */ |
@@ -212,64 +240,33 @@ static int _send(netdev_t *netdev, const iolist_t *iolist) |
212 | 240 | static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) |
213 | 241 | { |
214 | 242 | slipdev_t *dev = (slipdev_t *)netdev; |
215 | | - int res = 0; |
| 243 | + size_t res = 0; |
216 | 244 |
|
217 | 245 | (void)info; |
218 | 246 | if (buf == NULL) { |
219 | 247 | if (len > 0) { |
220 | 248 | /* remove data */ |
221 | | - for (; len > 0; len--) { |
222 | | - int byte = tsrb_get_one(&dev->inbuf); |
223 | | - if ((byte == (int)SLIPDEV_END) || (byte < 0)) { |
224 | | - /* end early if end of packet or ringbuffer is reached; |
225 | | - * len might be larger than the actual packet */ |
226 | | - break; |
227 | | - } |
228 | | - } |
| 249 | + crb_consume_chunk(&dev->rb, NULL, len); |
229 | 250 | } else { |
230 | 251 | /* the user was warned not to use a buffer size > `INT_MAX` ;-) */ |
231 | | - res = (int)tsrb_avail(&dev->inbuf); |
| 252 | + crb_get_chunk_size(&dev->rb, &res); |
232 | 253 | } |
233 | 254 | } |
234 | 255 | else { |
235 | | - int byte; |
236 | | - bool escaped = false; |
237 | | - uint8_t *ptr = buf; |
238 | | - |
239 | | - do { |
240 | | - int tmp; |
241 | | - |
242 | | - if ((byte = tsrb_get_one(&dev->inbuf)) < 0) { |
243 | | - /* something went wrong, return error */ |
244 | | - return -EIO; |
245 | | - } |
246 | | - |
247 | | - /* frame is larger than expected - lost end marker */ |
248 | | - if ((unsigned)res >= len) { |
249 | | - while (byte != SLIPDEV_END) { |
250 | | - /* clear out unreceived packet */ |
251 | | - byte = tsrb_get_one(&dev->inbuf); |
252 | | - } |
253 | | - return -ENOBUFS; |
254 | | - } |
255 | | - |
256 | | - tmp = slipdev_unstuff_readbyte(ptr, byte, &escaped); |
257 | | - ptr += tmp; |
258 | | - res += tmp; |
259 | | - } while (byte != SLIPDEV_END); |
260 | | - |
261 | | - if (++dev->rx_done != dev->rx_queued) { |
262 | | - DEBUG("slipdev: pkt still in queue"); |
263 | | - netdev_trigger_event_isr(&dev->netdev); |
264 | | - } |
| 256 | + crb_consume_chunk(&dev->rb, buf, len); |
| 257 | + res = len; |
265 | 258 | } |
266 | 259 | return res; |
267 | 260 | } |
268 | 261 |
|
269 | 262 | static void _isr(netdev_t *netdev) |
270 | 263 | { |
| 264 | + slipdev_t *dev = (slipdev_t *)netdev; |
| 265 | + |
271 | 266 | DEBUG("slipdev: handling ISR event\n"); |
272 | | - if (netdev->event_callback != NULL) { |
| 267 | + |
| 268 | + size_t len; |
| 269 | + while (crb_get_chunk_size(&dev->rb, &len)) { |
273 | 270 | DEBUG("slipdev: event handler set, issuing RX_COMPLETE event\n"); |
274 | 271 | netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE); |
275 | 272 | } |
|
0 commit comments