]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/protocol/usb_hid/arduino-1.8.13/cores/arduino/CDC.cpp
usb_hid: Update arduino cores to 1.8.13
[max/tmk_keyboard.git] / tmk_core / protocol / usb_hid / arduino-1.8.13 / cores / arduino / CDC.cpp
1
2
3 /* Copyright (c) 2011, Peter Barrett  
4 **  
5 ** Permission to use, copy, modify, and/or distribute this software for  
6 ** any purpose with or without fee is hereby granted, provided that the  
7 ** above copyright notice and this permission notice appear in all copies.  
8 ** 
9 ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL  
10 ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED  
11 ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR  
12 ** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES  
13 ** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,  
14 ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  
15 ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS  
16 ** SOFTWARE.  
17 */
18
19 #include "USBAPI.h"
20 #include <avr/wdt.h>
21 #include <util/atomic.h>
22
23 #if defined(USBCON)
24
25 typedef struct
26 {
27         u32     dwDTERate;
28         u8      bCharFormat;
29         u8      bParityType;
30         u8      bDataBits;
31         u8      lineState;
32 } LineInfo;
33
34 static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };
35 static volatile int32_t breakValue = -1;
36
37 static u8 wdtcsr_save;
38
39 #define WEAK __attribute__ ((weak))
40
41 extern const CDCDescriptor _cdcInterface PROGMEM;
42 const CDCDescriptor _cdcInterface =
43 {
44         D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
45
46         //      CDC communication interface
47         D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
48         D_CDCCS(CDC_HEADER,0x10,0x01),                                                          // Header (1.10 bcd)
49         D_CDCCS(CDC_CALL_MANAGEMENT,1,1),                                                       // Device handles call management (not)
50         D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6),                            // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported
51         D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE),        // Communication interface is master, data interface is slave 0
52         D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40),
53
54         //      CDC data interface
55         D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0),
56         D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0),
57         D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0)
58 };
59
60 bool isLUFAbootloader()
61 {
62         return pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE;
63 }
64
65 int CDC_GetInterface(u8* interfaceNum)
66 {
67         interfaceNum[0] += 2;   // uses 2
68         return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface));
69 }
70
71 bool CDC_Setup(USBSetup& setup)
72 {
73         u8 r = setup.bRequest;
74         u8 requestType = setup.bmRequestType;
75
76         if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
77         {
78                 if (CDC_GET_LINE_CODING == r)
79                 {
80                         USB_SendControl(0,(void*)&_usbLineInfo,7);
81                         return true;
82                 }
83         }
84
85         if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
86         {
87                 if (CDC_SEND_BREAK == r)
88                 {
89                         breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL;
90                 }
91
92                 if (CDC_SET_LINE_CODING == r)
93                 {
94                         USB_RecvControl((void*)&_usbLineInfo,7);
95                 }
96
97                 if (CDC_SET_CONTROL_LINE_STATE == r)
98                 {
99                         _usbLineInfo.lineState = setup.wValueL;
100
101                         // auto-reset into the bootloader is triggered when the port, already 
102                         // open at 1200 bps, is closed.  this is the signal to start the watchdog
103                         // with a relatively long period so it can finish housekeeping tasks
104                         // like servicing endpoints before the sketch ends
105
106                         uint16_t magic_key_pos = MAGIC_KEY_POS;
107
108 // If we don't use the new RAMEND directly, check manually if we have a newer bootloader.
109 // This is used to keep compatible with the old leonardo bootloaders.
110 // You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check.
111 #if MAGIC_KEY_POS != (RAMEND-1)
112                         // For future boards save the key in the inproblematic RAMEND
113                         // Which is reserved for the main() return value (which will never return)
114                         if (isLUFAbootloader()) {
115                                 // horray, we got a new bootloader!
116                                 magic_key_pos = (RAMEND-1);
117                         }
118 #endif
119
120                         // We check DTR state to determine if host port is open (bit 0 of lineState).
121                         if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0)
122                         {
123 #if MAGIC_KEY_POS != (RAMEND-1)
124                                 // Backup ram value if its not a newer bootloader and it hasn't already been saved.
125                                 // This should avoid memory corruption at least a bit, not fully
126                                 if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) {
127                                         *(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos;
128                                 }
129 #endif
130                                 // Store boot key
131                                 *(uint16_t *)magic_key_pos = MAGIC_KEY;
132                                 // Save the watchdog state in case the reset is aborted.
133                                 wdtcsr_save = WDTCSR;
134                                 wdt_enable(WDTO_120MS);
135                         }
136                         else if (*(uint16_t *)magic_key_pos == MAGIC_KEY)
137                         {
138                                 // Most OSs do some intermediate steps when configuring ports and DTR can
139                                 // twiggle more than once before stabilizing.
140                                 // To avoid spurious resets we set the watchdog to 120ms and eventually
141                                 // cancel if DTR goes back high.
142                                 // Cancellation is only done if an auto-reset was started, which is
143                                 // indicated by the magic key having been set.
144
145                                 wdt_reset();
146                                 // Restore the watchdog state in case the sketch was using it.
147                                 WDTCSR |= (1<<WDCE) | (1<<WDE);
148                                 WDTCSR = wdtcsr_save;
149 #if MAGIC_KEY_POS != (RAMEND-1)
150                                 // Restore backed up (old bootloader) magic key data
151                                 if (magic_key_pos != (RAMEND-1)) {
152                                         *(uint16_t *)magic_key_pos = *(uint16_t *)(RAMEND-1);
153                                 } else
154 #endif
155                                 {
156                                 // Clean up RAMEND key
157                                         *(uint16_t *)magic_key_pos = 0x0000;
158                                 }
159                         }
160                 }
161                 return true;
162         }
163         return false;
164 }
165
166
167 void Serial_::begin(unsigned long /* baud_count */)
168 {
169         peek_buffer = -1;
170 }
171
172 void Serial_::begin(unsigned long /* baud_count */, byte /* config */)
173 {
174         peek_buffer = -1;
175 }
176
177 void Serial_::end(void)
178 {
179 }
180
181 int Serial_::available(void)
182 {
183         if (peek_buffer >= 0) {
184                 return 1 + USB_Available(CDC_RX);
185         }
186         return USB_Available(CDC_RX);
187 }
188
189 int Serial_::peek(void)
190 {
191         if (peek_buffer < 0)
192                 peek_buffer = USB_Recv(CDC_RX);
193         return peek_buffer;
194 }
195
196 int Serial_::read(void)
197 {
198         if (peek_buffer >= 0) {
199                 int c = peek_buffer;
200                 peek_buffer = -1;
201                 return c;
202         }
203         return USB_Recv(CDC_RX);
204 }
205
206 int Serial_::availableForWrite(void)
207 {
208         return USB_SendSpace(CDC_TX);
209 }
210
211 void Serial_::flush(void)
212 {
213         USB_Flush(CDC_TX);
214 }
215
216 size_t Serial_::write(uint8_t c)
217 {
218         return write(&c, 1);
219 }
220
221 size_t Serial_::write(const uint8_t *buffer, size_t size)
222 {
223         /* only try to send bytes if the high-level CDC connection itself 
224          is open (not just the pipe) - the OS should set lineState when the port
225          is opened and clear lineState when the port is closed.
226          bytes sent before the user opens the connection or after
227          the connection is closed are lost - just like with a UART. */
228         
229         // TODO - ZE - check behavior on different OSes and test what happens if an
230         // open connection isn't broken cleanly (cable is yanked out, host dies
231         // or locks up, or host virtual serial port hangs)
232         if (_usbLineInfo.lineState > 0) {
233                 int r = USB_Send(CDC_TX,buffer,size);
234                 if (r > 0) {
235                         return r;
236                 } else {
237                         setWriteError();
238                         return 0;
239                 }
240         }
241         setWriteError();
242         return 0;
243 }
244
245 // This operator is a convenient way for a sketch to check whether the
246 // port has actually been configured and opened by the host (as opposed
247 // to just being connected to the host).  It can be used, for example, in 
248 // setup() before printing to ensure that an application on the host is
249 // actually ready to receive and display the data.
250 // We add a short delay before returning to fix a bug observed by Federico
251 // where the port is configured (lineState != 0) but not quite opened.
252 Serial_::operator bool() {
253         bool result = false;
254         if (_usbLineInfo.lineState > 0) 
255                 result = true;
256         delay(10);
257         return result;
258 }
259
260 unsigned long Serial_::baud() {
261         // Disable interrupts while reading a multi-byte value
262         uint32_t baudrate;
263         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
264                 baudrate =  _usbLineInfo.dwDTERate;
265         }
266         return baudrate;
267 }
268
269 uint8_t Serial_::stopbits() {
270         return _usbLineInfo.bCharFormat;
271 }
272
273 uint8_t Serial_::paritytype() {
274         return _usbLineInfo.bParityType;
275 }
276
277 uint8_t Serial_::numbits() {
278         return _usbLineInfo.bDataBits;
279 }
280
281 bool Serial_::dtr() {
282         return _usbLineInfo.lineState & 0x1;
283 }
284
285 bool Serial_::rts() {
286         return _usbLineInfo.lineState & 0x2;
287 }
288
289 int32_t Serial_::readBreak() {
290         int32_t ret;
291         // Disable IRQs while reading and clearing breakValue to make
292         // sure we don't overwrite a value just set by the ISR.
293         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
294                 ret = breakValue;
295                 breakValue = -1;
296         }
297         return ret;
298 }
299
300 Serial_ Serial;
301
302 #endif /* if defined(USBCON) */