]> git.donarmstrong.com Git - qmk_firmware.git/blob - protocol/usb_hid/arduino-1.0.1/cores/arduino/CDC.cpp
Squashed 'tmk_core/' content from commit 05caacc
[qmk_firmware.git] / protocol / usb_hid / arduino-1.0.1 / 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 "Platform.h"
20 #include "USBAPI.h"
21 #include <avr/wdt.h>
22
23 #if defined(USBCON)
24 #ifdef CDC_ENABLED
25
26 #if (RAMEND < 1000)
27 #define SERIAL_BUFFER_SIZE 16
28 #else
29 #define SERIAL_BUFFER_SIZE 64
30 #endif
31
32 struct ring_buffer
33 {
34         unsigned char buffer[SERIAL_BUFFER_SIZE];
35         volatile int head;
36         volatile int tail;
37 };
38
39 ring_buffer cdc_rx_buffer = { { 0 }, 0, 0};
40
41 typedef struct
42 {
43         u32     dwDTERate;
44         u8      bCharFormat;
45         u8      bParityType;
46         u8      bDataBits;
47         u8      lineState;
48 } LineInfo;
49
50 static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };
51
52 #define WEAK __attribute__ ((weak))
53
54 extern const CDCDescriptor _cdcInterface PROGMEM;
55 const CDCDescriptor _cdcInterface =
56 {
57         D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1),
58
59         //      CDC communication interface
60         D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
61         D_CDCCS(CDC_HEADER,0x10,0x01),                                                          // Header (1.10 bcd)
62         D_CDCCS(CDC_CALL_MANAGEMENT,1,1),                                                       // Device handles call management (not)
63         D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6),                            // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported
64         D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE),        // Communication interface is master, data interface is slave 0
65         D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40),
66
67         //      CDC data interface
68         D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0),
69         D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,0x40,0),
70         D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,0x40,0)
71 };
72
73 int WEAK CDC_GetInterface(u8* interfaceNum)
74 {
75         interfaceNum[0] += 2;   // uses 2
76         return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface));
77 }
78
79 bool WEAK CDC_Setup(Setup& setup)
80 {
81         u8 r = setup.bRequest;
82         u8 requestType = setup.bmRequestType;
83
84         if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
85         {
86                 if (CDC_GET_LINE_CODING == r)
87                 {
88                         USB_SendControl(0,(void*)&_usbLineInfo,7);
89                         return true;
90                 }
91         }
92
93         if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
94         {
95                 if (CDC_SET_LINE_CODING == r)
96                 {
97                         USB_RecvControl((void*)&_usbLineInfo,7);
98                         return true;
99                 }
100
101                 if (CDC_SET_CONTROL_LINE_STATE == r)
102                 {
103                         _usbLineInfo.lineState = setup.wValueL;
104
105                         // auto-reset into the bootloader is triggered when the port, already 
106                         // open at 1200 bps, is closed.  this is the signal to start the watchdog
107                         // with a relatively long period so it can finish housekeeping tasks
108                         // like servicing endpoints before the sketch ends
109                         if (1200 == _usbLineInfo.dwDTERate) {
110                                 // We check DTR state to determine if host port is open (bit 0 of lineState).
111                                 if ((_usbLineInfo.lineState & 0x01) == 0) {
112                                         *(uint16_t *)0x0800 = 0x7777;
113                                         wdt_enable(WDTO_120MS);
114                                 } else {
115                                         // Most OSs do some intermediate steps when configuring ports and DTR can
116                                         // twiggle more than once before stabilizing.
117                                         // To avoid spurious resets we set the watchdog to 250ms and eventually
118                                         // cancel if DTR goes back high.
119         
120                                         wdt_disable();
121                                         wdt_reset();
122                                         *(uint16_t *)0x0800 = 0x0;
123                                 }
124                         }
125                         return true;
126                 }
127         }
128         return false;
129 }
130
131
132 int _serialPeek = -1;
133 void Serial_::begin(uint16_t baud_count)
134 {
135 }
136
137 void Serial_::end(void)
138 {
139 }
140
141 void Serial_::accept(void) 
142 {
143         ring_buffer *buffer = &cdc_rx_buffer;
144         int c = USB_Recv(CDC_RX); 
145         int i = (unsigned int)(buffer->head+1) % SERIAL_BUFFER_SIZE;
146         
147         // if we should be storing the received character into the location
148         // just before the tail (meaning that the head would advance to the
149         // current location of the tail), we're about to overflow the buffer
150         // and so we don't write the character or advance the head.
151         if (i != buffer->tail) {
152                 buffer->buffer[buffer->head] = c;
153                 buffer->head = i;
154         }
155 }
156
157 int Serial_::available(void)
158 {
159         ring_buffer *buffer = &cdc_rx_buffer;
160         return (unsigned int)(SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % SERIAL_BUFFER_SIZE;
161 }
162
163 int Serial_::peek(void)
164 {
165         ring_buffer *buffer = &cdc_rx_buffer;
166         if (buffer->head == buffer->tail) {
167                 return -1;
168         } else {
169                 return buffer->buffer[buffer->tail];
170         }
171 }
172
173 int Serial_::read(void)
174 {
175         ring_buffer *buffer = &cdc_rx_buffer;
176         // if the head isn't ahead of the tail, we don't have any characters
177         if (buffer->head == buffer->tail) {
178                 return -1;
179         } else {
180                 unsigned char c = buffer->buffer[buffer->tail];
181                 buffer->tail = (unsigned int)(buffer->tail + 1) % SERIAL_BUFFER_SIZE;
182                 return c;
183         }       
184 }
185
186 void Serial_::flush(void)
187 {
188         USB_Flush(CDC_TX);
189 }
190
191 size_t Serial_::write(uint8_t c)
192 {
193         /* only try to send bytes if the high-level CDC connection itself 
194          is open (not just the pipe) - the OS should set lineState when the port
195          is opened and clear lineState when the port is closed.
196          bytes sent before the user opens the connection or after
197          the connection is closed are lost - just like with a UART. */
198         
199         // TODO - ZE - check behavior on different OSes and test what happens if an
200         // open connection isn't broken cleanly (cable is yanked out, host dies
201         // or locks up, or host virtual serial port hangs)
202         if (_usbLineInfo.lineState > 0) {
203                 int r = USB_Send(CDC_TX,&c,1);
204                 if (r > 0) {
205                         return r;
206                 } else {
207                         setWriteError();
208                         return 0;
209                 }
210         }
211         setWriteError();
212         return 0;
213 }
214
215 // This operator is a convenient way for a sketch to check whether the
216 // port has actually been configured and opened by the host (as opposed
217 // to just being connected to the host).  It can be used, for example, in 
218 // setup() before printing to ensure that an application on the host is
219 // actually ready to receive and display the data.
220 // We add a short delay before returning to fix a bug observed by Federico
221 // where the port is configured (lineState != 0) but not quite opened.
222 Serial_::operator bool() {
223         bool result = false;
224         if (_usbLineInfo.lineState > 0) 
225                 result = true;
226         delay(10);
227         return result;
228 }
229
230 Serial_ Serial;
231
232 #endif
233 #endif /* if defined(USBCON) */