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
+ typedef 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
+ } PulseMS ;
52
+
53
+ volatile PulseMS PulseMSRemaining ;
54
+
55
+ volatile uint8_t DTRGuard = 0x00 ;
56
+
57
+ /** LUFA CDC Class driver interface configuration and state information. This structure is
58
+ * passed to all CDC Class driver functions, so that multiple instances of the same class
59
+ * within a device can be differentiated from one another.
60
+ */
61
+ USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface =
62
+ {
63
+ .Config =
64
+ {
65
+ .ControlInterfaceNumber = 0 ,
66
+
67
+ .DataINEndpointNumber = CDC_TX_EPNUM ,
68
+ .DataINEndpointSize = CDC_TXRX_EPSIZE ,
69
+ .DataINEndpointDoubleBank = false,
70
+
71
+ .DataOUTEndpointNumber = CDC_RX_EPNUM ,
72
+ .DataOUTEndpointSize = CDC_TXRX_EPSIZE ,
73
+ .DataOUTEndpointDoubleBank = false,
74
+
75
+ .NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM ,
76
+ .NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE ,
77
+ .NotificationEndpointDoubleBank = false,
78
+ },
79
+ };
80
+
81
+ /** Main program entry point. This routine contains the overall program flow, including initial
82
+ * setup of all components and the main program loop.
83
+ */
84
+ int main (void )
85
+ {
86
+ SetupHardware ();
87
+
88
+ RingBuffer_InitBuffer (& USBtoUSART_Buffer );
89
+ RingBuffer_InitBuffer (& USARTtoUSB_Buffer );
90
+
91
+ // Size optimization (may speed up as well): Make the adresses local
92
+ PulseMS * PulseMSRemainingPtr = & PulseMSRemaining ;
93
+ uint8_t * DTRGuardPtr = & DTRGuard ;
94
+ sei ();
95
+
96
+ for (;;)
97
+ {
98
+ /* Only try to read in bytes from the CDC interface if the transmit buffer is not full */
99
+ if (!(RingBuffer_IsFull (& USBtoUSART_Buffer )))
100
+ {
101
+ int16_t ReceivedByte = CDC_Device_ReceiveByte (& VirtualSerial_CDC_Interface );
102
+
103
+ /* Read bytes from the USB OUT endpoint into the USART transmit buffer */
104
+ if (!(ReceivedByte < 0 ))
105
+ RingBuffer_Insert (& USBtoUSART_Buffer , ReceivedByte );
106
+ }
107
+
108
+ /* Check if the UART receive buffer flush timer has expired or the buffer is nearly full */
109
+ RingBuff_Count_t BufferCount = RingBuffer_GetCount (& USARTtoUSB_Buffer );
110
+ if ((TIFR0 & (1 << TOV0 )) || (BufferCount > BUFFER_NEARLY_FULL ))
111
+ {
112
+ TIFR0 |= (1 << TOV0 );
113
+
114
+ if (* DTRGuardPtr < 0xff )
115
+ (* DTRGuardPtr )++ ;
116
+
117
+ if (USARTtoUSB_Buffer .Count ) {
118
+ LEDs_TurnOnLEDs (LEDMASK_TX );
119
+ PulseMSRemainingPtr -> TxLEDPulse = TX_RX_LED_PULSE_MS ;
120
+ }
121
+
122
+ /* Read bytes from the USART receive buffer into the USB IN endpoint */
123
+ while (BufferCount -- )
124
+ CDC_Device_SendByte (& VirtualSerial_CDC_Interface , RingBuffer_Remove (& USARTtoUSB_Buffer ));
125
+
126
+ /* Turn off TX LED(s) once the TX pulse period has elapsed */
127
+ if (PulseMSRemainingPtr -> TxLEDPulse && !(-- PulseMSRemainingPtr -> TxLEDPulse ))
128
+ LEDs_TurnOffLEDs (LEDMASK_TX );
129
+
130
+ /* Turn off RX LED(s) once the RX pulse period has elapsed */
131
+ if (PulseMSRemainingPtr -> RxLEDPulse && !(-- PulseMSRemainingPtr -> RxLEDPulse ))
132
+ LEDs_TurnOffLEDs (LEDMASK_RX );
133
+ }
134
+
135
+ /* Load the next byte from the USART transmit buffer into the USART */
136
+ if (!(RingBuffer_IsEmpty (& USBtoUSART_Buffer ))) {
137
+ Serial_TxByte (RingBuffer_Remove (& USBtoUSART_Buffer ));
138
+
139
+ LEDs_TurnOnLEDs (LEDMASK_RX );
140
+ PulseMSRemainingPtr -> RxLEDPulse = TX_RX_LED_PULSE_MS ;
141
+ }
142
+
143
+ CDC_Device_USBTask (& VirtualSerial_CDC_Interface );
144
+ USB_USBTask ();
145
+ }
146
+ }
147
+
148
+ /** Configures the board hardware and chip peripherals for the demo's functionality. */
149
+ void SetupHardware (void )
150
+ {
151
+ /* Disable watchdog if enabled by bootloader/fuses */
152
+ MCUSR &= ~(1 << WDRF );
153
+ wdt_disable ();
154
+
155
+ /* Hardware Initialization */
156
+ Serial_Init (9600 , false);
157
+ LEDs_Init ();
158
+ USB_Init ();
159
+
160
+ /* Set PD4 to Hi-z/input to enable charge controller */
161
+ DDRD & ~(0x01 << 4 );
162
+ PORTD & ~(0x01 << 4 );
163
+
164
+ /* Start the flush timer so that overflows occur rapidly to push received bytes to the USB interface */
165
+ TCCR0B = (1 << CS02 );
166
+
167
+ /* Pull target /RESET line high */
168
+ AVR_RESET_LINE_PORT &= ~AVR_RESET_LINE_MASK ;
169
+ AVR_RESET_LINE_DDR |= AVR_RESET_LINE_MASK ;
170
+ }
171
+
172
+ /** Event handler for the library USB Configuration Changed event. */
173
+ void EVENT_USB_Device_ConfigurationChanged (void )
174
+ {
175
+ CDC_Device_ConfigureEndpoints (& VirtualSerial_CDC_Interface );
176
+ }
177
+
178
+ /** Event handler for the library USB Unhandled Control Request event. */
179
+ void EVENT_USB_Device_UnhandledControlRequest (void )
180
+ {
181
+ CDC_Device_ProcessControlRequest (& VirtualSerial_CDC_Interface );
182
+ }
183
+
184
+ /** Event handler for the CDC Class driver Line Encoding Changed event.
185
+ *
186
+ * \param[in] CDCInterfaceInfo Pointer to the CDC class interface configuration structure being referenced
187
+ */
188
+ void EVENT_CDC_Device_LineEncodingChanged (USB_ClassInfo_CDC_Device_t * const CDCInterfaceInfo )
189
+ {
190
+ uint8_t ConfigMask = 0 ;
191
+
192
+ switch (CDCInterfaceInfo -> State .LineEncoding .ParityType )
193
+ {
194
+ case CDC_PARITY_Odd :
195
+ ConfigMask = ((1 << UPM11 ) | (1 << UPM10 ));
196
+ break ;
197
+ case CDC_PARITY_Even :
198
+ ConfigMask = (1 << UPM11 );
199
+ break ;
200
+ }
201
+
202
+ if (CDCInterfaceInfo -> State .LineEncoding .CharFormat == CDC_LINEENCODING_TwoStopBits )
203
+ ConfigMask |= (1 << USBS1 );
204
+
205
+ switch (CDCInterfaceInfo -> State .LineEncoding .DataBits )
206
+ {
207
+ case 6 :
208
+ ConfigMask |= (1 << UCSZ10 );
209
+ break ;
210
+ case 7 :
211
+ ConfigMask |= (1 << UCSZ11 );
212
+ break ;
213
+ case 8 :
214
+ ConfigMask |= ((1 << UCSZ11 ) | (1 << UCSZ10 ));
215
+ break ;
216
+ }
217
+
218
+ /* Must turn off USART before reconfiguring it, otherwise incorrect operation may occur */
219
+ UCSR1B = 0 ;
220
+ UCSR1A = 0 ;
221
+ UCSR1C = 0 ;
222
+
223
+ /* Special case 57600 baud for compatibility with the ATmega328 bootloader. */
224
+ UBRR1 = (CDCInterfaceInfo -> State .LineEncoding .BaudRateBPS == 57600 )
225
+ ? SERIAL_UBBRVAL (CDCInterfaceInfo -> State .LineEncoding .BaudRateBPS )
226
+ : SERIAL_2X_UBBRVAL (CDCInterfaceInfo -> State .LineEncoding .BaudRateBPS );
227
+
228
+ UCSR1C = ConfigMask ;
229
+ UCSR1A = (CDCInterfaceInfo -> State .LineEncoding .BaudRateBPS == 57600 ) ? 0 : (1 << U2X1 );
230
+ UCSR1B = ((1 << RXCIE1 ) | (1 << TXEN1 ) | (1 << RXEN1 ));
231
+ }
232
+
233
+ /** ISR to manage the reception of data from the serial port, placing received bytes into a circular buffer
234
+ * for later transmission to the host.
235
+ */
236
+ ISR (USART1_RX_vect , ISR_BLOCK )
237
+ {
238
+ uint8_t ReceivedByte = UDR1 ;
239
+
240
+ if (USB_DeviceState == DEVICE_STATE_Configured )
241
+ RingBuffer_Insert (& USARTtoUSB_Buffer , ReceivedByte );
242
+ }
243
+
244
+ /** Event handler for the CDC Class driver Host-to-Device Line Encoding Changed event.
245
+ *
246
+ * \param[in] CDCInterfaceInfo Pointer to the CDC class interface configuration structure being referenced
247
+ */
248
+ void EVENT_CDC_Device_ControLineStateChanged (USB_ClassInfo_CDC_Device_t * const CDCInterfaceInfo )
249
+ {
250
+ bool CurrentDTRState = (CDCInterfaceInfo -> State .ControlLineStates .HostToDevice & CDC_CONTROL_LINE_OUT_DTR );
251
+ uint8_t * DTRGuardTemp = & DTRGuard ;
252
+
253
+ if (CurrentDTRState ) {
254
+ AVR_RESET_LINE_PORT &= ~AVR_RESET_LINE_MASK ;
255
+ * DTRGuardTemp = 0x00 ;
256
+ }
257
+ else {
258
+ if (* DTRGuardTemp > 0x60 && * DTRGuardTemp < 0xFF )
259
+ AVR_RESET_LINE_PORT |= AVR_RESET_LINE_MASK ;
260
+ }
261
+ }
0 commit comments