Merge branch 'edge'
[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 }
40
41 void USBSerial::ensure_tx_space(int space)
42 {
43 while (txbuf.free() < space)
44 {
45 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
46 usb->usbisr();
47 }
48 }
49
50 int USBSerial::_putc(int c)
51 {
52 if (!attached)
53 return 1;
54 ensure_tx_space(1);
55 txbuf.queue(c);
56
57 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
58 return 1;
59 }
60
61 int USBSerial::_getc()
62 {
63 if (!attached)
64 return 0;
65 uint8_t c = 0;
66 setled(4, 1); while (rxbuf.isEmpty()); setled(4, 0);
67 rxbuf.dequeue(&c);
68 if (rxbuf.free() == MAX_PACKET_SIZE_EPBULK)
69 {
70 usb->endpointSetInterrupt(CDC_BulkOut.bEndpointAddress, true);
71 iprintf("rxbuf has room for another packet, interrupt enabled\n");
72 }
73 else if ((rxbuf.free() < MAX_PACKET_SIZE_EPBULK) && (nl_in_rx == 0))
74 {
75 // handle potential deadlock where a short line, and the beginning of a very long line are bundled in one usb packet
76 rxbuf.flush();
77 flush_to_nl = true;
78
79 usb->endpointSetInterrupt(CDC_BulkOut.bEndpointAddress, true);
80 iprintf("rxbuf has room for another packet, interrupt enabled\n");
81 }
82 if (nl_in_rx > 0)
83 if (c == '\n' || c == '\r')
84 nl_in_rx--;
85
86 return c;
87 }
88
89 int USBSerial::puts(const char *str)
90 {
91 if (!attached)
92 return strlen(str);
93 int i = 0;
94 while (*str)
95 {
96 ensure_tx_space(1);
97 txbuf.queue(*str);
98 if ((txbuf.available() % 64) == 0)
99 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
100 i++;
101 str++;
102 }
103 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
104 return i;
105 }
106
107 uint16_t USBSerial::writeBlock(const uint8_t * buf, uint16_t size)
108 {
109 if (!attached)
110 return size;
111 if (size > txbuf.free())
112 {
113 size = txbuf.free();
114 }
115 if (size > 0)
116 {
117 for (uint8_t i = 0; i < size; i++)
118 {
119 txbuf.queue(buf[i]);
120 }
121 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
122 }
123 return size;
124 }
125
126 bool USBSerial::USBEvent_EPIn(uint8_t bEP, uint8_t bEPStatus)
127 {
128 /*
129 * Called in ISR context
130 */
131
132 // static bool needToSendNull = false;
133
134 bool r = true;
135
136 if (bEP != CDC_BulkIn.bEndpointAddress)
137 return false;
138
139 iprintf("USBSerial:EpIn: 0x%02X\n", bEPStatus);
140
141 uint8_t b[MAX_PACKET_SIZE_EPBULK];
142
143 int l = txbuf.available();
144 iprintf("%d bytes queued\n", l);
145 if (l > 0)
146 {
147 if (l > MAX_PACKET_SIZE_EPBULK)
148 l = MAX_PACKET_SIZE_EPBULK;
149 iprintf("Sending %d bytes:\n\t", l);
150 int i;
151 for (i = 0; i < l; i++) {
152 txbuf.dequeue(&b[i]);
153 if (b[i] >= 32 && b[i] < 128)
154 iprintf("%c", b[i]);
155 else {
156 iprintf("\\x%02X", b[i]);
157 }
158 }
159 iprintf("\nSending...\n");
160 send(b, l);
161 iprintf("Sent\n");
162 if (txbuf.available() == 0)
163 r = false;
164 }
165 else
166 {
167 r = false;
168 }
169 iprintf("USBSerial:EpIn Complete\n");
170 return r;
171 }
172
173 bool USBSerial::USBEvent_EPOut(uint8_t bEP, uint8_t bEPStatus)
174 {
175 /*
176 * Called in ISR context
177 */
178
179 bool r = true;
180
181 iprintf("USBSerial:EpOut\n");
182 if (bEP != CDC_BulkOut.bEndpointAddress)
183 return false;
184
185 if (rxbuf.free() < MAX_PACKET_SIZE_EPBULK)
186 {
187 // usb->endpointSetInterrupt(bEP, false);
188 return false;
189 }
190
191 uint8_t c[MAX_PACKET_SIZE_EPBULK];
192 uint32_t size = 64;
193
194 //we read the packet received and put it on the circular buffer
195 readEP(c, &size);
196 iprintf("Read %ld bytes:\n\t", size);
197 for (uint8_t i = 0; i < size; i++) {
198
199 if (flush_to_nl == false)
200 rxbuf.queue(c[i]);
201
202 if (c[i] >= 32 && c[i] < 128)
203 {
204 iprintf("%c", c[i]);
205 }
206 else
207 {
208 iprintf("\\x%02X", c[i]);
209 }
210
211 if (c[i] == '\n' || c[i] == '\r')
212 {
213 if (flush_to_nl)
214 flush_to_nl = false;
215 else
216 nl_in_rx++;
217 }
218 else if (rxbuf.isFull() && (nl_in_rx == 0))
219 {
220 // to avoid a deadlock with very long lines, we must dump the buffer
221 // and continue flushing to the next newline
222 rxbuf.flush();
223 flush_to_nl = true;
224 }
225 }
226 iprintf("\nQueued, %d empty\n", rxbuf.free());
227
228 if (rxbuf.free() < MAX_PACKET_SIZE_EPBULK)
229 {
230 // if buffer is full, stall endpoint, do not accept more data
231 r = false;
232
233 if (nl_in_rx == 0)
234 {
235 // we have to check for long line deadlock here too
236 flush_to_nl = true;
237 rxbuf.flush();
238
239 // and since our buffer is empty, we can accept more data
240 r = true;
241 }
242 }
243
244 usb->readStart(CDC_BulkOut.bEndpointAddress, MAX_PACKET_SIZE_EPBULK);
245 iprintf("USBSerial:EpOut Complete\n");
246 return r;
247 }
248
249 uint8_t USBSerial::available()
250 {
251 return rxbuf.available();
252 }
253
254 bool USBSerial::ready()
255 {
256 return rxbuf.available();
257 }
258
259 void USBSerial::on_module_loaded()
260 {
261 this->register_for_event(ON_MAIN_LOOP);
262 }
263
264 void USBSerial::on_main_loop(void *argument)
265 {
266 // apparently some OSes don't assert DTR when a program opens the port
267 if (available() && !attach)
268 attach = true;
269
270 if (attach != attached)
271 {
272 if (attach)
273 {
274 attached = true;
275 THEKERNEL->streams->append_stream(this);
276 puts("Smoothie\r\nok\r\n");
277 }
278 else
279 {
280 attached = false;
281 THEKERNEL->streams->remove_stream(this);
282 txbuf.flush();
283 rxbuf.flush();
284 nl_in_rx = 0;
285 }
286 }
287 if (nl_in_rx)
288 {
289 string received;
290 while (available())
291 {
292 char c = _getc();
293 if( c == '\n' || c == '\r')
294 {
295 struct SerialMessage message;
296 message.message = received;
297 message.stream = this;
298 iprintf("USBSerial Received: %s\n", message.message.c_str());
299 THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message );
300 return;
301 }
302 else
303 {
304 received += c;
305 }
306 }
307 }
308 }
309
310 void USBSerial::on_attach()
311 {
312 attach = true;
313 }
314
315 void USBSerial::on_detach()
316 {
317 attach = false;
318 }