DFU: increase detach timeout to 2 seconds
[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
26\r
47b0bbd2
MM
27// extern void setled(int, bool);\r
28#define setled(a, b) do {} while (0)\r
29\r
6de6340d 30// #define iprintf(...)\r
47b0bbd2
MM
31\r
32USBSerial::USBSerial(USB *u): USBCDC(u), rxbuf(128), txbuf(128)\r
33{\r
34 usb = u;\r
ca5e9a57 35 nl_in_rx = 0;\r
47b0bbd2
MM
36}\r
37\r
38int USBSerial::_putc(int c)\r
39{\r
40// send((uint8_t *)&c, 1);\r
41 if (txbuf.free())\r
42 txbuf.queue(c);\r
43\r
44 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);\r
45// usb->endpointTriggerInterrupt(CDC_BulkIn.bEndpointAddress);\r
46 return 1;\r
47}\r
48\r
49int USBSerial::_getc()\r
50{\r
ca5e9a57 51 uint8_t c = 0;\r
47b0bbd2
MM
52 setled(4, 1); while (rxbuf.isEmpty()); setled(4, 0);\r
53 rxbuf.dequeue(&c);\r
54 if (rxbuf.free() == MAX_PACKET_SIZE_EPBULK)\r
55 {\r
56 usb->endpointSetInterrupt(CDC_BulkOut.bEndpointAddress, true);\r
57 iprintf("rxbuf has room for another packet, interrupt enabled\n");\r
58// usb->endpointTriggerInterrupt(CDC_BulkOut.bEndpointAddress);\r
59 }\r
6de6340d
MM
60 if (nl_in_rx > 0)\r
61 if (c == '\n')\r
62 nl_in_rx--;\r
ca5e9a57 63\r
47b0bbd2
MM
64 return c;\r
65}\r
66\r
67uint16_t USBSerial::writeBlock(uint8_t * buf, uint16_t size)\r
68{\r
69 if (size > txbuf.free())\r
70 {\r
71 size = txbuf.free();\r
72 }\r
73 if (size > 0)\r
74 {\r
75 for (uint8_t i = 0; i < size; i++)\r
76 {\r
77 txbuf.queue(buf[i]);\r
78 }\r
79 usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);\r
80 }\r
81 return size;\r
82}\r
83\r
84bool USBSerial::USBEvent_EPIn(uint8_t bEP, uint8_t bEPStatus)\r
85{\r
86 /*\r
87 * Called in ISR context\r
88 */\r
89\r
90// static bool needToSendNull = false;\r
91\r
92 bool r = true;\r
93\r
94 if (bEP != CDC_BulkIn.bEndpointAddress)\r
95 return false;\r
96\r
97 iprintf("USBSerial:EpIn: 0x%02X\n", bEPStatus);\r
98\r
99 uint8_t b[MAX_PACKET_SIZE_EPBULK];\r
100\r
101 int l = txbuf.available();\r
102 iprintf("%d bytes queued\n", l);\r
103 if (l > 0)\r
104 {\r
105 if (l > MAX_PACKET_SIZE_EPBULK)\r
106 l = MAX_PACKET_SIZE_EPBULK;\r
107 iprintf("Sending %d bytes:\n\t", l);\r
108 int i;\r
109 for (i = 0; i < l; i++) {\r
110 txbuf.dequeue(&b[i]);\r
111 if (b[i] >= 32 && b[i] < 128)\r
112 iprintf("%c", b[i]);\r
113 else {\r
114 iprintf("\\x%02X", b[i]);\r
115 }\r
116 }\r
117 iprintf("\nSending...\n");\r
118 send(b, l);\r
119 iprintf("Sent\n");\r
120// if (l == 64 && txbuf.available() == 0)\r
121// needToSendNull = true;\r
122 if (txbuf.available() == 0)\r
123 r = false;\r
124 }\r
125 else\r
126 {\r
127// if (needToSendNull)\r
128// {\r
129// send(NULL, 0);\r
130// needToSendNull = false;\r
131// }\r
132// else\r
133// {\r
134 r = false;\r
135// }\r
136// usb->endpointSetInterrupt(bEP, false);\r
137 }\r
138 iprintf("USBSerial:EpIn Complete\n");\r
139 return r;\r
140}\r
141\r
142bool USBSerial::USBEvent_EPOut(uint8_t bEP, uint8_t bEPStatus)\r
143{\r
144 /*\r
145 * Called in ISR context\r
146 */\r
147\r
148 bool r = true;\r
149\r
150 iprintf("USBSerial:EpOut\n");\r
151 if (bEP != CDC_BulkOut.bEndpointAddress)\r
152 return false;\r
153\r
154 if (rxbuf.free() < MAX_PACKET_SIZE_EPBULK)\r
155 {\r
156// usb->endpointSetInterrupt(bEP, false);\r
157 return false;\r
158 }\r
159\r
160 uint8_t c[MAX_PACKET_SIZE_EPBULK];\r
161 uint32_t size = 64;\r
162\r
163 //we read the packet received and put it on the circular buffer\r
164 readEP(c, &size);\r
165 iprintf("Read %ld bytes:\n\t", size);\r
166 for (uint8_t i = 0; i < size; i++) {\r
167 rxbuf.queue(c[i]);\r
168 if (c[i] >= 32 && c[i] < 128)\r
ca5e9a57 169 {\r
47b0bbd2 170 iprintf("%c", c[i]);\r
ca5e9a57
MM
171 }\r
172 else\r
173 {\r
47b0bbd2
MM
174 iprintf("\\x%02X", c[i]);\r
175 }\r
ca5e9a57
MM
176 if (c[i] == '\n')\r
177 nl_in_rx++;\r
47b0bbd2
MM
178 }\r
179 iprintf("\nQueued, %d empty\n", rxbuf.free());\r
180\r
181 if (rxbuf.free() < MAX_PACKET_SIZE_EPBULK)\r
182 {\r
183// usb->endpointSetInterrupt(bEP, false);\r
184 r = false;\r
185 }\r
186\r
187 usb->readStart(CDC_BulkOut.bEndpointAddress, MAX_PACKET_SIZE_EPBULK);\r
188 iprintf("USBSerial:EpOut Complete\n");\r
189 return r;\r
190}\r
191\r
192/*\r
193bool USBSerial::EpCallback(uint8_t bEP, uint8_t bEPStatus) {\r
194 if (bEP == CDC_BulkOut.bEndpointAddress) {\r
195 uint8_t c[65];\r
196 uint32_t size = 0;\r
197\r
198 //we read the packet received and put it on the circular buffer\r
199 readEP(c, &size);\r
200 for (uint8_t i = 0; i < size; i++) {\r
201 buf.queue(c[i]);\r
202 }\r
203\r
204 //call a potential handler\r
205 rx.call();\r
206\r
207 // We reactivate the endpoint to receive next characters\r
208 usb->readStart(CDC_BulkOut.bEndpointAddress, MAX_PACKET_SIZE_EPBULK);\r
209 return true;\r
210 }\r
211 return false;\r
212}*/\r
213\r
ca5e9a57
MM
214uint8_t USBSerial::available()\r
215{\r
47b0bbd2
MM
216 return rxbuf.available();\r
217}\r
ca5e9a57
MM
218\r
219void USBSerial::on_module_loaded()\r
220{\r
221 this->register_for_event(ON_MAIN_LOOP);\r
222// this->kernel->streams->append_stream(this);\r
223}\r
224\r
0bdcabe6 225void USBSerial::on_main_loop(void *argument)\r
ca5e9a57 226{\r
75ec4e6c 227// this->kernel->streams->printf("!");\r
ca5e9a57
MM
228 if (nl_in_rx)\r
229 {\r
230 string received;\r
231 while (available())\r
232 {\r
233 char c = _getc();\r
234 if( c == '\n' )\r
235 {\r
236 struct SerialMessage message;\r
237 message.message = received;\r
238 message.stream = this;\r
239 this->kernel->call_event(ON_CONSOLE_LINE_RECEIVED, &message );\r
240 return;\r
241 }\r
242 else\r
243 {\r
244 received += c;\r
245 }\r
246 }\r
247 }\r
248}\r
249\r
250void USBSerial::on_attach()\r
251{\r
252 this->kernel->streams->append_stream(this);\r
253 writeBlock((uint8_t *) "Smoothie\nok\n", 12);\r
254}\r
255\r
256void USBSerial::on_detach()\r
257{\r
258 this->kernel->streams->remove_stream(this);\r
259 txbuf.flush();\r
260 rxbuf.flush();\r
261 nl_in_rx = 0;\r
262}\r