Added new EEPROM and FLASH buffer versions of the Endpoint and Pipe stream functions...
[pub/USBasp.git] / Demos / Device / LowLevel / CDC / CDC.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, and distribute this software
13 and its documentation for any purpose and without fee is hereby
14 granted, provided that the above copyright notice appear in all
15 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 CDC demo. This file contains the main tasks of the demo and
34 * is responsible for the initial application hardware configuration.
35 */
36
37 #include "CDC.h"
38
39 /* Globals: */
40 /** Contains the current baud rate and other settings of the virtual serial port. While this demo does not use
41 * the physical USART and thus does not use these settings, they must still be retained and returned to the host
42 * upon request or the host will assume the device is non-functional.
43 *
44 * These values are set by the host via a class-specific request, however they are not required to be used accurately.
45 * It is possible to completely ignore these value or use other settings as the host is completely unaware of the physical
46 * serial link characteristics and instead sends and receives data in endpoint streams.
47 */
48 CDC_Line_Coding_t LineCoding = { .BaudRateBPS = 9600,
49 .CharFormat = OneStopBit,
50 .ParityType = Parity_None,
51 .DataBits = 8 };
52
53 #if 0
54 /* NOTE: Here you can set up a standard stream using the created virtual serial port, so that the standard stream functions in
55 * <stdio.h> can be used on the virtual serial port (e.g. fprintf(&USBSerial, "Test"); to print a string).
56 */
57
58 static int CDC_putchar (char c, FILE *stream)
59 {
60 if (!(USB_IsConnected))
61 return -1;
62
63 Endpoint_SelectEndpoint(CDC_TX_EPNUM);
64 while (!(Endpoint_IsReadWriteAllowed()));
65 Endpoint_Write_Byte(c);
66 Endpoint_ClearIN();
67
68 return 0;
69 }
70
71 static int CDC_getchar (FILE *stream)
72 {
73 int c;
74
75 Endpoint_SelectEndpoint(CDC_RX_EPNUM);
76
77 for (;;)
78 {
79 if (!(USB_IsConnected))
80 return -1;
81
82 while (!(Endpoint_IsReadWriteAllowed()));
83
84 if (!(Endpoint_BytesInEndpoint()))
85 {
86 Endpoint_ClearOUT();
87 }
88 else
89 {
90 c = Endpoint_Read_Byte();
91 break;
92 }
93 }
94
95 return c;
96 }
97
98 static FILE USBSerial = FDEV_SETUP_STREAM(CDC_putchar, CDC_getchar, _FDEV_SETUP_RW);
99 #endif
100
101 /** Main program entry point. This routine contains the overall program flow, including initial
102 * setup of all components and the main program loop.
103 */
104 int main(void)
105 {
106 SetupHardware();
107
108 LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
109
110 for (;;)
111 {
112 CDC_Task();
113 USB_USBTask();
114 }
115 }
116
117 /** Configures the board hardware and chip peripherals for the demo's functionality. */
118 void SetupHardware(void)
119 {
120 /* Disable watchdog if enabled by bootloader/fuses */
121 MCUSR &= ~(1 << WDRF);
122 wdt_disable();
123
124 /* Disable clock division */
125 clock_prescale_set(clock_div_1);
126
127 /* Hardware Initialization */
128 Joystick_Init();
129 LEDs_Init();
130 USB_Init();
131 }
132
133 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
134 * starts the library USB task to begin the enumeration and USB management process.
135 */
136 void EVENT_USB_Connect(void)
137 {
138 /* Indicate USB enumerating */
139 LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
140 }
141
142 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
143 * the status LEDs and stops the USB management and CDC management tasks.
144 */
145 void EVENT_USB_Disconnect(void)
146 {
147 /* Indicate USB not ready */
148 LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
149 }
150
151 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
152 * of the USB device after enumeration - the device endpoints are configured and the CDC management task started.
153 */
154 void EVENT_USB_ConfigurationChanged(void)
155 {
156 /* Indicate USB connected and ready */
157 LEDs_SetAllLEDs(LEDMASK_USB_READY);
158
159 /* Setup CDC Notification, Rx and Tx Endpoints */
160 if (!(Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT,
161 ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE,
162 ENDPOINT_BANK_SINGLE)))
163 {
164 LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
165 }
166
167 if (!(Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK,
168 ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE,
169 ENDPOINT_BANK_SINGLE)))
170 {
171 LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
172 }
173
174 if (!(Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK,
175 ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE,
176 ENDPOINT_BANK_SINGLE)))
177 {
178 LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
179 }
180 }
181
182 /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
183 * control requests that are not handled internally by the USB library (including the CDC control commands,
184 * which are all issued via the control endpoint), so that they can be handled appropriately for the application.
185 */
186 void EVENT_USB_UnhandledControlPacket(void)
187 {
188 uint8_t* LineCodingData = (uint8_t*)&LineCoding;
189
190 /* Process CDC specific control requests */
191 switch (USB_ControlRequest.bRequest)
192 {
193 case REQ_GetLineEncoding:
194 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
195 {
196 /* Acknowledge the SETUP packet, ready for data transfer */
197 Endpoint_ClearSETUP();
198
199 /* Write the line coding data to the control endpoint */
200 Endpoint_Write_Control_Stream_LE(LineCodingData, sizeof(CDC_Line_Coding_t));
201
202 /* Finalize the stream transfer to send the last packet or clear the host abort */
203 Endpoint_ClearOUT();
204 }
205
206 break;
207 case REQ_SetLineEncoding:
208 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
209 {
210 /* Acknowledge the SETUP packet, ready for data transfer */
211 Endpoint_ClearSETUP();
212
213 /* Read the line coding data in from the host into the global struct */
214 Endpoint_Read_Control_Stream_LE(LineCodingData, sizeof(CDC_Line_Coding_t));
215
216 /* Finalize the stream transfer to clear the last packet from the host */
217 Endpoint_ClearIN();
218 }
219
220 break;
221 case REQ_SetControlLineState:
222 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
223 {
224 /* Acknowledge the SETUP packet, ready for data transfer */
225 Endpoint_ClearSETUP();
226
227 /* NOTE: Here you can read in the line state mask from the host, to get the current state of the output handshake
228 lines. The mask is read in from the wValue parameter in USB_ControlRequest, and can be masked against the
229 CONTROL_LINE_OUT_* masks to determine the RTS and DTR line states using the following code:
230 */
231
232 /* Acknowledge status stage */
233 while (!(Endpoint_IsINReady()));
234 Endpoint_ClearIN();
235 }
236
237 break;
238 }
239 }
240
241 /** Function to manage CDC data transmission and reception to and from the host. */
242 void CDC_Task(void)
243 {
244 char* ReportString = NULL;
245 uint8_t JoyStatus_LCL = Joystick_GetStatus();
246 static bool ActionSent = false;
247
248 char* JoystickStrings[] =
249 {
250 "Joystick Up\r\n",
251 "Joystick Down\r\n",
252 "Joystick Left\r\n",
253 "Joystick Right\r\n",
254 "Joystick Pressed\r\n",
255 };
256
257 #if 0
258 /* NOTE: Here you can use the notification endpoint to send back line state changes to the host, for the special RS-232
259 * handshake signal lines (and some error states), via the CONTROL_LINE_IN_* masks and the following code:
260 */
261 USB_Notification_Header_t Notification = (USB_Notification_Header_t)
262 {
263 .NotificationType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
264 .Notification = NOTIF_SerialState,
265 .wValue = 0,
266 .wIndex = 0,
267 .wLength = sizeof(uint16_t),
268 };
269
270 uint16_t LineStateMask;
271
272 // Set LineStateMask here to a mask of CONTROL_LINE_IN_* masks to set the input handshake line states to send to the host
273
274 Endpoint_SelectEndpoint(CDC_NOTIFICATION_EPNUM);
275 Endpoint_Write_Stream_LE(&Notification, sizeof(Notification));
276 Endpoint_Write_Stream_LE(&LineStateMask, sizeof(LineStateMask));
277 Endpoint_ClearIN();
278 #endif
279
280 /* Determine if a joystick action has occurred */
281 if (JoyStatus_LCL & JOY_UP)
282 ReportString = JoystickStrings[0];
283 else if (JoyStatus_LCL & JOY_DOWN)
284 ReportString = JoystickStrings[1];
285 else if (JoyStatus_LCL & JOY_LEFT)
286 ReportString = JoystickStrings[2];
287 else if (JoyStatus_LCL & JOY_RIGHT)
288 ReportString = JoystickStrings[3];
289 else if (JoyStatus_LCL & JOY_PRESS)
290 ReportString = JoystickStrings[4];
291
292 /* Flag management - Only allow one string to be sent per action */
293 if (ReportString == NULL)
294 {
295 ActionSent = false;
296 }
297 else if (ActionSent == false)
298 {
299 ActionSent = true;
300
301 /* Select the Serial Tx Endpoint */
302 Endpoint_SelectEndpoint(CDC_TX_EPNUM);
303
304 /* Write the String to the Endpoint */
305 Endpoint_Write_Stream_LE(ReportString, strlen(ReportString));
306
307 /* Remember if the packet to send completely fills the endpoint */
308 bool IsFull = (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE);
309
310 /* Finalize the stream transfer to send the last packet */
311 Endpoint_ClearIN();
312
313 /* If the last packet filled the endpoint, send an empty packet to release the buffer on
314 * the receiver (otherwise all data will be cached until a non-full packet is received) */
315 if (IsFull)
316 {
317 /* Wait until the endpoint is ready for another packet */
318 while (!(Endpoint_IsINReady()));
319
320 /* Send an empty packet to ensure that the host does not buffer data sent to it */
321 Endpoint_ClearIN();
322 }
323 }
324
325 /* Select the Serial Rx Endpoint */
326 Endpoint_SelectEndpoint(CDC_RX_EPNUM);
327
328 /* Throw away any received data from the host */
329 if (Endpoint_IsOUTReceived())
330 Endpoint_ClearOUT();
331 }