Skip to content

Commit

Permalink
usb/usbserial: Read() is non-blocking now
Browse files Browse the repository at this point in the history
Read() always requests MaxPacketSize bytes, can ignore returned header
bytes (used by the class CUSBSerialFT231XDevice) and returns up to the
requested number of bytes. Remaining bytes will be buffered for the
next Read() call(s). Read() returns 0, if there is no data available.

usb/usbserialft231x: Support FT232RL

addon/gpio/rtkgpio: Wait until Read() returns data.
  • Loading branch information
rsta2 committed Nov 14, 2020
1 parent 3bac240 commit a1c970b
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 83 deletions.
18 changes: 16 additions & 2 deletions addon/gpio/rtkgpio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ boolean CRTKGpioDevice::GetVersion (void)
}

u8 rxData[32] = {0};
if (m_pCH341->Read (rxData, 32) < 0)
if (Read (rxData, 32) < 0)
{
CLogger::Get ()->Write (FromRtkgpio, LogError, "Read error version");

Expand Down Expand Up @@ -220,7 +220,7 @@ TRtkGpioLevel CRTKGpioDevice::GetPinLevel (unsigned nPin)
}

u8 rxData[4] = {0};
if (m_pCH341->Read (rxData, 4) < 0)
if (Read (rxData, 4) < 0)
{
CLogger::Get ()->Write (FromRtkgpio, LogError, "Read error");

Expand All @@ -243,3 +243,17 @@ TRtkGpioLevel CRTKGpioDevice::GetPinLevel (unsigned nPin)
CLogger::Get ()->Write (FromRtkgpio, LogError, "Invalid level");
return RtkGpioLevelUnknown;
}

int CRTKGpioDevice::Read (void *pBuffer, size_t nCount)
{
assert (m_pCH341 != 0);

int nResult;
do
{
nResult = m_pCH341->Read (pBuffer, nCount);
}
while (nResult == 0);

return nResult;
}
3 changes: 3 additions & 0 deletions addon/gpio/rtkgpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class CRTKGpioDevice

TRtkGpioLevel GetPinLevel (unsigned nPin);

private:
int Read (void *pBuffer, size_t nCount);

private:
CUSBSerialCH341Device *m_pCH341;
};
Expand Down
10 changes: 7 additions & 3 deletions include/circle/usb/usbserial.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ enum TUSBSerialParity
class CUSBSerialDevice : public CUSBFunction
{
public:
CUSBSerialDevice (CUSBFunction *pFunction);
CUSBSerialDevice (CUSBFunction *pFunction,
size_t nReadHeaderBytes = 0); // number of bytes to be ignored
virtual ~CUSBSerialDevice (void);

boolean Configure (void);
Expand All @@ -67,12 +68,15 @@ class CUSBSerialDevice : public CUSBFunction
TUSBSerialStopBits m_nStopBits;

private:
size_t m_nReadHeaderBytes;

CUSBEndpoint *m_pEndpointIn;
CUSBEndpoint *m_pEndpointOut;

u8 *m_pBufferIn;
size_t m_nBufferInSize;
u8 *m_pBufferOut;
size_t m_nBufferOutSize;
size_t m_nBufferInValid;
unsigned m_nBufferInPtr;

unsigned m_nDeviceNumber;
static CNumberPool s_DeviceNumberPool;
Expand Down
2 changes: 0 additions & 2 deletions include/circle/usb/usbserialft231x.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ class CUSBSerialFT231XDevice : public CUSBSerialDevice
boolean SetLineProperties (TUSBSerialDataBits nDataBits,
TUSBSerialParity nParity, TUSBSerialStopBits nStopBits);

int Read (void *pBuffer, size_t nCount);

static const TUSBDeviceID *GetDeviceIDTable (void);
};

Expand Down
118 changes: 66 additions & 52 deletions lib/usb/usbserial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
//
#include <circle/synchronize.h>
#include <circle/util.h>
#include <circle/alloc.h>
#include <circle/usb/usbserial.h>
#include <circle/usb/usbhostcontroller.h>
#include <circle/usb/usbrequest.h>
#include <circle/devicenameservice.h>
#include <circle/logger.h>
#include <assert.h>
Expand All @@ -31,14 +31,19 @@ CNumberPool CUSBSerialDevice::s_DeviceNumberPool (1);
static const char FromSerial[] = "userial";
static const char DevicePrefix[] = "utty";

