add crnl to end of M503 to flush in some cases
[clinton/Smoothieware.git] / src / libs / USBDevice / USBSerial / USBSerial.cpp
CommitLineData
47b0bbd2
MM
1/* Copyright (c) 2010-2011 mbed.org, MIT License\r
2*\r
3* Permission is hereby granted, free of charge, to any person obtaining a copy of this software\r
4* and associated documentation files (the "Software"), to deal in the Software without\r
5* restriction, including without limitation the rights to use, copy, modify, merge, publish,\r
6* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the\r
7* Software is furnished to do so, subject to the following conditions:\r
8*\r
9* The above copyright notice and this permission notice shall be included in all copies or\r
10* substantial portions of the Software.\r
11*\r
12* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING\r
13* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
14* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\r
15* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
16* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
17*/\r
18\r
19#include <cstdint>\r
20#include <cstdio>\r
21\r
22#include "USBSerial.h"\r
23\r
ca5e9a57
MM
24#include "libs/Kernel.h"\r
25#include "libs/SerialMessage.h"\r
61134a65 26#include "StreamOutputPool.h"\r
ca5e9a57 27\r
47b0bbd2
MM
28// extern void setled(int, bool);\r
29#define setled(a, b) do {} while (0)\r
30\r
1e9a12f7 31#define iprintf(...) do { } while (0)\r
47b0bbd2 32\r
8fbff64b 33USBSerial::USBSerial(USB *u): USBCDC(u), rxbuf(256 + 8), txbuf(128 + 8)\r
47b0bbd2
MM
34{\r
35 usb = u;\r
ca5e9a57 36 nl_in_rx = 0;\r
654286ea 37 attach = attached = false;\r
0e91ff91 38 flush_to_nl = false;\r
47b0bbd2
MM
39}\r
40\r
6cf52cc2
MM
41void USBSerial::ensure_tx_space(int space)\r
42{\r
43 while (txbuf.free() < space)\r
44 {\r
45 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);\r
46 usb->usbisr();\r
47 }\r
48}\r
49\r
47b0bbd2
MM
50int USBSerial::_putc(int c)\r
51{\r
654286ea
MM
52 if (!attached)\r
53 return 1;\r
6cf52cc2
MM
54 ensure_tx_space(1);\r
55 txbuf.queue(c);\r
47b0bbd2
MM
56\r
57 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);\r
47b0bbd2
MM
58 return 1;\r
59}\r
60\r
61int USBSerial::_getc()\r
62{\r
654286ea
MM
63 if (!attached)\r
64 return 0;\r
ca5e9a57 65 uint8_t c = 0;\r
47b0bbd2
MM
66 setled(4, 1); while (rxbuf.isEmpty()); setled(4, 0);\r
67 rxbuf.dequeue(&c);\r
68 if (rxbuf.free() == MAX_PACKET_SIZE_EPBULK)\r
69 {\r
70 usb->endpointSetInterrupt(CDC_BulkOut.bEndpointAddress, true);\r
71 iprintf("rxbuf has room for another packet, interrupt enabled\n");\r
47b0bbd2 72 }\r
d56ad249
MM
73 else if ((rxbuf.free() < MAX_PACKET_SIZE_EPBULK) && (nl_in_rx == 0))\r
74 {\r
75 // handle potential deadlock where a short line, and the beginning of a very long line are bundled in one usb packet\r
76 rxbuf.flush();\r
77 flush_to_nl = true;\r
78\r
79 usb->endpointSetInterrupt(CDC_BulkOut.bEndpointAddress, true);\r
80 iprintf("rxbuf has room for another packet, interrupt enabled\n");\r
81 }\r
6de6340d 82 if (nl_in_rx > 0)\r
9afe7d79 83 if (c == '\n' || c == '\r')\r
6de6340d 84 nl_in_rx--;\r
ca5e9a57 85\r
47b0bbd2
MM
86 return c;\r
87}\r
88\r
99b9ed8a
MM
89int USBSerial::puts(const char *str)\r
90{\r
654286ea
MM
91 if (!attached)\r
92 return strlen(str);\r
99b9ed8a
MM
93 int i = 0;\r
94 while (*str)\r
95 {\r
6cf52cc2 96 ensure_tx_space(1);\r
ed4ab0dd 97 txbuf.queue(*str);\r
77b8129c
MM
98 if ((txbuf.available() % 64) == 0)\r
99 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);\r
99b9ed8a
MM
100 i++;\r
101 str++;\r
102 }\r
aff8aca7 103 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);\r
99b9ed8a
MM
104 return i;\r
105}\r
106\r
9bba3e2d 107uint16_t USBSerial::writeBlock(const uint8_t * buf, uint16_t size)\r
47b0bbd2 108{\r
654286ea
MM
109 if (!attached)\r
110 return size;\r
47b0bbd2
MM
111 if (size > txbuf.free())\r
112 {\r
113 size = txbuf.free();\r
114 }\r
115 if (size > 0)\r
116 {\r
117 for (uint8_t i = 0; i < size; i++)\r
118 {\r
119 txbuf.queue(buf[i]);\r
120 }\r
121 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);\r
122 }\r
123 return size;\r
124}\r
125\r
126bool USBSerial::USBEvent_EPIn(uint8_t bEP, uint8_t bEPStatus)\r
127{\r
128 /*\r
129 * Called in ISR context\r
130 */\r
131\r
132// static bool needToSendNull = false;\r
133\r
134 bool r = true;\r
135\r
136 if (bEP != CDC_BulkIn.bEndpointAddress)\r
137 return false;\r
138\r
139 iprintf("USBSerial:EpIn: 0x%02X\n", bEPStatus);\r
140\r
141 uint8_t b[MAX_PACKET_SIZE_EPBULK];\r
142\r
143 int l = txbuf.available();\r
144 iprintf("%d bytes queued\n", l);\r
145 if (l > 0)\r
146 {\r
147 if (l > MAX_PACKET_SIZE_EPBULK)\r
148 l = MAX_PACKET_SIZE_EPBULK;\r
149 iprintf("Sending %d bytes:\n\t", l);\r
150 int i;\r
151 for (i = 0; i < l; i++) {\r
152 txbuf.dequeue(&b[i]);\r
153 if (b[i] >= 32 && b[i] < 128)\r
154 iprintf("%c", b[i]);\r
155 else {\r
156 iprintf("\\x%02X", b[i]);\r
157 }\r
158 }\r
159 iprintf("\nSending...\n");\r
160 send(b, l);\r
161 iprintf("Sent\n");\r
47b0bbd2
MM
162 if (txbuf.available() == 0)\r
163 r = false;\r
164 }\r
165 else\r
166 {\r
f455ce87 167 r = false;\r
47b0bbd2
MM
168 }\r
169 iprintf("USBSerial:EpIn Complete\n");\r
170 return r;\r
171}\r
172\r
173bool USBSerial::USBEvent_EPOut(uint8_t bEP, uint8_t bEPStatus)\r
174{\r
175 /*\r
176 * Called in ISR context\r
177 */\r
178\r
179 bool r = true;\r
180\r
181 iprintf("USBSerial:EpOut\n");\r
182 if (bEP != CDC_BulkOut.bEndpointAddress)\r
183 return false;\r
184\r
185 if (rxbuf.free() < MAX_PACKET_SIZE_EPBULK)\r
186 {\r
187// usb->endpointSetInterrupt(bEP, false);\r
188 return false;\r
189 }\r
190\r
191 uint8_t c[MAX_PACKET_SIZE_EPBULK];\r
192 uint32_t size = 64;\r
193\r
194 //we read the packet received and put it on the circular buffer\r
195 readEP(c, &size);\r
196 iprintf("Read %ld bytes:\n\t", size);\r
197 for (uint8_t i = 0; i < size; i++) {\r
0e91ff91
MM
198\r
199 if (flush_to_nl == false)\r
200 rxbuf.queue(c[i]);\r
201\r
47b0bbd2 202 if (c[i] >= 32 && c[i] < 128)\r
ca5e9a57 203 {\r
47b0bbd2 204 iprintf("%c", c[i]);\r
ca5e9a57
MM
205 }\r
206 else\r
207 {\r
47b0bbd2
MM
208 iprintf("\\x%02X", c[i]);\r
209 }\r
0e91ff91 210\r
9afe7d79 211 if (c[i] == '\n' || c[i] == '\r')\r
0e91ff91
MM
212 {\r
213 if (flush_to_nl)\r
214 flush_to_nl = false;\r
215 else\r
216 nl_in_rx++;\r
217 }\r
218 else if (rxbuf.isFull() && (nl_in_rx == 0))\r
219 {\r
220 // to avoid a deadlock with very long lines, we must dump the buffer\r
221 // and continue flushing to the next newline\r
222 rxbuf.flush();\r
223 flush_to_nl = true;\r
224 }\r
47b0bbd2
MM
225 }\r
226 iprintf("\nQueued, %d empty\n", rxbuf.free());\r
227\r
228 if (rxbuf.free() < MAX_PACKET_SIZE_EPBULK)\r
229 {\r
0e91ff91 230 // if buffer is full, stall endpoint, do not accept more data\r
47b0bbd2 231 r = false;\r
0e91ff91
MM
232\r
233 if (nl_in_rx == 0)\r
234 {\r
235 // we have to check for long line deadlock here too\r
236 flush_to_nl = true;\r
237 rxbuf.flush();\r
238\r
239 // and since our buffer is empty, we can accept more data\r
240 r = true;\r
241 }\r
47b0bbd2
MM
242 }\r
243\r
244 usb->readStart(CDC_BulkOut.bEndpointAddress, MAX_PACKET_SIZE_EPBULK);\r
245 iprintf("USBSerial:EpOut Complete\n");\r
246 return r;\r
247}\r
248\r
ca5e9a57
MM
249uint8_t USBSerial::available()\r
250{\r
47b0bbd2
MM
251 return rxbuf.available();\r
252}\r
ca5e9a57
MM
253\r
254void USBSerial::on_module_loaded()\r
255{\r
824de637 256 this->register_for_event(ON_MAIN_LOOP);\r
ca5e9a57
MM
257}\r
258\r
824de637 259void USBSerial::on_main_loop(void *argument)\r
ca5e9a57 260{\r
8922c191
MM
261 // apparently some OSes don't assert DTR when a program opens the port\r
262 if (available() && !attach)\r
263 attach = true;\r
264\r
654286ea
MM
265 if (attach != attached)\r
266 {\r
267 if (attach)\r
268 {\r
269 attached = true;\r
347854ff 270 THEKERNEL->streams->append_stream(this);\r
08d9afc6 271 puts("Smoothie\r\nok\r\n");\r
654286ea
MM
272 }\r
273 else\r
274 {\r
275 attached = false;\r
347854ff 276 THEKERNEL->streams->remove_stream(this);\r
654286ea
MM
277 txbuf.flush();\r
278 rxbuf.flush();\r
279 nl_in_rx = 0;\r
280 }\r
281 }\r
ca5e9a57
MM
282 if (nl_in_rx)\r
283 {\r
284 string received;\r
285 while (available())\r
286 {\r
287 char c = _getc();\r
9afe7d79 288 if( c == '\n' || c == '\r')\r
ca5e9a57
MM
289 {\r
290 struct SerialMessage message;\r
291 message.message = received;\r
292 message.stream = this;\r
99b9ed8a 293 iprintf("USBSerial Received: %s\n", message.message.c_str());\r
314ab8f7 294 THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message );\r
ca5e9a57
MM
295 return;\r
296 }\r
297 else\r
298 {\r
299 received += c;\r
300 }\r
301 }\r
302 }\r
303}\r
304\r
305void USBSerial::on_attach()\r
306{\r
654286ea 307 attach = true;\r
ca5e9a57
MM
308}\r
309\r
310void USBSerial::on_detach()\r
311{\r
654286ea 312 attach = false;\r
ca5e9a57 313}\r