diff --git a/LUFA/Drivers/USB/Class/Device/CDC.c b/LUFA/Drivers/USB/Class/Device/CDC.c index 026ac269af..39154608e4 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 3ada8f7afb..1b0b86810a 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 5fb232c099..b9e4c9ebfe 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 56bcf31477..3e9d055e45 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 b189535f00..cddd5cbb58 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 bc3935302a..abb0e02ddd 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 ac1e064d58..88005eeb0a 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 2faef43828..cb0f6112a2 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,74 +79,73 @@ */ 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 2faef43828..cb0f6112a2 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,74 +79,73 @@ */ 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 4f3fcf524d..c2ecc7cf4b 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 2faef43828..cb0f6112a2 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,74 +79,73 @@ */ 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 05dd8a4b51..b96b45f4d0 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 7272fd8256..f02fe9bade 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 {