CUSBSerialDevice::CUSBSerialDevice (CUSBFunction *pFunction)
CUSBSerialDevice::CUSBSerialDevice (CUSBFunction *pFunction, size_t nReadHeaderBytes)
: CUSBFunction (pFunction),
m_nBaudRate (9600),
m_nDataBits (USBSerialDataBits8),
m_nParity (USBSerialParityNone),
m_nStopBits (USBSerialStopBits1),
m_nReadHeaderBytes (nReadHeaderBytes),
m_pEndpointIn (0),
m_pEndpointOut (0),
m_pBufferIn (0),
m_nBufferInSize (0),
m_nBufferInValid (0),
m_nBufferInPtr (0),
m_nDeviceNumber (0)
{
}
Expand All @@ -58,19 +63,9 @@ CUSBSerialDevice::~CUSBSerialDevice (void)
delete m_pEndpointIn;
m_pEndpointIn = 0;

if (m_pBufferIn)
{
free (m_pBufferIn);
m_pBufferIn = 0;
m_nBufferInSize = 0;
}

if (m_pBufferOut)
{
free (m_pBufferOut);
m_pBufferOut = 0;
m_nBufferOutSize = 0;
}
delete [] m_pBufferIn;
m_pBufferIn = 0;
m_nBufferInSize = 0;
}

boolean CUSBSerialDevice::Configure (void)
Expand Down Expand Up @@ -113,6 +108,10 @@ boolean CUSBSerialDevice::Configure (void)
return FALSE;
}

m_nBufferInSize = m_pEndpointIn->GetMaxPacketSize ();
m_pBufferIn = new u8[m_nBufferInSize];
assert (m_pBufferIn != 0);

if (!CUSBFunction::Configure ())
{
CLogger::Get ()->Write (FromSerial, LogError, "Cannot set interface");
Expand All @@ -125,13 +124,6 @@ boolean CUSBSerialDevice::Configure (void)

CDeviceNameService::Get ()->AddDevice (DevicePrefix, m_nDeviceNumber, this, FALSE);

m_nBufferInSize = m_pEndpointIn->GetMaxPacketSize ();
m_pBufferIn = (u8 *) malloc (m_nBufferInSize);
assert (m_pBufferIn != 0);
m_nBufferOutSize = m_pEndpointOut->GetMaxPacketSize ();
m_pBufferOut = (u8 *) malloc (m_nBufferOutSize);
assert (m_pBufferOut != 0);

return TRUE;
}

Expand All @@ -143,22 +135,14 @@ int CUSBSerialDevice::Write (const void *pBuffer, size_t nCount)
CUSBHostController *pHost = GetHost ();
assert (pHost != 0);

size_t count = (nCount < m_pEndpointOut->GetMaxPacketSize ()) ?
m_pEndpointOut->GetMaxPacketSize () : nCount;
if (m_nBufferOutSize < count)
{
m_pBufferOut = (u8 *) realloc (m_pBufferOut, count);
m_nBufferOutSize = count;
}
DMA_BUFFER (u8, BufferOut, nCount);
memcpy (BufferOut, pBuffer, nCount);

memcpy (m_pBufferOut, pBuffer, nCount);

int nActual = pHost->Transfer (m_pEndpointOut, (void *) m_pBufferOut, nCount);
assert (m_pEndpointOut != 0);
int nActual = pHost->Transfer (m_pEndpointOut, BufferOut, nCount);
if (nActual < 0)
{
CLogger::Get ()->Write (FromSerial, LogError, "USB write failed");

return -1;
CLogger::Get ()->Write (FromSerial, LogWarning, "USB write failed");
}

return nActual;
Expand All @@ -169,33 +153,63 @@ int CUSBSerialDevice::Read (void *pBuffer, size_t nCount)
assert (pBuffer != 0);
assert (nCount > 0);

CUSBHostController *pHost = GetHost ();
assert (pHost != 0);
assert (m_pBufferIn != 0);
assert (m_nBufferInSize > 0);
assert (m_nBufferInValid <= m_nBufferInSize);
assert (m_nBufferInPtr <= m_nBufferInValid);

