Fri, 17 Nov 2017 10:13:31 +0100
proper configuration, homing and planner optimization
2 | 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) */ |