]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Output/pjrcUSB/arm/usb_serial.c
a67448855cb4c5f633c4d0833625a4aa2ff1be4d
[kiibohd-controller.git] / Output / pjrcUSB / arm / usb_serial.c
1 #include "usb_dev.h"
2 #include "usb_serial.h"
3 #include <Lib/USBLib.h>
4
5 // defined by usb_dev.h -> usb_desc.h
6 #if defined(CDC_STATUS_INTERFACE) && defined(CDC_DATA_INTERFACE)
7
8 uint8_t usb_cdc_line_coding[7];
9 volatile uint8_t usb_cdc_line_rtsdtr=0;
10 volatile uint8_t usb_cdc_transmit_flush_timer=0;
11
12 static usb_packet_t *rx_packet=NULL;
13 static usb_packet_t *tx_packet=NULL;
14 static volatile uint8_t tx_noautoflush=0;
15
16 #define TRANSMIT_FLUSH_TIMEOUT  5   /* in milliseconds */
17
18 static void usb_serial_receive(void)
19 {
20         if (!usb_configuration) return;
21         if (rx_packet) return;
22         while (1) {
23                 rx_packet = usb_rx(CDC_RX_ENDPOINT);
24                 if (rx_packet == NULL) return;
25                 if (rx_packet->len > 0) return;
26                 usb_free(rx_packet);
27                 rx_packet = NULL;
28         }
29 }
30
31 // get the next character, or -1 if nothing received
32 int usb_serial_getchar(void)
33 {
34         unsigned int i;
35         int c;
36
37         usb_serial_receive();
38         if (!rx_packet) return -1;
39         i = rx_packet->index;
40         c = rx_packet->buf[i++];
41         if (i >= rx_packet->len) {
42                 usb_free(rx_packet);
43                 rx_packet = NULL;
44         } else {
45                 rx_packet->index = i;
46         }
47         return c;
48 }
49
50 // peek at the next character, or -1 if nothing received
51 int usb_serial_peekchar(void)
52 {
53         usb_serial_receive();
54         if (!rx_packet) return -1;
55         return rx_packet->buf[rx_packet->index];
56 }
57
58 // number of bytes available in the receive buffer
59 int usb_serial_available(void)
60 {
61         int count=0;
62
63         if (usb_configuration) {
64                 count = usb_rx_byte_count(CDC_RX_ENDPOINT);
65         }
66         if (rx_packet) count += rx_packet->len - rx_packet->index;
67         return count;
68 }
69
70 // discard any buffered input
71 void usb_serial_flush_input(void)
72 {
73         usb_packet_t *rx;
74
75         if (!usb_configuration) return;
76         if (rx_packet) {
77                 usb_free(rx_packet);
78                 rx_packet = NULL;
79         }
80         while (1) {
81                 rx = usb_rx(CDC_RX_ENDPOINT);
82                 if (!rx) break;
83                 usb_free(rx);
84         }
85 }
86
87 // Maximum number of transmit packets to queue so we don't starve other endpoints for memory
88 #define TX_PACKET_LIMIT 8
89
90 // When the PC isn't listening, how long do we wait before discarding data?  If this is
91 // too short, we risk losing data during the stalls that are common with ordinary desktop
92 // software.  If it's too long, we stall the user's program when no software is running.
93 #define TX_TIMEOUT_MSEC 70
94
95 #if F_CPU == 96000000
96   #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596)
97 #elif F_CPU == 48000000
98   #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428)
99 #elif F_CPU == 24000000
100   #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262)
101 #endif
102
103 // When we've suffered the transmit timeout, don't wait again until the computer
104 // begins accepting data.  If no software is running to receive, we'll just discard
105 // data as rapidly as Serial.print() can generate it, until there's something to
106 // actually receive it.
107 static uint8_t transmit_previous_timeout=0;
108
109
110 // transmit a character.  0 returned on success, -1 on error
111 int usb_serial_putchar(uint8_t c)
112 {
113 #if 1
114         return usb_serial_write(&c, 1);
115 #endif
116 #if 0
117         uint32_t wait_count;
118
119         tx_noautoflush = 1;
120         if (!tx_packet) {
121                 wait_count = 0;
122                 while (1) {
123                         if (!usb_configuration) {
124                                 tx_noautoflush = 0;
125                                 return -1;
126                         }
127                         if (usb_tx_packet_count(CDC_TX_ENDPOINT) < TX_PACKET_LIMIT) {
128                                 tx_noautoflush = 1;
129                                 tx_packet = usb_malloc();
130                                 if (tx_packet) break;
131                                 tx_noautoflush = 0;
132                         }
133                         if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) {
134                                 transmit_previous_timeout = 1;
135                                 return -1;
136                         }
137                 }
138         }
139         transmit_previous_timeout = 0;
140         tx_packet->buf[tx_packet->index++] = c;
141         if (tx_packet->index < CDC_TX_SIZE) {
142                 usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
143         } else {
144                 tx_packet->len = CDC_TX_SIZE;
145                 usb_cdc_transmit_flush_timer = 0;
146                 usb_tx(CDC_TX_ENDPOINT, tx_packet);
147                 tx_packet = NULL;
148         }
149         tx_noautoflush = 0;
150         return 0;
151 #endif
152 }
153
154
155 int usb_serial_write(const void *buffer, uint32_t size)
156 {
157 #if 1
158         uint32_t len;
159         uint32_t wait_count;
160         const uint8_t *src = (const uint8_t *)buffer;
161         uint8_t *dest;
162
163         tx_noautoflush = 1;
164         while (size > 0) {
165                 if (!tx_packet) {
166                         wait_count = 0;
167                         while (1) {
168                                 if (!usb_configuration) {
169                                         tx_noautoflush = 0;
170                                         return -1;
171                                 }
172                                 if (usb_tx_packet_count(CDC_TX_ENDPOINT) < TX_PACKET_LIMIT) {
173                                         tx_noautoflush = 1;
174                                         tx_packet = usb_malloc();
175                                         if (tx_packet) break;
176                                         tx_noautoflush = 0;
177                                 }
178                                 if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) {
179                                         transmit_previous_timeout = 1;
180                                         return -1;
181                                 }
182                                 yield();
183                         }
184                 }
185                 transmit_previous_timeout = 0;
186                 len = CDC_TX_SIZE - tx_packet->index;
187                 if (len > size) len = size;
188                 dest = tx_packet->buf + tx_packet->index;
189                 tx_packet->index += len;
190                 size -= len;
191                 while (len-- > 0) *dest++ = *src++;
192                 if (tx_packet->index < CDC_TX_SIZE) {
193                         usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
194                 } else {
195                         tx_packet->len = CDC_TX_SIZE;
196                         usb_cdc_transmit_flush_timer = 0;
197                         usb_tx(CDC_TX_ENDPOINT, tx_packet);
198                         tx_packet = NULL;
199                 }
200         }
201         tx_noautoflush = 0;
202         return 0;
203 #endif
204 #if 0
205         const uint8_t *p = (const uint8_t *)buffer;
206         int r;
207
208         while (size) {
209                 r = usb_serial_putchar(*p++);
210                 if (r < 0) return -1;
211                 size--;
212         }
213         return 0;
214 #endif
215 }
216
217 void usb_serial_flush_output(void)
218 {
219         if (!usb_configuration) return;
220         //serial_print("usb_serial_flush_output\n");
221         if (tx_packet && tx_packet->index > 0) {
222                 usb_cdc_transmit_flush_timer = 0;
223                 tx_packet->len = tx_packet->index;
224                 usb_tx(CDC_TX_ENDPOINT, tx_packet);
225                 tx_packet = NULL;
226         }
227         // while (usb_tx_byte_count(CDC_TX_ENDPOINT) > 0) ; // wait
228 }
229
230 void usb_serial_flush_callback(void)
231 {
232         if (tx_noautoflush) return;
233         //serial_print("usb_flush_callback \n");
234         tx_packet->len = tx_packet->index;
235         usb_tx(CDC_TX_ENDPOINT, tx_packet);
236         tx_packet = NULL;
237         //serial_print("usb_flush_callback end\n");
238 }
239
240 #endif // CDC_STATUS_INTERFACE && CDC_DATA_INTERFACE
241