[Thread] Implement read on socket interface
Bug: 313425570 Test: build pass & manual test Change-Id: I4e6dfdfa73f7145e8f36d05abf1531d7796b4b9e
This commit is contained in:
parent
5b2cd32368
commit
1623351bc0
2 changed files with 143 additions and 0 deletions
|
@ -89,6 +89,41 @@ otError SocketInterface::SendFrame(const uint8_t* aFrame, uint16_t aLength) {
|
||||||
return OT_ERROR_NONE;
|
return OT_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
otError SocketInterface::WaitForFrame(uint64_t aTimeoutUs) {
|
||||||
|
otError error = OT_ERROR_NONE;
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = static_cast<time_t>(aTimeoutUs / US_PER_S);
|
||||||
|
timeout.tv_usec = static_cast<suseconds_t>(aTimeoutUs % US_PER_S);
|
||||||
|
|
||||||
|
fd_set readFds;
|
||||||
|
fd_set errorFds;
|
||||||
|
int rval;
|
||||||
|
|
||||||
|
FD_ZERO(&readFds);
|
||||||
|
FD_ZERO(&errorFds);
|
||||||
|
FD_SET(mSockFd, &readFds);
|
||||||
|
FD_SET(mSockFd, &errorFds);
|
||||||
|
|
||||||
|
rval = TEMP_FAILURE_RETRY(select(mSockFd + 1, &readFds, nullptr, &errorFds, &timeout));
|
||||||
|
|
||||||
|
if (rval > 0) {
|
||||||
|
if (FD_ISSET(mSockFd, &readFds)) {
|
||||||
|
Read();
|
||||||
|
} else if (FD_ISSET(mSockFd, &errorFds)) {
|
||||||
|
DieNowWithMessage("RCP error", OT_EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
DieNow(OT_EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (rval == 0) {
|
||||||
|
ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT);
|
||||||
|
} else {
|
||||||
|
DieNowWithMessage("wait response", OT_EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
void SocketInterface::UpdateFdSet(void* aMainloopContext) {
|
void SocketInterface::UpdateFdSet(void* aMainloopContext) {
|
||||||
otSysMainloopContext* context = reinterpret_cast<otSysMainloopContext*>(aMainloopContext);
|
otSysMainloopContext* context = reinterpret_cast<otSysMainloopContext*>(aMainloopContext);
|
||||||
|
|
||||||
|
@ -101,12 +136,69 @@ void SocketInterface::UpdateFdSet(void* aMainloopContext) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SocketInterface::Process(const void* aMainloopContext) {
|
||||||
|
const otSysMainloopContext* context =
|
||||||
|
reinterpret_cast<const otSysMainloopContext*>(aMainloopContext);
|
||||||
|
|
||||||
|
assert(context != nullptr);
|
||||||
|
|
||||||
|
if (FD_ISSET(mSockFd, &context->mReadFdSet)) {
|
||||||
|
Read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketInterface::Read(void) {
|
||||||
|
uint8_t buffer[kMaxFrameSize];
|
||||||
|
|
||||||
|
ssize_t rval = TEMP_FAILURE_RETRY(read(mSockFd, buffer, sizeof(buffer)));
|
||||||
|
|
||||||
|
if (rval > 0) {
|
||||||
|
ProcessReceivedData(buffer, static_cast<uint16_t>(rval));
|
||||||
|
} else if (rval < 0) {
|
||||||
|
DieNow(OT_EXIT_ERROR_ERRNO);
|
||||||
|
} else {
|
||||||
|
otLogCritPlat("Socket connection is closed by remote.");
|
||||||
|
exit(OT_EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SocketInterface::Write(const uint8_t* aFrame, uint16_t aLength) {
|
void SocketInterface::Write(const uint8_t* aFrame, uint16_t aLength) {
|
||||||
ssize_t rval = TEMP_FAILURE_RETRY(write(mSockFd, aFrame, aLength));
|
ssize_t rval = TEMP_FAILURE_RETRY(write(mSockFd, aFrame, aLength));
|
||||||
VerifyOrDie(rval >= 0, OT_EXIT_ERROR_ERRNO);
|
VerifyOrDie(rval >= 0, OT_EXIT_ERROR_ERRNO);
|
||||||
VerifyOrDie(rval > 0, OT_EXIT_FAILURE);
|
VerifyOrDie(rval > 0, OT_EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SocketInterface::ProcessReceivedData(const uint8_t* aBuffer, uint16_t aLength) {
|
||||||
|
while (aLength--) {
|
||||||
|
uint8_t byte = *aBuffer++;
|
||||||
|
if (mReceiveFrameBuffer->CanWrite(sizeof(uint8_t))) {
|
||||||
|
IgnoreError(mReceiveFrameBuffer->WriteByte(byte));
|
||||||
|
} else {
|
||||||
|
HandleSocketFrame(this, OT_ERROR_NO_BUFS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HandleSocketFrame(this, OT_ERROR_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketInterface::HandleSocketFrame(void* aContext, otError aError) {
|
||||||
|
static_cast<SocketInterface*>(aContext)->HandleSocketFrame(aError);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketInterface::HandleSocketFrame(otError aError) {
|
||||||
|
VerifyOrExit((mReceiveFrameCallback != nullptr) && (mReceiveFrameBuffer != nullptr));
|
||||||
|
|
||||||
|
if (aError == OT_ERROR_NONE) {
|
||||||
|
mReceiveFrameCallback(mReceiveFrameContext);
|
||||||
|
} else {
|
||||||
|
mReceiveFrameBuffer->DiscardFrame();
|
||||||
|
otLogWarnPlat("Process socket frame failed: %s", otThreadErrorToString(aError));
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int SocketInterface::OpenFile(const ot::Url::Url& aRadioUrl) {
|
int SocketInterface::OpenFile(const ot::Url::Url& aRadioUrl) {
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
sockaddr_un serverAddress;
|
sockaddr_un serverAddress;
|
||||||
|
|
|
@ -86,6 +86,21 @@ class SocketInterface : public ot::Spinel::SpinelInterface {
|
||||||
*/
|
*/
|
||||||
otError SendFrame(const uint8_t* aFrame, uint16_t aLength);
|
otError SendFrame(const uint8_t* aFrame, uint16_t aLength);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for receiving part or all of Spinel frame within specified
|
||||||
|
* interval.
|
||||||
|
*
|
||||||
|
* @param[in] aTimeout The timeout value in microseconds.
|
||||||
|
*
|
||||||
|
* @retval OT_ERROR_NONE Part or all of Spinel frame is
|
||||||
|
* received.
|
||||||
|
* @retval OT_ERROR_RESPONSE_TIMEOUT No Spinel frame is received within @p
|
||||||
|
* aTimeout.
|
||||||
|
* @retval OT_EXIT_FAILURE RCP error
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
otError WaitForFrame(uint64_t aTimeoutUs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the file descriptor sets with file descriptors used by the radio
|
* Updates the file descriptor sets with file descriptors used by the radio
|
||||||
* driver.
|
* driver.
|
||||||
|
@ -96,6 +111,15 @@ class SocketInterface : public ot::Spinel::SpinelInterface {
|
||||||
*/
|
*/
|
||||||
void UpdateFdSet(void* aMainloopContext);
|
void UpdateFdSet(void* aMainloopContext);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs radio driver processing.
|
||||||
|
*
|
||||||
|
* @param[in] aMainloopContext A pointer to the mainloop context
|
||||||
|
* containing fd_sets.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void Process(const void* aMainloopContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the bus speed between the host and the radio.
|
* Returns the bus speed between the host and the radio.
|
||||||
*
|
*
|
||||||
|
@ -136,6 +160,17 @@ class SocketInterface : public ot::Spinel::SpinelInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* Instructs `SocketInterface` to read data from radio over the
|
||||||
|
* socket.
|
||||||
|
*
|
||||||
|
* If a full Spinel frame is received, this method invokes the
|
||||||
|
* `HandleSocketFrame()` (on the `aCallback` object from constructor) to
|
||||||
|
* pass the received frame to be processed.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void Read(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a given frame to the socket.
|
* Writes a given frame to the socket.
|
||||||
*
|
*
|
||||||
|
@ -145,6 +180,22 @@ class SocketInterface : public ot::Spinel::SpinelInterface {
|
||||||
*/
|
*/
|
||||||
void Write(const uint8_t* aFrame, uint16_t aLength);
|
void Write(const uint8_t* aFrame, uint16_t aLength);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process received data.
|
||||||
|
*
|
||||||
|
* If a full frame is finished processing and we obtain the raw Spinel
|
||||||
|
* frame, this method invokes the `HandleSocketFrame()` (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 ProcessReceivedData(const uint8_t* aBuffer, uint16_t aLength);
|
||||||
|
|
||||||
|
static void HandleSocketFrame(void* aContext, otError aError);
|
||||||
|
void HandleSocketFrame(otError aError);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens file specified by aRadioUrl.
|
* Opens file specified by aRadioUrl.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue