/*
LUFA Library
- Copyright (C) Dean Camera, 2010.
+ Copyright (C) Dean Camera, 2012.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+ Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
#include "USBtoSerial.h"
/** Circular buffer to hold data from the host before it is sent to the device via the serial port. */
-RingBuffer_t USBtoUSART_Buffer;
+static RingBuffer_t USBtoUSART_Buffer;
/** Underlying data buffer for \ref USBtoUSART_Buffer, where the stored bytes are located. */
-uint8_t USBtoUSART_Buffer_Data[128];
+static uint8_t USBtoUSART_Buffer_Data[128];
/** Circular buffer to hold data from the serial port before it is sent to the host. */
-RingBuffer_t USARTtoUSB_Buffer;
+static RingBuffer_t USARTtoUSB_Buffer;
/** Underlying data buffer for \ref USARTtoUSB_Buffer, where the stored bytes are located. */
-uint8_t USARTtoUSB_Buffer_Data[128];
-
+static uint8_t USARTtoUSB_Buffer_Data[128];
/** LUFA CDC Class driver interface configuration and state information. This structure is
* passed to all CDC Class driver functions, so that multiple instances of the same class
.Config =
{
.ControlInterfaceNumber = 0,
-
- .DataINEndpointNumber = CDC_TX_EPNUM,
- .DataINEndpointSize = CDC_TXRX_EPSIZE,
- .DataINEndpointDoubleBank = false,
-
- .DataOUTEndpointNumber = CDC_RX_EPNUM,
- .DataOUTEndpointSize = CDC_TXRX_EPSIZE,
- .DataOUTEndpointDoubleBank = false,
-
- .NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM,
- .NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE,
- .NotificationEndpointDoubleBank = false,
+ .DataINEndpoint =
+ {
+ .Address = CDC_TX_EPADDR,
+ .Size = CDC_TXRX_EPSIZE,
+ .Banks = 1,
+ },
+ .DataOUTEndpoint =
+ {
+ .Address = CDC_RX_EPADDR,
+ .Size = CDC_TXRX_EPSIZE,
+ .Banks = 1,
+ },
+ .NotificationEndpoint =
+ {
+ .Address = CDC_NOTIFICATION_EPADDR,
+ .Size = CDC_NOTIFICATION_EPSIZE,
+ .Banks = 1,
+ },
},
};
+
/** Main program entry point. This routine contains the overall program flow, including initial
* setup of all components and the main program loop.
*/
RingBuffer_InitBuffer(&USARTtoUSB_Buffer, USARTtoUSB_Buffer_Data, sizeof(USARTtoUSB_Buffer_Data));
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
- sei();
+ GlobalInterruptEnable();
for (;;)
{
if (!(ReceivedByte < 0))
RingBuffer_Insert(&USBtoUSART_Buffer, ReceivedByte);
}
-
+
/* Check if the UART receive buffer flush timer has expired or the buffer is nearly full */
uint16_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer);
- if ((TIFR0 & (1 << TOV0)) || (BufferCount > 200))
+ if ((TIFR0 & (1 << TOV0)) || (BufferCount > (uint8_t)(sizeof(USARTtoUSB_Buffer_Data) * .75)))
{
- /* Clear flush timer expiry flag */
- TIFR0 |= (1 << TOV0);
-
- /* Read bytes from the USART receive buffer into the USB IN endpoint */
- while (BufferCount--)
+ Endpoint_SelectEndpoint(VirtualSerial_CDC_Interface.Config.DataINEndpoint.Address);
+
+ /* Check if a packet is already enqueued to the host - if so, we shouldn't try to send more data
+ * until it completes as there is a chance nothing is listening and a lengthy timeout could occur */
+ if (Endpoint_IsINReady())
{
- /* Try to send the next byte of data to the host, abort if there is an error without dequeuing */
- if (CDC_Device_SendByte(&VirtualSerial_CDC_Interface,
- RingBuffer_Peek(&USARTtoUSB_Buffer)) != ENDPOINT_READYWAIT_NoError)
+ /* Clear flush timer expiry flag */
+ TIFR0 |= (1 << TOV0);
+
+ /* Never send more than one bank size less one byte to the host at a time, so that we don't block
+ * while a Zero Length Packet (ZLP) to terminate the transfer is sent if the host isn't listening */
+ uint8_t BytesToSend = MIN(BufferCount, (CDC_TXRX_EPSIZE - 1));
+
+ /* Read bytes from the USART receive buffer into the USB IN endpoint */
+ while (BytesToSend--)
{
- break;
+ /* Try to send the next byte of data to the host, abort if there is an error without dequeuing */
+ if (CDC_Device_SendByte(&VirtualSerial_CDC_Interface,
+ RingBuffer_Peek(&USARTtoUSB_Buffer)) != ENDPOINT_READYWAIT_NoError)
+ {
+ break;
+ }
+
+ /* Dequeue the already sent byte from the buffer now we have confirmed that no transmission error occurred */
+ RingBuffer_Remove(&USARTtoUSB_Buffer);
}
-
- /* Dequeue the already sent byte from the buffer now we have confirmed that no transmission error occurred */
- RingBuffer_Remove(&USARTtoUSB_Buffer);
}
}
/* Load the next byte from the USART transmit buffer into the USART */
if (!(RingBuffer_IsEmpty(&USBtoUSART_Buffer)))
- Serial_TxByte(RingBuffer_Remove(&USBtoUSART_Buffer));
+ Serial_SendByte(RingBuffer_Remove(&USBtoUSART_Buffer));
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
USB_USBTask();