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