|
1 /* |
|
2 LUFA Library |
|
3 Copyright (C) Dean Camera, 2010. |
|
4 |
|
5 dean [at] fourwalledcubicle [dot] com |
|
6 www.fourwalledcubicle.com |
|
7 */ |
|
8 |
|
9 /* |
|
10 Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) |
|
11 |
|
12 Permission to use, copy, modify, distribute, and sell this |
|
13 software and its documentation for any purpose is hereby granted |
|
14 without fee, provided that the above copyright notice appear in |
|
15 all copies and that both that the copyright notice and this |
|
16 permission notice and warranty disclaimer appear in supporting |
|
17 documentation, and that the name of the author not be used in |
|
18 advertising or publicity pertaining to distribution of the |
|
19 software without specific, written prior permission. |
|
20 |
|
21 The author disclaim all warranties with regard to this |
|
22 software, including all implied warranties of merchantability |
|
23 and fitness. In no event shall the author be liable for any |
|
24 special, indirect or consequential damages or any damages |
|
25 whatsoever resulting from loss of use, data or profits, whether |
|
26 in an action of contract, negligence or other tortious action, |
|
27 arising out of or in connection with the use or performance of |
|
28 this software. |
|
29 */ |
|
30 |
|
31 /** \file |
|
32 * |
|
33 * Main source file for the Arduino-usbserial project. This file contains the main tasks of |
|
34 * the project and is responsible for the initial application hardware configuration. |
|
35 */ |
|
36 |
|
37 #include "Arduino-usbserial.h" |
|
38 |
|
39 /** Circular buffer to hold data from the host before it is sent to the device via the serial port. */ |
|
40 RingBuff_t USBtoUSART_Buffer; |
|
41 |
|
42 /** Circular buffer to hold data from the serial port before it is sent to the host. */ |
|
43 RingBuff_t USARTtoUSB_Buffer; |
|
44 |
|
45 /** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */ |
|
46 volatile struct |
|
47 { |
|
48 uint8_t TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */ |
|
49 uint8_t RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */ |
|
50 uint8_t PingPongLEDPulse; /**< Milliseconds remaining for enumeration Tx/Rx ping-pong LED pulse */ |
|
51 } PulseMSRemaining; |
|
52 |
|
53 /** LUFA CDC Class driver interface configuration and state information. This structure is |
|
54 * passed to all CDC Class driver functions, so that multiple instances of the same class |
|
55 * within a device can be differentiated from one another. |
|
56 */ |
|
57 USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface = |
|
58 { |
|
59 .Config = |
|
60 { |
|
61 .ControlInterfaceNumber = 0, |
|
62 |
|
63 .DataINEndpointNumber = CDC_TX_EPNUM, |
|
64 .DataINEndpointSize = CDC_TXRX_EPSIZE, |
|
65 .DataINEndpointDoubleBank = false, |
|
66 |
|
67 .DataOUTEndpointNumber = CDC_RX_EPNUM, |
|
68 .DataOUTEndpointSize = CDC_TXRX_EPSIZE, |
|
69 .DataOUTEndpointDoubleBank = false, |
|
70 |
|
71 .NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM, |
|
72 .NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE, |
|
73 .NotificationEndpointDoubleBank = false, |
|
74 }, |
|
75 }; |
|
76 |
|
77 /** Main program entry point. This routine contains the overall program flow, including initial |
|
78 * setup of all components and the main program loop. |
|
79 */ |
|
80 int main(void) |
|
81 { |
|
82 SetupHardware(); |
|
83 |
|
84 RingBuffer_InitBuffer(&USBtoUSART_Buffer); |
|
85 RingBuffer_InitBuffer(&USARTtoUSB_Buffer); |
|
86 |
|
87 sei(); |
|
88 |
|
89 for (;;) |
|
90 { |
|
91 /* Only try to read in bytes from the CDC interface if the transmit buffer is not full */ |
|
92 if (!(RingBuffer_IsFull(&USBtoUSART_Buffer))) |
|
93 { |
|
94 int16_t ReceivedByte = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); |
|
95 |
|
96 /* Read bytes from the USB OUT endpoint into the USART transmit buffer */ |
|
97 if (!(ReceivedByte < 0)) |
|
98 RingBuffer_Insert(&USBtoUSART_Buffer, ReceivedByte); |
|
99 } |
|
100 |
|
101 /* Check if the UART receive buffer flush timer has expired or the buffer is nearly full */ |
|
102 RingBuff_Count_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer); |
|
103 if ((TIFR0 & (1 << TOV0)) || (BufferCount > BUFFER_NEARLY_FULL)) |
|
104 { |
|
105 TIFR0 |= (1 << TOV0); |
|
106 |
|
107 if (USARTtoUSB_Buffer.Count) { |
|
108 LEDs_TurnOnLEDs(LEDMASK_TX); |
|
109 PulseMSRemaining.TxLEDPulse = TX_RX_LED_PULSE_MS; |
|
110 } |
|
111 |
|
112 /* Read bytes from the USART receive buffer into the USB IN endpoint */ |
|
113 while (BufferCount--) |
|
114 CDC_Device_SendByte(&VirtualSerial_CDC_Interface, RingBuffer_Remove(&USARTtoUSB_Buffer)); |
|
115 |
|
116 /* Turn off TX LED(s) once the TX pulse period has elapsed */ |
|
117 if (PulseMSRemaining.TxLEDPulse && !(--PulseMSRemaining.TxLEDPulse)) |
|
118 LEDs_TurnOffLEDs(LEDMASK_TX); |
|
119 |
|
120 /* Turn off RX LED(s) once the RX pulse period has elapsed */ |
|
121 if (PulseMSRemaining.RxLEDPulse && !(--PulseMSRemaining.RxLEDPulse)) |
|
122 LEDs_TurnOffLEDs(LEDMASK_RX); |
|
123 } |
|
124 |
|
125 /* Load the next byte from the USART transmit buffer into the USART */ |
|
126 if (!(RingBuffer_IsEmpty(&USBtoUSART_Buffer))) { |
|
127 Serial_TxByte(RingBuffer_Remove(&USBtoUSART_Buffer)); |
|
128 |
|
129 LEDs_TurnOnLEDs(LEDMASK_RX); |
|
130 PulseMSRemaining.RxLEDPulse = TX_RX_LED_PULSE_MS; |
|
131 } |
|
132 |
|
133 CDC_Device_USBTask(&VirtualSerial_CDC_Interface); |
|
134 USB_USBTask(); |
|
135 } |
|
136 } |
|
137 |
|
138 /** Configures the board hardware and chip peripherals for the demo's functionality. */ |
|
139 void SetupHardware(void) |
|
140 { |
|
141 /* Disable watchdog if enabled by bootloader/fuses */ |
|
142 MCUSR &= ~(1 << WDRF); |
|
143 wdt_disable(); |
|
144 |
|
145 /* Hardware Initialization */ |
|
146 Serial_Init(9600, false); |
|
147 LEDs_Init(); |
|
148 USB_Init(); |
|
149 |
|
150 /* Start the flush timer so that overflows occur rapidly to push received bytes to the USB interface */ |
|
151 TCCR0B = (1 << CS02); |
|
152 |
|
153 /* Pull target /RESET line high */ |
|
154 AVR_RESET_LINE_PORT |= AVR_RESET_LINE_MASK; |
|
155 AVR_RESET_LINE_DDR |= AVR_RESET_LINE_MASK; |
|
156 } |
|
157 |
|
158 /** Event handler for the library USB Configuration Changed event. */ |
|
159 void EVENT_USB_Device_ConfigurationChanged(void) |
|
160 { |
|
161 CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface); |
|
162 } |
|
163 |
|
164 /** Event handler for the library USB Unhandled Control Request event. */ |
|
165 void EVENT_USB_Device_UnhandledControlRequest(void) |
|
166 { |
|
167 CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface); |
|
168 } |
|
169 |
|
170 /** Event handler for the CDC Class driver Line Encoding Changed event. |
|
171 * |
|
172 * \param[in] CDCInterfaceInfo Pointer to the CDC class interface configuration structure being referenced |
|
173 */ |
|
174 void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) |
|
175 { |
|
176 uint8_t ConfigMask = 0; |
|
177 |
|
178 switch (CDCInterfaceInfo->State.LineEncoding.ParityType) |
|
179 { |
|
180 case CDC_PARITY_Odd: |
|
181 ConfigMask = ((1 << UPM11) | (1 << UPM10)); |
|
182 break; |
|
183 case CDC_PARITY_Even: |
|
184 ConfigMask = (1 << UPM11); |
|
185 break; |
|
186 } |
|
187 |
|
188 if (CDCInterfaceInfo->State.LineEncoding.CharFormat == CDC_LINEENCODING_TwoStopBits) |
|
189 ConfigMask |= (1 << USBS1); |
|
190 |
|
191 switch (CDCInterfaceInfo->State.LineEncoding.DataBits) |
|
192 { |
|
193 case 6: |
|
194 ConfigMask |= (1 << UCSZ10); |
|
195 break; |
|
196 case 7: |
|
197 ConfigMask |= (1 << UCSZ11); |
|
198 break; |
|
199 case 8: |
|
200 ConfigMask |= ((1 << UCSZ11) | (1 << UCSZ10)); |
|
201 break; |
|
202 } |
|
203 |
|
204 /* Must turn off USART before reconfiguring it, otherwise incorrect operation may occur */ |
|
205 UCSR1B = 0; |
|
206 UCSR1A = 0; |
|
207 UCSR1C = 0; |
|
208 |
|
209 /* Special case 57600 baud for compatibility with the ATmega328 bootloader. */ |
|
210 UBRR1 = (CDCInterfaceInfo->State.LineEncoding.BaudRateBPS == 57600) |
|
211 ? SERIAL_UBBRVAL(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS) |
|
212 : SERIAL_2X_UBBRVAL(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS); |
|
213 |
|
214 UCSR1C = ConfigMask; |
|
215 UCSR1A = (CDCInterfaceInfo->State.LineEncoding.BaudRateBPS == 57600) ? 0 : (1 << U2X1); |
|
216 UCSR1B = ((1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1)); |
|
217 } |
|
218 |
|
219 /** ISR to manage the reception of data from the serial port, placing received bytes into a circular buffer |
|
220 * for later transmission to the host. |
|
221 */ |
|
222 ISR(USART1_RX_vect, ISR_BLOCK) |
|
223 { |
|
224 uint8_t ReceivedByte = UDR1; |
|
225 |
|
226 if (USB_DeviceState == DEVICE_STATE_Configured) |
|
227 RingBuffer_Insert(&USARTtoUSB_Buffer, ReceivedByte); |
|
228 } |
|
229 |
|
230 /** Event handler for the CDC Class driver Host-to-Device Line Encoding Changed event. |
|
231 * |
|
232 * \param[in] CDCInterfaceInfo Pointer to the CDC class interface configuration structure being referenced |
|
233 */ |
|
234 void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) |
|
235 { |
|
236 bool CurrentDTRState = (CDCInterfaceInfo->State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR); |
|
237 |
|
238 if (CurrentDTRState) |
|
239 AVR_RESET_LINE_PORT &= ~AVR_RESET_LINE_MASK; |
|
240 else |
|
241 AVR_RESET_LINE_PORT |= AVR_RESET_LINE_MASK; |
|
242 } |