mirror of
https://github.com/espressif/openthread.git
synced 2026-10-02 05:47:40 +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.Encode(aFrame, aLength, encoderBuffer));
|
||||||
SuccessOrExit(error = hdlcEncoder.Finalize(encoderBuffer));
|
SuccessOrExit(error = hdlcEncoder.Finalize(encoderBuffer));
|
||||||
|
|
||||||
SuccessOrExit(error = Write(encoderBuffer.GetBuffer(), encoderBuffer.GetLength()));
|
error = Write(encoderBuffer.GetBuffer(), encoderBuffer.GetLength());
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return error;
|
return error;
|
||||||
@@ -183,7 +183,6 @@ exit:
|
|||||||
otError HdlcInterface::Write(const uint8_t *aFrame, uint16_t aLength)
|
otError HdlcInterface::Write(const uint8_t *aFrame, uint16_t aLength)
|
||||||
{
|
{
|
||||||
otError error = OT_ERROR_NONE;
|
otError error = OT_ERROR_NONE;
|
||||||
|
|
||||||
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
||||||
otSimSendRadioSpinelWriteEvent(aFrame, aLength);
|
otSimSendRadioSpinelWriteEvent(aFrame, aLength);
|
||||||
#else
|
#else
|
||||||
@@ -195,19 +194,83 @@ otError HdlcInterface::Write(const uint8_t *aFrame, uint16_t aLength)
|
|||||||
{
|
{
|
||||||
aLength -= static_cast<uint16_t>(rval);
|
aLength -= static_cast<uint16_t>(rval);
|
||||||
aFrame += 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");
|
perror("HdlcInterface::Write()");
|
||||||
ExitNow(error = OT_ERROR_FAILED);
|
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
|
else
|
||||||
{
|
{
|
||||||
ExitNow(error = OT_ERROR_FAILED);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error = OT_ERROR_FAILED;
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
#endif
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public:
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kMaxFrameSize = 2048, ///< Maximum frame size (number of bytes).
|
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.
|
* @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.
|
* 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.
|
* This is blocking call, i.e., if the socket is not writable, this method waits for it to become writable for
|
||||||
* @param[in] aLength The length (number of bytes) in the frame
|
* 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_NONE Successfully encoded and sent the frame.
|
||||||
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode 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);
|
otError SendFrame(const uint8_t *aFrame, uint16_t aLength);
|
||||||
@@ -154,8 +158,42 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
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);
|
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 HandleHdlcFrame(void *aContext, uint8_t *aFrame, uint16_t aFrameLength);
|
||||||
static void HandleHdlcError(void *aContext, otError aError, 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