blob: a31217686a7ee08ea4137b05d0d1681f00f81e2c [file] [log] [blame]
Brian Silverman099196d2017-06-21 23:26:02 -07001/* Teensyduino Core Library
2 * http://www.pjrc.com/teensy/
3 * Copyright (c) 2017 PJRC.COM, LLC.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * 1. The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * 2. If the Software is incorporated into a build system that allows
17 * selection among a list of target devices, then similar target
18 * devices manufactured by PJRC.COM must be included in the list of
19 * target devices and selectable in the same manner.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
25 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
26 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 * SOFTWARE.
29 */
30
31#include "usb_dev.h"
32#include "usb_serial.h"
33#include "core_pins.h" // for yield()
34//#include "HardwareSerial.h"
35#include <string.h> // for memcpy()
36
37// defined by usb_dev.h -> usb_desc.h
38#if defined(CDC_STATUS_INTERFACE) && defined(CDC_DATA_INTERFACE)
39#if F_CPU >= 20000000
40
41uint32_t usb_cdc_line_coding[2];
42volatile uint32_t usb_cdc_line_rtsdtr_millis;
43volatile uint8_t usb_cdc_line_rtsdtr=0;
44volatile uint8_t usb_cdc_transmit_flush_timer=0;
45
46static usb_packet_t *rx_packet=NULL;
47static usb_packet_t *tx_packet=NULL;
48static volatile uint8_t tx_noautoflush=0;
49
50#define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */
51
52// get the next character, or -1 if nothing received
53int usb_serial_getchar(void)
54{
55 unsigned int i;
56 int c;
57
58 if (!rx_packet) {
59 if (!usb_configuration) return -1;
60 rx_packet = usb_rx(CDC_RX_ENDPOINT);
61 if (!rx_packet) return -1;
62 }
63 i = rx_packet->index;
64 c = rx_packet->buf[i++];
65 if (i >= rx_packet->len) {
66 usb_free(rx_packet);
67 rx_packet = NULL;
68 } else {
69 rx_packet->index = i;
70 }
71 return c;
72}
73
74// peek at the next character, or -1 if nothing received
75int usb_serial_peekchar(void)
76{
77 if (!rx_packet) {
78 if (!usb_configuration) return -1;
79 rx_packet = usb_rx(CDC_RX_ENDPOINT);
80 if (!rx_packet) return -1;
81 }
82 if (!rx_packet) return -1;
83 return rx_packet->buf[rx_packet->index];
84}
85
86// number of bytes available in the receive buffer
87int usb_serial_available(void)
88{
89 int count;
90 count = usb_rx_byte_count(CDC_RX_ENDPOINT);
91 if (rx_packet) count += rx_packet->len - rx_packet->index;
92 return count;
93}
94
95// read a block of bytes to a buffer
96int usb_serial_read(void *buffer, uint32_t size)
97{
98 uint8_t *p = (uint8_t *)buffer;
99 uint32_t qty, count=0;
100
101 while (size) {
102 if (!usb_configuration) break;
103 if (!rx_packet) {
104 rx:
105 rx_packet = usb_rx(CDC_RX_ENDPOINT);
106 if (!rx_packet) break;
107 if (rx_packet->len == 0) {
108 usb_free(rx_packet);
109 goto rx;
110 }
111 }
112 qty = rx_packet->len - rx_packet->index;
113 if (qty > size) qty = size;
114 memcpy(p, rx_packet->buf + rx_packet->index, qty);
115 p += qty;
116 count += qty;
117 size -= qty;
118 rx_packet->index += qty;
119 if (rx_packet->index >= rx_packet->len) {
120 usb_free(rx_packet);
121 rx_packet = NULL;
122 }
123 }
124 return count;
125}
126
127// discard any buffered input
128void usb_serial_flush_input(void)
129{
130 usb_packet_t *rx;
131
132 if (!usb_configuration) return;
133 if (rx_packet) {
134 usb_free(rx_packet);
135 rx_packet = NULL;
136 }
137 while (1) {
138 rx = usb_rx(CDC_RX_ENDPOINT);
139 if (!rx) break;
140 usb_free(rx);
141 }
142}
143
144// Maximum number of transmit packets to queue so we don't starve other endpoints for memory
145#define TX_PACKET_LIMIT 8
146
147// When the PC isn't listening, how long do we wait before discarding data? If this is
148// too short, we risk losing data during the stalls that are common with ordinary desktop
149// software. If it's too long, we stall the user's program when no software is running.
150#define TX_TIMEOUT_MSEC 70
151
152#if F_CPU == 240000000
153 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600)
154#elif F_CPU == 216000000
155 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440)
156#elif F_CPU == 192000000
157 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1280)
158#elif F_CPU == 180000000
159 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1200)
160#elif F_CPU == 168000000
161 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1100)
162#elif F_CPU == 144000000
163 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 932)
164#elif F_CPU == 120000000
165 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 764)
166#elif F_CPU == 96000000
167 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596)
168#elif F_CPU == 72000000
169 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512)
170#elif F_CPU == 48000000
171 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428)
172#elif F_CPU == 24000000
173 #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262)
174#endif
175
176// When we've suffered the transmit timeout, don't wait again until the computer
177// begins accepting data. If no software is running to receive, we'll just discard
178// data as rapidly as Serial.print() can generate it, until there's something to
179// actually receive it.
180static uint8_t transmit_previous_timeout=0;
181
182
183// transmit a character. 0 returned on success, -1 on error
184int usb_serial_putchar(uint8_t c)
185{
186 return usb_serial_write(&c, 1);
187}
188
189
190int usb_serial_write(const void *buffer, uint32_t size)
191{
192 uint32_t ret = size;
193 uint32_t len;
194 uint32_t wait_count;
195 const uint8_t *src = (const uint8_t *)buffer;
196 uint8_t *dest;
197
198 tx_noautoflush = 1;
199 while (size > 0) {
200 if (!tx_packet) {
201 wait_count = 0;
202 while (1) {
203 if (!usb_configuration) {
204 tx_noautoflush = 0;
205 return -1;
206 }
207 if (usb_tx_packet_count(CDC_TX_ENDPOINT) < TX_PACKET_LIMIT) {
208 tx_noautoflush = 1;
209 tx_packet = usb_malloc();
210 if (tx_packet) break;
211 tx_noautoflush = 0;
212 }
213 if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) {
214 transmit_previous_timeout = 1;
215 return -1;
216 }
217 yield();
218 }
219 }
220 transmit_previous_timeout = 0;
221 len = CDC_TX_SIZE - tx_packet->index;
222 if (len > size) len = size;
223 dest = tx_packet->buf + tx_packet->index;
224 tx_packet->index += len;
225 size -= len;
226 while (len-- > 0) *dest++ = *src++;
227 if (tx_packet->index >= CDC_TX_SIZE) {
228 tx_packet->len = CDC_TX_SIZE;
229 usb_tx(CDC_TX_ENDPOINT, tx_packet);
230 tx_packet = NULL;
231 }
232 usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
233 }
234 tx_noautoflush = 0;
235 return ret;
236}
237
238int usb_serial_write_buffer_free(void)
239{
240 uint32_t len;
241
242 tx_noautoflush = 1;
243 if (!tx_packet) {
244 if (!usb_configuration ||
245 usb_tx_packet_count(CDC_TX_ENDPOINT) >= TX_PACKET_LIMIT ||
246 (tx_packet = usb_malloc()) == NULL) {
247 tx_noautoflush = 0;
248 return 0;
249 }
250 }
251 len = CDC_TX_SIZE - tx_packet->index;
252 // TODO: Perhaps we need "usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT"
253 // added here, so the SOF interrupt can't take away the available buffer
254 // space we just promised the user could write without blocking?
255 // But does this come with other performance downsides? Could it lead to
256 // buffer data never actually transmitting in some usage cases? More
257 // investigation is needed.
258 // https://github.com/PaulStoffregen/cores/issues/10#issuecomment-61514955
259 tx_noautoflush = 0;
260 return len;
261}
262
263void usb_serial_flush_output(void)
264{
265 if (!usb_configuration) return;
266 tx_noautoflush = 1;
267 if (tx_packet) {
268 usb_cdc_transmit_flush_timer = 0;
269 tx_packet->len = tx_packet->index;
270 usb_tx(CDC_TX_ENDPOINT, tx_packet);
271 tx_packet = NULL;
272 } else {
273 usb_packet_t *tx = usb_malloc();
274 if (tx) {
275 usb_cdc_transmit_flush_timer = 0;
276 usb_tx(CDC_TX_ENDPOINT, tx);
277 } else {
278 usb_cdc_transmit_flush_timer = 1;
279 }
280 }
281 tx_noautoflush = 0;
282}
283
284void usb_serial_flush_callback(void)
285{
286 if (tx_noautoflush) return;
287 if (tx_packet) {
288 tx_packet->len = tx_packet->index;
289 usb_tx(CDC_TX_ENDPOINT, tx_packet);
290 tx_packet = NULL;
291 } else {
292 usb_packet_t *tx = usb_malloc();
293 if (tx) {
294 usb_tx(CDC_TX_ENDPOINT, tx);
295 } else {
296 usb_cdc_transmit_flush_timer = 1;
297 }
298 }
299}
300
301
302
303
304#endif // F_CPU
305#endif // CDC_STATUS_INTERFACE && CDC_DATA_INTERFACE