aboutsummaryrefslogtreecommitdiffstats
path: root/Projects/XPLAINBridge
diff options
context:
space:
mode:
authorDean Camera <dean@fourwalledcubicle.com>2010-08-01 14:03:13 +0000
committerDean Camera <dean@fourwalledcubicle.com>2010-08-01 14:03:13 +0000
commitff09cf9c73bbc2623a8c1420918747840382cc5b (patch)
tree41967f96971d3e1ed2a00f5449f3c83b5a19eba3 /Projects/XPLAINBridge
parentfb0e6597b611731e31b5d1285e52fc81a5ffd559 (diff)
downloadlufa-ff09cf9c73bbc2623a8c1420918747840382cc5b.tar.gz
lufa-ff09cf9c73bbc2623a8c1420918747840382cc5b.tar.bz2
lufa-ff09cf9c73bbc2623a8c1420918747840382cc5b.zip
Fix XPLAINBridge project discarding characters from the USB interface due to a double read from the endpoint.
Make XPLAINBridge and USBtoSerial projects more reliable by forcing a flush if the UART-to-USB buffer becomes nearly full. Reduce locking in the LightweightRingBuffer.h header files by only locking on the update of the buffer count, and require insertions and removals from each buffer to occur in only one execution thread. Fix CDC_*_ReceiveByte() returning 0 when the interface is not configured, instead of the new -1 error value. Fix CDC_Host_ReceiveByte() not re-freezing the pipe if no packet has been received. Remove redundant Pipe token set commands in the CDC and RNDIS host class drivers.
Diffstat (limited to 'Projects/XPLAINBridge')
-rw-r--r--Projects/XPLAINBridge/Lib/LightweightRingBuff.h127
-rw-r--r--Projects/XPLAINBridge/Lib/SoftUART.c2
-rw-r--r--Projects/XPLAINBridge/XPLAINBridge.c18
3 files changed, 84 insertions, 63 deletions
diff --git a/Projects/XPLAINBridge/Lib/LightweightRingBuff.h b/Projects/XPLAINBridge/Lib/LightweightRingBuff.h
index 2faef4382..cb0f6112a 100644
--- a/Projects/XPLAINBridge/Lib/LightweightRingBuff.h
+++ b/Projects/XPLAINBridge/Lib/LightweightRingBuff.h
@@ -44,10 +44,19 @@
/* Defines: */
/** Size of each ring buffer, in data elements - must be between 1 and 255. */
- #define BUFFER_SIZE 255
+ #define BUFFER_SIZE 255
/** Type of data to store into the buffer. */
- #define RingBuff_Data_t uint8_t
+ #define RingBuff_Data_t uint8_t
+
+ /** Datatype which may be used to store the count of data stored in a buffer, retrieved
+ * via a call to \ref RingBuffer_GetCount().
+ */
+ #if (BUFFER_SIZE <= 0xFF)
+ #define RingBuff_Count_t uint8_t
+ #else
+ #define RingBuff_Count_t uint16_t
+ #endif
/* Type Defines: */
/** Type define for a new ring buffer object. Buffers should be initialized via a call to
@@ -58,11 +67,11 @@
RingBuff_Data_t Buffer[BUFFER_SIZE]; /**< Internal ring buffer data, referenced by the buffer pointers. */
RingBuff_Data_t* In; /**< Current storage location in the circular buffer */
RingBuff_Data_t* Out; /**< Current retrieval location in the circular buffer */
- uint8_t Count; /**< Total number of bytes stored in the circular buffer */
+ RingBuff_Count_t Count;
} RingBuff_t;
/* Inline Functions: */
- /** Initialises a ring buffer ready for use. Buffers must be initialized via this function
+ /** Initializes a ring buffer ready for use. Buffers must be initialized via this function
* before any operations are called upon them. Already initialized buffers may be reset
* by re-initializing them using this function.
*
@@ -70,75 +79,74 @@
*/
static inline void RingBuffer_InitBuffer(RingBuff_t* const Buffer)
{
- Buffer->In = Buffer->Buffer;
- Buffer->Out = Buffer->Buffer;
- Buffer->Count = 0;
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+ {
+ Buffer->In = Buffer->Buffer;
+ Buffer->Out = Buffer->Buffer;
+ }
}
- /** Atomically determines if the specified ring buffer contains any free space. This should
- * be tested before storing data to the buffer, to ensure that no data is lost due to a
- * buffer overrun.
+ /** Retrieves the minimum number of bytes stored in a particular buffer. This value is computed
+ * by entering an atomic lock on the buffer while the IN and OUT locations are fetched, so that
+ * the buffer cannot be modified while the computation takes place. This value should be cached
+ * when reading out the contents of the buffer, so that as small a time as possible is spent
+ * in an atomic lock.
*
- * \param[in,out] Buffer Pointer to a ring buffer structure to insert into
+ * \note The value returned by this function is guaranteed to only be the minimum number of bytes
+ * stored in the given buffer; this value may change as other threads write new data and so
+ * the returned number should be used only to determine how many successive reads may safely
+ * be performed on the buffer.
*
- * \return Boolean true if the buffer contains no free space, false otherwise
- */
- static inline bool RingBuffer_IsFull(RingBuff_t* const Buffer)
+ * \param[in] Buffer Pointer to a ring buffer structure whose count is to be computed
+ */
+ static inline RingBuff_Count_t RingBuffer_GetCount(RingBuff_t* const Buffer)
{
- bool IsFull;
+ RingBuff_Count_t Count;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
- IsFull = (Buffer->Count == BUFFER_SIZE);
+ Count = Buffer->Count;
}
- return IsFull;
+ return Count;
}
- /** Atomically inserts an element into the ring buffer.
+ /** Atomically determines if the specified ring buffer contains any free space. This should
+ * be tested before storing data to the buffer, to ensure that no data is lost due to a
+ * buffer overrun.
*
* \param[in,out] Buffer Pointer to a ring buffer structure to insert into
- * \param[in] Data Data element to insert into the buffer
- */
- static inline void RingBuffer_AtomicInsert(RingBuff_t* const Buffer,
- const RingBuff_Data_t Data)
+ *
+ * \return Boolean true if the buffer contains no free space, false otherwise
+ */
+ static inline bool RingBuffer_IsFull(RingBuff_t* const Buffer)
{
- ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
- {
- *Buffer->In = Data;
-
- if (++Buffer->In == &Buffer->Buffer[BUFFER_SIZE])
- Buffer->In = Buffer->Buffer;
-
- Buffer->Count++;
- }
+ return (RingBuffer_GetCount(Buffer) == BUFFER_SIZE);
}
- /** Atomically retrieves an element from the ring buffer.
+ /** Atomically determines if the specified ring buffer contains any data. This should
+ * be tested before removing data from the buffer, to ensure that the buffer does not
+ * underflow.
*
- * \param[in,out] Buffer Pointer to a ring buffer structure to retrieve from
+ * If the data is to be removed in a loop, store the total number of bytes stored in the
+ * buffer (via a call to the \ref RingBuffer_GetCount() function) in a temporary variable
+ * to reduce the time spent in atomicity locks.
*
- * \return Next data element stored in the buffer
- */
- static inline RingBuff_Data_t RingBuffer_AtomicRemove(RingBuff_t* const Buffer)
+ * \param[in,out] Buffer Pointer to a ring buffer structure to insert into
+ *
+ * \return Boolean true if the buffer contains no free space, false otherwise
+ */
+ static inline bool RingBuffer_IsEmpty(RingBuff_t* const Buffer)
{
- RingBuff_Data_t Data;
-
- ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
- {
- Data = *Buffer->Out;
-
- if (++Buffer->Out == &Buffer->Buffer[BUFFER_SIZE])
- Buffer->Out = Buffer->Buffer;
-
- Buffer->Count--;
- }
-
- return Data;
+ return (RingBuffer_GetCount(Buffer) == 0);
}
/** Inserts an element into the ring buffer.
*
+ * \note Only one execution thread (main program thread or an ISR) may insert into a single buffer
+ * otherwise data corruption may occur. Insertion and removal may occur from different execution
+ * threads.
+ *
* \param[in,out] Buffer Pointer to a ring buffer structure to insert into
* \param[in] Data Data element to insert into the buffer
*/
@@ -149,11 +157,18 @@
if (++Buffer->In == &Buffer->Buffer[BUFFER_SIZE])
Buffer->In = Buffer->Buffer;
-
- Buffer->Count++;
+
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+ {
+ Buffer->Count++;
+ }
}
- /** Retrieves an element from the ring buffer.
+ /** Removes an element from the ring buffer.
+ *
+ * \note Only one execution thread (main program thread or an ISR) may remove from a single buffer
+ * otherwise data corruption may occur. Insertion and removal may occur from different execution
+ * threads.
*
* \param[in,out] Buffer Pointer to a ring buffer structure to retrieve from
*
@@ -165,11 +180,13 @@
if (++Buffer->Out == &Buffer->Buffer[BUFFER_SIZE])
Buffer->Out = Buffer->Buffer;
-
- Buffer->Count--;
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+ {
+ Buffer->Count--;
+ }
+
return Data;
}
#endif
-
diff --git a/Projects/XPLAINBridge/Lib/SoftUART.c b/Projects/XPLAINBridge/Lib/SoftUART.c
index 05dd8a4b5..b96b45f4d 100644
--- a/Projects/XPLAINBridge/Lib/SoftUART.c
+++ b/Projects/XPLAINBridge/Lib/SoftUART.c
@@ -140,7 +140,7 @@ ISR(TIMER3_COMPA_vect, ISR_BLOCK)
TX_Data >>= 1;
TX_BitsRemaining--;
}
- else if (USBtoUART_Buffer.Count && !(RX_BitsRemaining))
+ else if (!(RX_BitsRemaining) && !(RingBuffer_IsEmpty(&USBtoUART_Buffer)))
{
/* Start bit - TX line low */
STXPORT &= ~(1 << STX);
diff --git a/Projects/XPLAINBridge/XPLAINBridge.c b/Projects/XPLAINBridge/XPLAINBridge.c
index 7272fd825..f02fe9bad 100644
--- a/Projects/XPLAINBridge/XPLAINBridge.c
+++ b/Projects/XPLAINBridge/XPLAINBridge.c
@@ -36,8 +36,8 @@
#include "XPLAINBridge.h"
-/* Current firmware mode, making the device behave as either a programmer or a USART bridge */
-bool CurrentFirmwareMode = MODE_PDI_PROGRAMMER;
+/** Current firmware mode, making the device behave as either a programmer or a USART bridge */
+bool CurrentFirmwareMode = MODE_USART_BRIDGE;
/** 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
@@ -122,16 +122,17 @@ void UARTBridge_Task(void)
/* Read bytes from the USB OUT endpoint into the UART transmit buffer */
int16_t ReceivedByte = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
if (!(ReceivedByte < 0) && !(RingBuffer_IsFull(&USBtoUART_Buffer)))
- RingBuffer_AtomicInsert(&USBtoUART_Buffer, CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface));
+ RingBuffer_Insert(&USBtoUART_Buffer, ReceivedByte);
- /* Check if the UART receive buffer flush timer has expired */
- if (TIFR0 & (1 << TOV0))
+ /* Check if the UART receive buffer flush timer has expired or buffer is nearly full */
+ RingBuff_Count_t BufferCount = RingBuffer_GetCount(&UARTtoUSB_Buffer);
+ if ((TIFR0 & (1 << TOV0)) || (BufferCount > 200))
{
TIFR0 |= (1 << TOV0);
/* Read bytes from the UART receive buffer into the USB IN endpoint */
- while (UARTtoUSB_Buffer.Count)
- CDC_Device_SendByte(&VirtualSerial_CDC_Interface, RingBuffer_AtomicRemove(&UARTtoUSB_Buffer));
+ while (BufferCount--)
+ CDC_Device_SendByte(&VirtualSerial_CDC_Interface, RingBuffer_Remove(&UARTtoUSB_Buffer));
}
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
@@ -184,6 +185,9 @@ void EVENT_USB_Device_ConfigurationChanged(void)
/* Initialize ring buffers used to hold serial data between USB and software UART interfaces */
RingBuffer_InitBuffer(&USBtoUART_Buffer);
RingBuffer_InitBuffer(&UARTtoUSB_Buffer);
+
+ /* Start the software USART */
+ SoftUART_Init();
}
else
{