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