//***************************************************************************** // //! Writes data to a ring buffer. //! //! \param psUSBRingBuf points to the ring buffer to be written to. //! \param pui8Data points to the data to be written. //! \param ui32Length is the number of bytes to be written. //! //! This function write a sequence of bytes into a ring buffer. //! //! \return None. // //***************************************************************************** void USBRingBufWrite(tUSBRingBufObject *psUSBRingBuf, const uint8_t *pui8Data, uint32_t ui32Length) { uint32_t ui32Temp; // // Check the arguments. // ASSERT(psUSBRingBuf != NULL); ASSERT(pui8Data != NULL); ASSERT(ui32Length != 0); // // Verify that space is available in the buffer. // ASSERT(ui32Length <= USBRingBufFree(psUSBRingBuf)); // // Write the data into the ring buffer. // for(ui32Temp = 0; ui32Temp < ui32Length; ui32Temp++) { USBRingBufWriteOne(psUSBRingBuf, pui8Data[ui32Temp]); } }
//***************************************************************************** // //! Writes data to a ring buffer. //! //! \param ptUSBRingBuf points to the ring buffer to be written to. //! \param pucData points to the data to be written. //! \param ulLength is the number of bytes to be written. //! //! This function write a sequence of bytes into a ring buffer. //! //! \return None. // //***************************************************************************** void USBRingBufWrite(tUSBRingBufObject *ptUSBRingBuf, const unsigned char *pucData, unsigned long ulLength) { unsigned long ulTemp; // // Check the arguments. // ASSERT(ptUSBRingBuf != NULL); ASSERT(pucData != NULL); ASSERT(ulLength != 0); // // Verify that space is available in the buffer. // ASSERT(ulLength <= USBRingBufFree(ptUSBRingBuf)); // // Write the data into the ring buffer. // for(ulTemp = 0; ulTemp < ulLength; ulTemp++) { USBRingBufWriteOne(ptUSBRingBuf, pucData[ulTemp]); } }
//***************************************************************************** // //! Writes a block of data to the transmit buffer and queues it for //! transmission to the USB controller. //! //! \param psBuffer points to the pointer instance into which data is to be //! written. //! \param pucData points to the first byte of data which is to be written. //! \param ulLength is the number of bytes of data to write to the buffer. //! //! This function copies the supplied data into the transmit buffer. The //! transmit buffer data will be packetized according to the constraints //! imposed by the lower layer in use and sent to the USB controller as soon as //! possible. Once a packet is transmitted and acknowledged, a //! \b USB_EVENT_TX_COMPLETE event will be sent to the application callback //! indicating the number of bytes that have been sent from the buffer. //! //! Attempts to send more data than there is space for in the transmit buffer //! will result in fewer bytes than expected being written. The value returned //! by the function indicates the actual number of bytes copied to the buffer. //! //! \return Returns the number of bytes actually written. // //***************************************************************************** unsigned long USBBufferWrite(const tUSBBuffer *psBuffer, const unsigned char *pucData, unsigned long ulLength) { unsigned long ulSpace; tUSBBufferVars *psVars; // // Check parameter validity. // ASSERT(psBuffer && pucData); ASSERT(psBuffer->bTransmitBuffer == true); // // Get our workspace variables. // psVars = psBuffer->pvWorkspace; // // How much space is left in the buffer? // ulSpace = USBRingBufFree(&psVars->sRingBuf); // // How many bytes will we write? // ulLength = (ulLength > ulSpace) ? ulSpace : ulLength; // // Write the data to the buffer. // if(ulLength) { USBRingBufWrite(&psVars->sRingBuf, pucData, ulLength); } // // Try to transmit the next packet to the host. // ScheduleNextTransmission(psBuffer); // // Tell the caller how many bytes we wrote to the buffer. // return(ulLength); }
//***************************************************************************** // //! Writes a block of data to the transmit buffer and queues it for //! transmission to the USB controller. //! //! \param psBuffer points to the pointer instance into which data is to be //! written. //! \param pui8Data points to the first byte of data which is to be written. //! \param ui32Length is the number of bytes of data to write to the buffer. //! //! This function copies the supplied data into the transmit buffer. The //! transmit buffer data will be packetized according to the constraints //! imposed by the lower layer in use and sent to the USB controller as soon as //! possible. Once a packet is transmitted and acknowledged, a //! \b USB_EVENT_TX_COMPLETE event will be sent to the application callback //! indicating the number of bytes that have been sent from the buffer. //! //! Attempts to send more data than there is space for in the transmit buffer //! will result in fewer bytes than expected being written. The value returned //! by the function indicates the actual number of bytes copied to the buffer. //! //! \return Returns the number of bytes actually written. // //***************************************************************************** uint32_t USBBufferWrite(const tUSBBuffer *psBuffer, const uint8_t *pui8Data, uint32_t ui32Length) { uint32_t ui32Space; tUSBBufferVars *psPrivate; // // Check parameter validity. // ASSERT(psBuffer && pui8Data); ASSERT(psBuffer->bTransmitBuffer == true); // // Create a writable pointer to the private data. // psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData; // // How much space is left in the buffer? // ui32Space = USBRingBufFree(&psPrivate->sRingBuf); // // How many bytes will we write? // ui32Length = (ui32Length > ui32Space) ? ui32Space : ui32Length; // // Write the data to the buffer. // if(ui32Length) { USBRingBufWrite(&psPrivate->sRingBuf, pui8Data, ui32Length); } // // Try to transmit the next packet to the host. // ScheduleNextTransmission((tUSBBuffer *)psBuffer); // // Tell the caller how many bytes we wrote to the buffer. // return(ui32Length); }
//***************************************************************************** // //! Returns the number of free bytes in the buffer. //! //! \param psBuffer is the pointer to the buffer instance which is to be //! queried. //! //! This function returns the number of free bytes in the buffer. For a //! transmit buffer, this indicates the maximum number of bytes that can be //! passed on a call to USBBufferWrite() and accepted for transmission. For a //! receive buffer, it indicates the number of bytes that can be read from the //! USB controller before the buffer will be full. //! //! \return Returns the number of free bytes in the buffer. // //***************************************************************************** unsigned long USBBufferSpaceAvailable(const tUSBBuffer *psBuffer) { tUSBBufferVars *psVars; // // Check parameter validity. // ASSERT(psBuffer); // // Get our workspace variables. // psVars = psBuffer->pvWorkspace; // // Return the amount of space available in the buffer. // return(USBRingBufFree(&psVars->sRingBuf)); }
//***************************************************************************** // //! Returns the number of free bytes in the buffer. //! //! \param psBuffer is the pointer to the buffer instance which is to be //! queried. //! //! This function returns the number of free bytes in the buffer. For a //! transmit buffer, this indicates the maximum number of bytes that can be //! passed on a call to USBBufferWrite() and accepted for transmission. For a //! receive buffer, it indicates the number of bytes that can be read from the //! USB controller before the buffer will be full. //! //! \return Returns the number of free bytes in the buffer. // //***************************************************************************** uint32_t USBBufferSpaceAvailable(const tUSBBuffer *psBuffer) { tUSBBufferVars *psPrivate; // // Check parameter validity. // ASSERT(psBuffer); // // Create a writable pointer to the private data. // psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData; // // Return the amount of space available in the buffer. // return(USBRingBufFree(&psPrivate->sRingBuf)); }
//***************************************************************************** // //! Writes a single byte of data to a ring buffer. //! //! \param ptUSBRingBuf points to the ring buffer to be written to. //! \param ucData is the byte to be written. //! //! This function writes a single byte of data into a ring buffer. //! //! \return None. // //***************************************************************************** void USBRingBufWriteOne(tUSBRingBufObject *ptUSBRingBuf, unsigned char ucData) { // // Check the arguments. // ASSERT(ptUSBRingBuf != NULL); // // Verify that space is available in the buffer. // ASSERT(USBRingBufFree(ptUSBRingBuf) != 0); // // Write the data byte. // ptUSBRingBuf->pucBuf[ptUSBRingBuf->ulWriteIndex] = ucData; // // Increment the write index. // UpdateIndexAtomic(&ptUSBRingBuf->ulWriteIndex, 1, ptUSBRingBuf->ulSize); }
//***************************************************************************** // //! Writes a single byte of data to a ring buffer. //! //! \param psUSBRingBuf points to the ring buffer to be written to. //! \param ui8Data is the byte to be written. //! //! This function writes a single byte of data into a ring buffer. //! //! \return None. // //***************************************************************************** void USBRingBufWriteOne(tUSBRingBufObject *psUSBRingBuf, uint8_t ui8Data) { // // Check the arguments. // ASSERT(psUSBRingBuf != NULL); // // Verify that space is available in the buffer. // ASSERT(USBRingBufFree(psUSBRingBuf) != 0); // // Write the data byte. // psUSBRingBuf->pui8Buf[psUSBRingBuf->ui32WriteIndex] = ui8Data; // // Increment the write index. // UpdateIndexAtomic(&psUSBRingBuf->ui32WriteIndex, 1, psUSBRingBuf->ui32Size); }
//***************************************************************************** // //! Adds bytes to the ring buffer by advancing the write index. //! //! \param psUSBRingBuf points to the ring buffer to which bytes have been //! added. //! \param ui32NumBytes is the number of bytes added to the buffer. //! //! This function should be used by clients who wish to add data to the buffer //! directly rather than via calls to USBRingBufWrite() or //! USBRingBufWriteOne(). It advances the write index by a given number of //! bytes. //! //! \note It is considered an error if the \e ui32NumBytes parameter is larger //! than the amount of free space in the buffer and a debug build of this //! function will fail (ASSERT) if this condition is detected. In a release //! build, the buffer read pointer will be advanced if too much data is written //! but this will, of course, result in some of the oldest data in the buffer //! being discarded and also, depending upon how data is being read from //! the buffer, may result in a race condition which could corrupt the read //! pointer. //! //! \return None. // //***************************************************************************** void USBRingBufAdvanceWrite(tUSBRingBufObject *psUSBRingBuf, uint32_t ui32NumBytes) { uint32_t ui32Count; // // Check the arguments. // ASSERT(psUSBRingBuf != NULL); // // Make sure we were not asked to add a silly number of bytes. // ASSERT(ui32NumBytes <= psUSBRingBuf->ui32Size); // // Determine how much free space we currently think the buffer has. // ui32Count = USBRingBufFree(psUSBRingBuf); // // Check that the client has not added more data to the buffer than there // is space for. In this case, corruption may have occurred since the // buffer may have been read under interrupt context while the writer was // busy trashing the area around the read pointer. // ASSERT(ui32Count >= ui32NumBytes); // // Update the write pointer. // psUSBRingBuf->ui32WriteIndex += ui32NumBytes; // // Check and correct for wrap. // if(psUSBRingBuf->ui32WriteIndex >= psUSBRingBuf->ui32Size) { psUSBRingBuf->ui32WriteIndex -= psUSBRingBuf->ui32Size; } // // Did the client add more bytes than the buffer had free space for? This // should be considered a bug since, unless this function is called in // the same context as the code which is reading from the buffer, writing // over the earliest data can cause corrupted data to be read. The // ASSERT above catches this in debug builds but, in release builds, we // go ahead and try to fix up the read pointer appropriately. // if(ui32Count < ui32NumBytes) { // // Yes - we need to advance the read pointer to ahead of the write // pointer to discard some of the oldest data. // psUSBRingBuf->ui32ReadIndex = psUSBRingBuf->ui32WriteIndex + 1; // // Correct for buffer wrap if necessary. // if(psUSBRingBuf->ui32ReadIndex >= psUSBRingBuf->ui32Size) { psUSBRingBuf->ui32ReadIndex -= psUSBRingBuf->ui32Size; } } }
//***************************************************************************** // // Handles USB_EVENT_RX_AVAILABLE for a receive buffer. // // \param psBuffer points to the buffer which is receiving the event. // \param ulSize is the size reported in the event. // \param pucData is the pointer provided in the event. // // This function is responsible for reading data from the lower layer into // the buffer or, if we had previously passed a section of the buffer to the // lower layer for it to write into directly, updating the buffer write pointer // to add the new data to the buffer. // // If the pointer provided is NULL, we call the low level pfnTransfer function // to get the new data. If the pointer is not NULL and not within the existing // ring buffer, we copy the data directly from the pointer to the buffer and // return the number of bytes read. // // \return Returns the number of bytes read from the lower layer. // //***************************************************************************** static unsigned long HandleRxAvailable(tUSBBuffer *psBuffer, unsigned long ulSize, unsigned char *pucData) { tUSBBufferVars *psVars; unsigned long ulAvail, ulRead, ulPacket, ulRetCount; // // Get a pointer to our workspace variables. // psVars = psBuffer->pvWorkspace; // // Has the data already been read into memory? // if(pucData) { // // Yes - is it already in our ring buffer? // if((pucData >= psBuffer->pcBuffer) && (pucData < psBuffer->pcBuffer + psBuffer->ulBufferSize)) { // // The data is already in our ring buffer so merely update the // write pointer to add the new data. // USBRingBufAdvanceWrite(&psVars->sRingBuf, ulSize); // // In this case, we pass back 0 to indicate that the lower layer // doesn't need to make any buffer pointer updates. // ulRetCount = 0; } else { // // The data is not within our buffer so we need to copy it into // the buffer. // // How much space does the buffer have available? // ulAvail = USBRingBufFree(&psVars->sRingBuf); // // How much should we copy? // ulRead = (ulAvail < ulSize) ? ulAvail : ulSize; // // Copy the data into the buffer. // USBRingBufWrite(&psVars->sRingBuf, pucData, ulRead); // // We need to return the number of bytes we read in this case // since the buffer supplied to us was owned by the lower layer and // it may need to update its read pointer. // ulRetCount = ulRead; } } else { // // We were passed a NULL pointer so the low level driver has not read // the data into memory yet. We need to call the transfer function to // get the packet. // // How big is the packet that we need to receive? // ulPacket = psBuffer->pfnAvailable(psBuffer->pvHandle); // // How much contiguous space do we have in the buffer? // ulAvail = USBRingBufContigFree(&psVars->sRingBuf); // // Get as much of the packet as we can in the available space. // ulRead = psBuffer->pfnTransfer(psBuffer->pvHandle, (psVars->sRingBuf.pucBuf + psVars->sRingBuf.ulWriteIndex), ulAvail, true); // // Advance the ring buffer write pointer to add our new data. // if(ulRead) { USBRingBufAdvanceWrite(&psVars->sRingBuf, ulRead); } // // Did we get the whole packet? // if(ulRead < ulPacket) { // // No - how much space do we have in the buffer? // ulAvail = USBRingBufContigFree(&psVars->sRingBuf); // // If there is any space left, read as much of the remainder of // the packet as we can. // if(ulAvail) { ulPacket = psBuffer->pfnTransfer(psBuffer->pvHandle, (psVars->sRingBuf.pucBuf + psVars->sRingBuf.ulWriteIndex), ulAvail, true); // // Update the write pointer after we read more data into the // buffer. // if(ulPacket) { USBRingBufAdvanceWrite(&psVars->sRingBuf, ulPacket); } } } // // We need to return 0 in this case to indicate that the lower layer // need not perform any buffer maintenance as a result of the callback. // ulRetCount = 0; } // // How much data do we have in the buffer? // ulAvail = USBRingBufUsed(&psVars->sRingBuf); // // Pass the event on to the client with the current read pointer and // available data size. The client is expected to understand the ring // structure and be able to deal with wrap if it wants to read the data // directly from the buffer. // ulRead = psBuffer->pfnCallback(psBuffer->pvCBData, USB_EVENT_RX_AVAILABLE, ulAvail, (psVars->sRingBuf.pucBuf + psVars->sRingBuf.ulReadIndex)); // // If the client read anything from the buffer, update the read pointer. // USBRingBufAdvanceRead(&psVars->sRingBuf, ulRead); // // Return the correct value to the low level driver. // return(ulRetCount); }