|
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) */ |