diff options
author | Dean Camera <dean@fourwalledcubicle.com> | 2010-08-01 14:03:13 +0000 |
---|---|---|
committer | Dean Camera <dean@fourwalledcubicle.com> | 2010-08-01 14:03:13 +0000 |
commit | ff09cf9c73bbc2623a8c1420918747840382cc5b (patch) | |
tree | 41967f96971d3e1ed2a00f5449f3c83b5a19eba3 | |
parent | fb0e6597b611731e31b5d1285e52fc81a5ffd559 (diff) | |
download | lufa-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.
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/CDC.c | 21 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/CDC.h | 2 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/CDC.c | 28 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/CDC.h | 2 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/RNDIS.c | 6 | ||||
-rw-r--r-- | LUFA/ManPages/LUFAPoweredProjects.txt | 1 | ||||
-rw-r--r-- | Projects/Benito/Benito.c | 9 | ||||
-rw-r--r-- | Projects/Benito/Lib/LightweightRingBuff.h | 127 | ||||
-rw-r--r-- | Projects/USBtoSerial/Lib/LightweightRingBuff.h | 127 | ||||
-rw-r--r-- | Projects/USBtoSerial/USBtoSerial.c | 15 | ||||
-rw-r--r-- | Projects/XPLAINBridge/Lib/LightweightRingBuff.h | 127 | ||||
-rw-r--r-- | Projects/XPLAINBridge/Lib/SoftUART.c | 2 | ||||
-rw-r--r-- | Projects/XPLAINBridge/XPLAINBridge.c | 18 |
13 files changed, 269 insertions, 216 deletions
diff --git a/LUFA/Drivers/USB/Class/Device/CDC.c b/LUFA/Drivers/USB/Class/Device/CDC.c index 026ac269a..39154608e 100644 --- a/LUFA/Drivers/USB/Class/Device/CDC.c +++ b/LUFA/Drivers/USB/Class/Device/CDC.c @@ -133,7 +133,7 @@ void CDC_Device_USBTask(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) } uint8_t CDC_Device_SendString(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, - char* const Data, + const char* const Data, const uint16_t Length) { if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) @@ -219,20 +219,21 @@ uint16_t CDC_Device_BytesReceived(USB_ClassInfo_CDC_Device_t* const CDCInterface int16_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) { - uint8_t ReceivedByte = -1; - if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) - return 0; + return -1; + + int16_t ReceivedByte = -1; Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataOUTEndpointNumber); - if (!(Endpoint_IsOUTReceived())) - return -1; - else if (Endpoint_BytesInEndpoint()) - ReceivedByte = Endpoint_Read_Byte(); + if (Endpoint_IsOUTReceived()) + { + if (Endpoint_BytesInEndpoint()) + ReceivedByte = Endpoint_Read_Byte(); - if (!(Endpoint_BytesInEndpoint())) - Endpoint_ClearOUT(); + if (!(Endpoint_BytesInEndpoint())) + Endpoint_ClearOUT(); + } return ReceivedByte; } diff --git a/LUFA/Drivers/USB/Class/Device/CDC.h b/LUFA/Drivers/USB/Class/Device/CDC.h index 3ada8f7af..1b0b86810 100644 --- a/LUFA/Drivers/USB/Class/Device/CDC.h +++ b/LUFA/Drivers/USB/Class/Device/CDC.h @@ -214,7 +214,7 @@ * \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum. */ uint8_t CDC_Device_SendString(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, - char* const Data, + const char* const Data, const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); /** Sends a given byte to the attached USB host, if connected. If a host is not connected when the function is called, the diff --git a/LUFA/Drivers/USB/Class/Host/CDC.c b/LUFA/Drivers/USB/Class/Host/CDC.c index 5fb232c09..b9e4c9ebf 100644 --- a/LUFA/Drivers/USB/Class/Host/CDC.c +++ b/LUFA/Drivers/USB/Class/Host/CDC.c @@ -205,7 +205,6 @@ void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) return; Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipeNumber); - Pipe_SetPipeToken(PIPE_TOKEN_IN); Pipe_Unfreeze(); if (Pipe_IsINReceived()) @@ -285,7 +284,7 @@ uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, } uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, - char* const Data, + const char* const Data, const uint16_t Length) { if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive)) @@ -333,7 +332,6 @@ uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo return 0; Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber); - Pipe_SetPipeToken(PIPE_TOKEN_IN); Pipe_Unfreeze(); if (Pipe_IsINReceived()) @@ -360,25 +358,25 @@ uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) { - uint8_t ReceivedByte = -1; - if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive)) - return 0; + return -1; + int16_t ReceivedByte = -1; + Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber); - Pipe_SetPipeToken(PIPE_TOKEN_IN); Pipe_Unfreeze(); - if (!(Pipe_IsINReceived())) - return -1; - else if (Pipe_BytesInPipe()) - ReceivedByte = Pipe_Read_Byte(); + if (Pipe_IsINReceived()) + { + if (Pipe_BytesInPipe()) + ReceivedByte = Pipe_Read_Byte(); - if (!(Pipe_BytesInPipe())) - Pipe_ClearIN(); - - Pipe_Freeze(); + if (!(Pipe_BytesInPipe())) + Pipe_ClearIN(); + } + Pipe_Freeze(); + return ReceivedByte; } diff --git a/LUFA/Drivers/USB/Class/Host/CDC.h b/LUFA/Drivers/USB/Class/Host/CDC.h index 56bcf3147..3e9d055e4 100644 --- a/LUFA/Drivers/USB/Class/Host/CDC.h +++ b/LUFA/Drivers/USB/Class/Host/CDC.h @@ -217,7 +217,7 @@ * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum. */ uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, - char* const Data, + const char* const Data, const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); /** Sends a given byte to the attached USB device, if connected. If a device is not connected when the function is called, the diff --git a/LUFA/Drivers/USB/Class/Host/RNDIS.c b/LUFA/Drivers/USB/Class/Host/RNDIS.c index b189535f0..cddd5cbb5 100644 --- a/LUFA/Drivers/USB/Class/Host/RNDIS.c +++ b/LUFA/Drivers/USB/Class/Host/RNDIS.c @@ -386,12 +386,9 @@ bool RNDIS_Host_IsPacketReceived(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfac return false; Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipeNumber); - Pipe_SetPipeToken(PIPE_TOKEN_IN); Pipe_Unfreeze(); - - PacketWaiting = Pipe_IsINReceived(); - + PacketWaiting = Pipe_IsINReceived(); Pipe_Freeze(); return PacketWaiting; @@ -407,7 +404,6 @@ uint8_t RNDIS_Host_ReadPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceIn return PIPE_READYWAIT_DeviceDisconnected; Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipeNumber); - Pipe_SetPipeToken(PIPE_TOKEN_IN); Pipe_Unfreeze(); if (!(Pipe_IsReadWriteAllowed())) diff --git a/LUFA/ManPages/LUFAPoweredProjects.txt b/LUFA/ManPages/LUFAPoweredProjects.txt index bc3935302..abb0e02dd 100644 --- a/LUFA/ManPages/LUFAPoweredProjects.txt +++ b/LUFA/ManPages/LUFAPoweredProjects.txt @@ -61,6 +61,7 @@ * - SD Card reader: http://elasticsheep.com/2010/04/teensy2-usb-mass-storage-with-an-sd-card/ * - SEGA Megadrive/Genesis Development Cartridge: http://www.makestuff.eu/wordpress/?page_id=398 * - Stripe Snoop, a Magnetic Card reader: http://www.ossguy.com/ss_usb/ + * - Touchscreen Input Device: http://capnstech.blogspot.com/2010/07/touchscreen-update.html * - USB Interface for Playstation Portable Devices: http://forums.ps2dev.org/viewtopic.php?t=11001 * - Userial, a USB to Serial converter with SPI, I2C and other protocols: http://www.tty1.net/userial/ * - XUM1541, a Commodore 64 floppy drive to USB adapter: http://www.root.org/~nate/c64/xum1541/ diff --git a/Projects/Benito/Benito.c b/Projects/Benito/Benito.c index ac1e064d5..88005eeb0 100644 --- a/Projects/Benito/Benito.c +++ b/Projects/Benito/Benito.c @@ -127,13 +127,14 @@ int main(void) LEDs_TurnOffLEDs(LEDMASK_RX); /* Check if the receive buffer flush period has expired */ - if (!(--FlushPeriodRemaining) || (Tx_Buffer.Count > 200)) + RingBuff_Count_t BufferCount = RingBuffer_GetCount(&Tx_Buffer); + if (!(--FlushPeriodRemaining) || (BufferCount > 200)) { /* Echo bytes from the target to the host via the virtual serial port */ - if (Tx_Buffer.Count) + if (BufferCount) { - while (Tx_Buffer.Count) - CDC_Device_SendByte(&VirtualSerial_CDC_Interface, RingBuffer_AtomicRemove(&Tx_Buffer)); + while (BufferCount--) + CDC_Device_SendByte(&VirtualSerial_CDC_Interface, RingBuffer_Remove(&Tx_Buffer)); LEDs_TurnOnLEDs(LEDMASK_RX); PulseMSRemaining.RxLEDPulse = TX_RX_LED_PULSE_MS; diff --git a/Projects/Benito/Lib/LightweightRingBuff.h b/Projects/Benito/Lib/LightweightRingBuff.h index 2faef4382..cb0f6112a 100644 --- a/Projects/Benito/Lib/LightweightRingBuff.h +++ b/Projects/Benito/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/USBtoSerial/Lib/LightweightRingBuff.h b/Projects/USBtoSerial/Lib/LightweightRingBuff.h index 2faef4382..cb0f6112a 100644 --- a/Projects/USBtoSerial/Lib/LightweightRingBuff.h +++ b/Projects/USBtoSerial/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/USBtoSerial/USBtoSerial.c b/Projects/USBtoSerial/USBtoSerial.c index 4f3fcf524..c2ecc7cf4 100644 --- a/Projects/USBtoSerial/USBtoSerial.c +++ b/Projects/USBtoSerial/USBtoSerial.c @@ -84,21 +84,22 @@ int main(void) /* Read bytes from the USB OUT endpoint into the USART transmit buffer */ int16_t ReceivedByte = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); if (!(ReceivedByte < 0) && !(RingBuffer_IsFull(&USBtoUSART_Buffer))) - RingBuffer_AtomicInsert(&USBtoUSART_Buffer, (uint8_t)ReceivedByte); + RingBuffer_Insert(&USBtoUSART_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 the buffer is nearly full */ + RingBuff_Count_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer); + if ((TIFR0 & (1 << TOV0)) || (BufferCount > 200)) { TIFR0 |= (1 << TOV0); /* Read bytes from the USART receive buffer into the USB IN endpoint */ - while (USARTtoUSB_Buffer.Count) - CDC_Device_SendByte(&VirtualSerial_CDC_Interface, RingBuffer_AtomicRemove(&USARTtoUSB_Buffer)); + while (BufferCount--) + CDC_Device_SendByte(&VirtualSerial_CDC_Interface, RingBuffer_Remove(&USARTtoUSB_Buffer)); } /* Load the next byte from the USART transmit buffer into the USART */ - if (USBtoUSART_Buffer.Count) - Serial_TxByte(RingBuffer_AtomicRemove(&USBtoUSART_Buffer)); + if (!(RingBuffer_IsEmpty(&USBtoUSART_Buffer))) + Serial_TxByte(RingBuffer_Remove(&USBtoUSART_Buffer)); CDC_Device_USBTask(&VirtualSerial_CDC_Interface); USB_USBTask(); 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 { |