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