mirror of
https://github.com/espressif/openthread.git
synced 2026-08-06 10:47:46 +00:00
[hdlc-interface] wait for socket to be writable when sending a frame (#3309)
This commit changes `HdlcInterface` method `SendFrame()` to handle the case where the socket associated with the HDLC interface is not immediately ready to accept the frame. With the change in this commit `SendFrame()` will block and wait for socket to become writable within a timeout interval.
This commit is contained in:
committed by
Jonathan Hui
parent
1801b0713f
commit
3f3970ccaa
@@ -174,7 +174,7 @@ otError HdlcInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength)
|
||||
SuccessOrExit(error = hdlcEncoder.Encode(aFrame, aLength, encoderBuffer));
|
||||
SuccessOrExit(error = hdlcEncoder.Finalize(encoderBuffer));
|
||||
|
||||
SuccessOrExit(error = Write(encoderBuffer.GetBuffer(), encoderBuffer.GetLength()));
|
||||
error = Write(encoderBuffer.GetBuffer(), encoderBuffer.GetLength());
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -183,7 +183,6 @@ exit:
|
||||
otError HdlcInterface::Write(const uint8_t *aFrame, uint16_t aLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
||||
otSimSendRadioSpinelWriteEvent(aFrame, aLength);
|
||||
#else
|
||||
@@ -195,19 +194,83 @@ otError HdlcInterface::Write(const uint8_t *aFrame, uint16_t aLength)
|
||||
{
|
||||
aLength -= static_cast<uint16_t>(rval);
|
||||
aFrame += static_cast<uint16_t>(rval);
|
||||
continue;
|
||||
}
|
||||
else if (rval < 0)
|
||||
|
||||
if ((rval < 0) && (errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINTR))
|
||||
{
|
||||
perror("HdlcInterface::Write");
|
||||
ExitNow(error = OT_ERROR_FAILED);
|
||||
perror("HdlcInterface::Write()");
|
||||
exit(OT_EXIT_FAILURE);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = WaitForWritable());
|
||||
}
|
||||
|
||||
exit:
|
||||
#endif // OPENTHREAD_POSIX_VIRTUAL_TIME
|
||||
return error;
|
||||
}
|
||||
|
||||
otError HdlcInterface::WaitForWritable(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
struct timeval timeout = {kMaxWaitTime / 1000, (kMaxWaitTime % 1000) * 1000};
|
||||
struct timeval end;
|
||||
struct timeval now;
|
||||
fd_set writeFds;
|
||||
fd_set errorFds;
|
||||
int rval;
|
||||
|
||||
otSysGetTime(&now);
|
||||
timeradd(&now, &timeout, &end);
|
||||
|
||||
while (true)
|
||||
{
|
||||
FD_ZERO(&writeFds);
|
||||
FD_ZERO(&errorFds);
|
||||
FD_SET(mSockFd, &writeFds);
|
||||
FD_SET(mSockFd, &errorFds);
|
||||
|
||||
rval = select(mSockFd + 1, NULL, &writeFds, &errorFds, &timeout);
|
||||
|
||||
if (rval > 0)
|
||||
{
|
||||
if (FD_ISSET(mSockFd, &writeFds))
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
else if (FD_ISSET(mSockFd, &errorFds))
|
||||
{
|
||||
fprintf(stderr, "HdlcInterface::WaitForWritable(): socket error\n\r");
|
||||
exit(OT_EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "HdlcInterface::WaitForWritable(): select error\n\r");
|
||||
exit(OT_EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else if ((rval < 0) && (errno != EINTR))
|
||||
{
|
||||
perror("HdlcInterface::WaitForWritable()");
|
||||
exit(OT_EXIT_FAILURE);
|
||||
}
|
||||
|
||||
otSysGetTime(&now);
|
||||
|
||||
if (timercmp(&end, &now, >))
|
||||
{
|
||||
timersub(&end, &now, &timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_FAILED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
error = OT_ERROR_FAILED;
|
||||
|
||||
exit:
|
||||
#endif
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
enum
|
||||
{
|
||||
kMaxFrameSize = 2048, ///< Maximum frame size (number of bytes).
|
||||
kMaxWaitTime = 2000, ///< Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`).
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -102,7 +103,7 @@ public:
|
||||
|
||||
/**
|
||||
*
|
||||
* This method returns the socket file descriptor associate with the interface
|
||||
* This method returns the socket file descriptor associated with the interface.
|
||||
*
|
||||
* @returns The associated socket file descriptor, or -1 if interface is not initializes.
|
||||
*
|
||||
@@ -129,12 +130,15 @@ public:
|
||||
/**
|
||||
* This method encodes and sends a frame to Radio Co-processor (RCP) over the socket.
|
||||
*
|
||||
* @param[in] aFrame A pointer to buffer containing the frame to send.
|
||||
* @param[in] aLength The length (number of bytes) in the frame
|
||||
* This is blocking call, i.e., if the socket is not writable, this method waits for it to become writable for
|
||||
* up to `kMaxWaitTime` interval.
|
||||
*
|
||||
* @param[in] aFrame A pointer to buffer containing the frame to send.
|
||||
* @param[in] aLength The length (number of bytes) in the frame.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully encoded and sent the frame.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame.
|
||||
* @retval OT_ERROR_FAILED Failed to send frame due to socket write failure.
|
||||
* @retval OT_ERROR_FAILED Failed to send due to socket not becoming writable within `kMaxWaitTime`.
|
||||
*
|
||||
*/
|
||||
otError SendFrame(const uint8_t *aFrame, uint16_t aLength);
|
||||
@@ -154,8 +158,42 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
/**
|
||||
* This method waits for the socket file descriptor associated with the HDLC interface to become writable within
|
||||
* `kMaxWaitTime` interval.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Socket is writable.
|
||||
* @retval OT_ERROR_FAILED Socket did not become writable within `kMaxWaitTime`.
|
||||
*
|
||||
*/
|
||||
otError WaitForWritable(void);
|
||||
|
||||
/**
|
||||
* This method writes a given frame to the socket.
|
||||
*
|
||||
* This is blocking call, i.e., if the socket is not writable, this method waits for it to become writable for
|
||||
* up to `kMaxWaitTime` interval.
|
||||
*
|
||||
* @param[in] aFrame A pointer to buffer containing the frame to write.
|
||||
* @param[in] aLength The length (number of bytes) in the frame.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Frame was written successfully.
|
||||
* @retval OT_ERROR_FAILED Failed to write due to socket not becoming writable within `kMaxWaitTime`.
|
||||
*
|
||||
*/
|
||||
otError Write(const uint8_t *aFrame, uint16_t aLength);
|
||||
void Decode(const uint8_t *aBuffer, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* This method performs HDLC decoding on received data.
|
||||
*
|
||||
* If a full HDLC frame is decoded while reading data, this method invokes the `HandleReceivedFrame()` (on the
|
||||
* `aCallback` object from constructor) to pass the received frame to be processed.
|
||||
*
|
||||
* @param[in] aBuffer A pointer to buffer containing data.
|
||||
* @param[in] aLength The length (number of bytes) in the buffer.
|
||||
*
|
||||
*/
|
||||
void Decode(const uint8_t *aBuffer, uint16_t aLength);
|
||||
|
||||
static void HandleHdlcFrame(void *aContext, uint8_t *aFrame, uint16_t aFrameLength);
|
||||
static void HandleHdlcError(void *aContext, otError aError, uint8_t *aFrame, uint16_t aFrameLength);
|
||||
|
||||
Reference in New Issue
Block a user