size_t count = (nCount < m_pEndpointIn->GetMaxPacketSize ()) ?
m_pEndpointIn->GetMaxPacketSize () : nCount;
if (m_nBufferInSize < count)
if (m_nBufferInPtr == m_nBufferInValid) // buffer empty?
{
m_pBufferIn = (u8 *) realloc (m_pBufferIn, count);
m_nBufferInSize = count;
}
CUSBHostController *pHost = GetHost ();
assert (pHost != 0);

int nActual = pHost->Transfer (m_pEndpointIn, (void *) m_pBufferIn, count);
if (nActual < 0)
{
CLogger::Get ()->Write (FromSerial, LogError, "USB read failed");
assert (m_pEndpointIn != 0);
CUSBRequest URB (m_pEndpointIn, m_pBufferIn, m_nBufferInSize);

// do not retry if request cannot be served immediately
URB.SetCompleteOnNAK ();

if (!pHost->SubmitBlockingRequest (&URB))
{
CLogger::Get ()->Write (FromSerial, LogWarning, "USB read failed");

return -1;
}

m_nBufferInValid = URB.GetResultLength ();
m_nBufferInPtr = m_nReadHeaderBytes;

if ( m_nBufferInValid == 0
|| m_nBufferInValid == m_nBufferInPtr)
{
m_nBufferInValid = 0;
m_nBufferInPtr = 0;

return 0;
}

if (m_nBufferInValid < m_nBufferInPtr)
{
CLogger::Get ()->Write (FromSerial, LogWarning, "Missing read header");

return -1;
m_nBufferInValid = 0;
m_nBufferInPtr = 0;

return -1;
}
}

if (nCount < (size_t) nActual)
size_t nRemain = m_nBufferInValid - m_nBufferInPtr;
if (nRemain < nCount)
{
nActual = nCount;
nCount = nRemain;
}

memcpy (pBuffer, m_pBufferIn, nActual);
assert (nCount > 0);
memcpy (pBuffer, m_pBufferIn + m_nBufferInPtr, nCount);
m_nBufferInPtr += nCount;

return nActual;
return nCount;
}

boolean CUSBSerialDevice::SetBaudRate (unsigned nBaudRate)
Expand Down
30 changes: 6 additions & 24 deletions lib/usb/usbserialft231x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ static const char FromFt231x[] = "ft231x";
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)

CUSBSerialFT231XDevice::CUSBSerialFT231XDevice (CUSBFunction *pFunction)
: CUSBSerialDevice (pFunction)
: CUSBSerialDevice (pFunction, 2)
{
}

Expand All @@ -67,6 +67,10 @@ boolean CUSBSerialFT231XDevice::Configure (void)
{
type = "FT-X";
}
else if (deviceDesc->bcdDevice == 0x600)
{
type = "FT232RL";
}
CLogger::Get ()->Write (FromFt231x, LogNotice, "Part number: %s", (const char *)type);

CUSBHostController *pHost = GetHost ();
Expand Down Expand Up @@ -229,33 +233,11 @@ boolean CUSBSerialFT231XDevice::SetLineProperties (TUSBSerialDataBits nDataBits,
return TRUE;
}

int CUSBSerialFT231XDevice::Read (void *pBuffer, size_t nCount)
{
assert (pBuffer != 0);
assert (nCount > 0);

int nActual = CUSBSerialDevice::Read (pBuffer, nCount);
if (nActual < 0)
{
return -1;
}

assert (nActual > 0);
nActual -= 2;
if (nActual > 0)
{
memmove (pBuffer, (u8 *)pBuffer + 2, nActual);
}

//CLogger::Get ()->Write (FromFt231x, LogDebug, "Read() want %d, returned %d", nCount, nActual);

return nActual;
}

const TUSBDeviceID *CUSBSerialFT231XDevice::GetDeviceIDTable (void)
{
static const TUSBDeviceID DeviceIDTable[] =
{
{ USB_DEVICE (0x0403, 0x6001) },
{ USB_DEVICE (0x0403, 0x6015) },
{ }
};
Expand Down

0 comments on commit a1c970b

Please sign in to comment.