From 429bf4a484e3b18105834d7fb531273a5db8e07f Mon Sep 17 00:00:00 2001 From: shihchienc Date: Wed, 24 Jan 2024 08:58:39 +0000 Subject: [PATCH 1/6] [Thread] Initialize socket interface Bug: 31342557 Test: build pass & manual test Change-Id: I9d2ef2f6da8d9c856498f4d89423f76c369cbc62 --- threadnetwork/aidl/default/Android.bp | 2 + .../aidl/default/socket_interface.cpp | 43 +++++++++ .../aidl/default/socket_interface.hpp | 91 +++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 threadnetwork/aidl/default/socket_interface.cpp create mode 100644 threadnetwork/aidl/default/socket_interface.hpp diff --git a/threadnetwork/aidl/default/Android.bp b/threadnetwork/aidl/default/Android.bp index 816f89225b..82a76e0669 100644 --- a/threadnetwork/aidl/default/Android.bp +++ b/threadnetwork/aidl/default/Android.bp @@ -37,6 +37,7 @@ cc_binary { srcs: [ "main.cpp", "service.cpp", + "socket_interface.cpp", "thread_chip.cpp", "utils.cpp", ], @@ -63,6 +64,7 @@ cc_fuzz { ], srcs: [ + "socket_interface.cpp", "thread_chip.cpp", "utils.cpp", "fuzzer.cpp", diff --git a/threadnetwork/aidl/default/socket_interface.cpp b/threadnetwork/aidl/default/socket_interface.cpp new file mode 100644 index 0000000000..3a8b1cf77a --- /dev/null +++ b/threadnetwork/aidl/default/socket_interface.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file includes the implementation for the Socket interface to radio + * (RCP). + */ + +#include "socket_interface.hpp" + +namespace aidl { +namespace android { +namespace hardware { +namespace threadnetwork { + +SocketInterface::SocketInterface(const ot::Url::Url& aRadioUrl) + : mReceiveFrameCallback(nullptr), + mReceiveFrameContext(nullptr), + mReceiveFrameBuffer(nullptr), + mSockFd(-1), + mRadioUrl(aRadioUrl) { + memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics)); + mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor; +} + +} // namespace threadnetwork +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/threadnetwork/aidl/default/socket_interface.hpp b/threadnetwork/aidl/default/socket_interface.hpp new file mode 100644 index 0000000000..2d1b614dfc --- /dev/null +++ b/threadnetwork/aidl/default/socket_interface.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file includes definitions for the Socket interface interface to radio + * (RCP). + */ + +#include "lib/spinel/spinel_interface.hpp" +#include "lib/url/url.hpp" + +namespace aidl { +namespace android { +namespace hardware { +namespace threadnetwork { + +/** + * Defines a Socket interface to the Radio Co-processor (RCP) + * + */ +class SocketInterface : public ot::Spinel::SpinelInterface { + public: + /** + * Initializes the object. + * + * @param[in] aRadioUrl RadioUrl parsed from radio url. + * + */ + explicit SocketInterface(const ot::Url::Url& aRadioUrl); + + /** + * This destructor deinitializes the object. + * + */ + ~SocketInterface(); + + /** + * Returns the RCP interface metrics. + * + * @return The RCP interface metrics. + * + */ + const otRcpInterfaceMetrics* GetRcpInterfaceMetrics(void) const { return &mInterfaceMetrics; } + + /** + * Indicates whether or not the given interface matches this interface name. + * + * @param[in] aInterfaceName A pointer to the interface name. + * + * @retval TRUE The given interface name matches this interface name. + * @retval FALSE The given interface name doesn't match this interface + * name. + */ + static bool IsInterfaceNameMatch(const char* aInterfaceName) { + static const char kInterfaceName[] = "spinel+socket"; + return (strncmp(aInterfaceName, kInterfaceName, strlen(kInterfaceName)) == 0); + } + + private: + ReceiveFrameCallback mReceiveFrameCallback; + void* mReceiveFrameContext; + RxFrameBuffer* mReceiveFrameBuffer; + + int mSockFd; + const ot::Url::Url& mRadioUrl; + + otRcpInterfaceMetrics mInterfaceMetrics; + + // Non-copyable, intentionally not implemented. + SocketInterface(const SocketInterface&); + SocketInterface& operator=(const SocketInterface&); +}; + +} // namespace threadnetwork +} // namespace hardware +} // namespace android +} // namespace aidl From 31ecb33558719aca25afc6fd46e653505683043d Mon Sep 17 00:00:00 2001 From: shihchienc Date: Mon, 29 Jan 2024 08:35:15 +0000 Subject: [PATCH 2/6] [Thread] Implement init/deinit socket interface Bug: 313425570 Test: build pass & manual test Change-Id: I34388f76972f9b88f390a04b100c2fbf61019a1d --- .../aidl/default/socket_interface.cpp | 88 +++++++++++++++++++ .../aidl/default/socket_interface.hpp | 69 +++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/threadnetwork/aidl/default/socket_interface.cpp b/threadnetwork/aidl/default/socket_interface.cpp index 3a8b1cf77a..e42f03db7f 100644 --- a/threadnetwork/aidl/default/socket_interface.cpp +++ b/threadnetwork/aidl/default/socket_interface.cpp @@ -22,6 +22,17 @@ #include "socket_interface.hpp" +#include +#include +#include +#include +#include +#include +#include + +#include "common/code_utils.hpp" +#include "openthread/openthread-system.h" + namespace aidl { namespace android { namespace hardware { @@ -37,6 +48,83 @@ SocketInterface::SocketInterface(const ot::Url::Url& aRadioUrl) mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor; } +otError SocketInterface::Init(ReceiveFrameCallback aCallback, void* aCallbackContext, + RxFrameBuffer& aFrameBuffer) { + otError error = OT_ERROR_NONE; + + VerifyOrExit(mSockFd == -1, error = OT_ERROR_ALREADY); + + mSockFd = OpenFile(mRadioUrl); + VerifyOrExit(mSockFd != -1, error = OT_ERROR_FAILED); + + mReceiveFrameCallback = aCallback; + mReceiveFrameContext = aCallbackContext; + mReceiveFrameBuffer = &aFrameBuffer; + +exit: + return error; +} + +SocketInterface::~SocketInterface(void) { + Deinit(); +} + +void SocketInterface::Deinit(void) { + CloseFile(); + + mReceiveFrameCallback = nullptr; + mReceiveFrameContext = nullptr; + mReceiveFrameBuffer = nullptr; +} + +void SocketInterface::UpdateFdSet(void* aMainloopContext) { + otSysMainloopContext* context = reinterpret_cast(aMainloopContext); + + assert(context != nullptr); + + FD_SET(mSockFd, &context->mReadFdSet); + + if (context->mMaxFd < mSockFd) { + context->mMaxFd = mSockFd; + } +} + +int SocketInterface::OpenFile(const ot::Url::Url& aRadioUrl) { + int fd = -1; + sockaddr_un serverAddress; + + VerifyOrExit(sizeof(serverAddress.sun_path) > strlen(aRadioUrl.GetPath()), + otLogCritPlat("Invalid file path length")); + strncpy(serverAddress.sun_path, aRadioUrl.GetPath(), sizeof(serverAddress.sun_path)); + serverAddress.sun_family = AF_UNIX; + + fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); + VerifyOrExit(fd != -1, otLogCritPlat("open(): errno=%s", strerror(errno))); + + if (connect(fd, reinterpret_cast(&serverAddress), sizeof(serverAddress)) == + -1) { + otLogCritPlat("connect(): errno=%s", strerror(errno)); + close(fd); + fd = -1; + } + +exit: + return fd; +} + +void SocketInterface::CloseFile(void) { + VerifyOrExit(mSockFd != -1); + + VerifyOrExit(0 == close(mSockFd), otLogCritPlat("close(): errno=%s", strerror(errno))); + VerifyOrExit(wait(nullptr) != -1 || errno == ECHILD, + otLogCritPlat("wait(): errno=%s", strerror(errno))); + + mSockFd = -1; + +exit: + return; +} + } // namespace threadnetwork } // namespace hardware } // namespace android diff --git a/threadnetwork/aidl/default/socket_interface.hpp b/threadnetwork/aidl/default/socket_interface.hpp index 2d1b614dfc..5c679cd899 100644 --- a/threadnetwork/aidl/default/socket_interface.hpp +++ b/threadnetwork/aidl/default/socket_interface.hpp @@ -48,6 +48,57 @@ class SocketInterface : public ot::Spinel::SpinelInterface { */ ~SocketInterface(); + /** + * Initializes the interface to the Radio Co-processor (RCP) + * + * @note This method should be called before reading and sending Spinel + * frames to the interface. + * + * @param[in] aCallback Callback on frame received + * @param[in] aCallbackContext Callback context + * @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object. + * + * @retval OT_ERROR_NONE The interface is initialized successfully + * @retval OT_ERROR_ALREADY The interface is already initialized. + * @retval OT_ERROR_FAILED Failed to initialize the interface. + * + */ + otError Init(ReceiveFrameCallback aCallback, void* aCallbackContext, + RxFrameBuffer& aFrameBuffer); + + /** + * Deinitializes the interface to the RCP. + * + */ + void Deinit(void); + + /** + * Updates the file descriptor sets with file descriptors used by the radio + * driver. + * + * @param[in,out] aMainloopContext A pointer to the mainloop context + * containing fd_sets. + * + */ + void UpdateFdSet(void* aMainloopContext); + + /** + * Returns the bus speed between the host and the radio. + * + * @return Bus speed in bits/second. + * + */ + uint32_t GetBusSpeed(void) const { return 1000000; } + + /** + * Hardware resets the RCP. + * + * @retval OT_ERROR_NONE Successfully reset the RCP. + * @retval OT_ERROR_NOT_IMPLEMENT The hardware reset is not implemented. + * + */ + otError HardwareReset(void) { return OT_ERROR_NOT_IMPLEMENTED; } + /** * Returns the RCP interface metrics. * @@ -71,6 +122,24 @@ class SocketInterface : public ot::Spinel::SpinelInterface { } private: + /** + * Opens file specified by aRadioUrl. + * + * @param[in] aRadioUrl A reference to object containing path to file and + * data for configuring the connection with tty type file. + * + * @retval The file descriptor of newly opened file. + * @retval -1 Fail to open file. + * + */ + int OpenFile(const ot::Url::Url& aRadioUrl); + + /** + * Closes file associated with the file descriptor. + * + */ + void CloseFile(void); + ReceiveFrameCallback mReceiveFrameCallback; void* mReceiveFrameContext; RxFrameBuffer* mReceiveFrameBuffer; From 005f602d2323741f287d6f6b02c9333f964593bd Mon Sep 17 00:00:00 2001 From: shihchienc Date: Wed, 31 Jan 2024 07:37:55 +0000 Subject: [PATCH 3/6] [Thread] Wait until socket created to create interface Bug: 313425570 Test: build pass & manual test Change-Id: I4704178519ed032ad352a3ab252e80478c179574 --- .../aidl/default/socket_interface.cpp | 66 +++++++++++++++++++ .../aidl/default/socket_interface.hpp | 24 +++++++ 2 files changed, 90 insertions(+) diff --git a/threadnetwork/aidl/default/socket_interface.cpp b/threadnetwork/aidl/default/socket_interface.cpp index e42f03db7f..a8b434af07 100644 --- a/threadnetwork/aidl/default/socket_interface.cpp +++ b/threadnetwork/aidl/default/socket_interface.cpp @@ -24,14 +24,18 @@ #include #include +#include #include #include #include #include #include +#include + #include "common/code_utils.hpp" #include "openthread/openthread-system.h" +#include "platform-posix.h" namespace aidl { namespace android { @@ -54,6 +58,8 @@ otError SocketInterface::Init(ReceiveFrameCallback aCallback, void* aCallbackCon VerifyOrExit(mSockFd == -1, error = OT_ERROR_ALREADY); + WaitForSocketFileCreated(mRadioUrl.GetPath()); + mSockFd = OpenFile(mRadioUrl); VerifyOrExit(mSockFd != -1, error = OT_ERROR_FAILED); @@ -125,6 +131,66 @@ exit: return; } +void SocketInterface::WaitForSocketFileCreated(const char* aPath) { + int inotifyFd; + int wd; + int lastSlashIdx; + std::string folderPath; + std::string socketPath(aPath); + + VerifyOrExit(!IsSocketFileExisted(aPath)); + + inotifyFd = inotify_init(); + VerifyOrDie(inotifyFd != -1, OT_EXIT_ERROR_ERRNO); + + lastSlashIdx = socketPath.find_last_of('/'); + VerifyOrDie(lastSlashIdx != std::string::npos, OT_EXIT_ERROR_ERRNO); + + folderPath = socketPath.substr(0, lastSlashIdx); + wd = inotify_add_watch(inotifyFd, folderPath.c_str(), IN_CREATE); + VerifyOrDie(wd != -1, OT_EXIT_ERROR_ERRNO); + + otLogInfoPlat("Waiting for socket file %s be created...", aPath); + + while (true) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(inotifyFd, &fds); + struct timeval timeout = {kMaxSelectTimeMs / MS_PER_S, + (kMaxSelectTimeMs % MS_PER_S) * MS_PER_S}; + + int rval = select(inotifyFd + 1, &fds, nullptr, nullptr, &timeout); + VerifyOrDie(rval >= 0, OT_EXIT_ERROR_ERRNO); + + if (rval == 0 && IsSocketFileExisted(aPath)) { + break; + } + + if (FD_ISSET(inotifyFd, &fds)) { + char buffer[sizeof(struct inotify_event)]; + ssize_t bytesRead = read(inotifyFd, buffer, sizeof(buffer)); + + VerifyOrDie(bytesRead >= 0, OT_EXIT_ERROR_ERRNO); + + struct inotify_event* event = reinterpret_cast(buffer); + if ((event->mask & IN_CREATE) && IsSocketFileExisted(aPath)) { + break; + } + } + } + + close(inotifyFd); + +exit: + otLogInfoPlat("Socket file: %s is created", aPath); + return; +} + +bool SocketInterface::IsSocketFileExisted(const char* aPath) { + struct stat st; + return stat(aPath, &st) == 0 && S_ISSOCK(st.st_mode); +} + } // namespace threadnetwork } // namespace hardware } // namespace android diff --git a/threadnetwork/aidl/default/socket_interface.hpp b/threadnetwork/aidl/default/socket_interface.hpp index 5c679cd899..23940f5fda 100644 --- a/threadnetwork/aidl/default/socket_interface.hpp +++ b/threadnetwork/aidl/default/socket_interface.hpp @@ -140,6 +140,30 @@ class SocketInterface : public ot::Spinel::SpinelInterface { */ void CloseFile(void); + /** + * Check if socket file is created. + * + * @param[in] aPath Socket file path name. + * + * @retval TRUE The required socket file is created. + * @retval FALSE The required socket file is not created. + * + */ + bool IsSocketFileExisted(const char* aPath); + + /** + * Wait until the socket file is created. + * + * @param[in] aPath Socket file path name. + * + */ + void WaitForSocketFileCreated(const char* aPath); + + enum { + kMaxSelectTimeMs = 2000, ///< Maximum wait time in Milliseconds for file + ///< descriptor to become available. + }; + ReceiveFrameCallback mReceiveFrameCallback; void* mReceiveFrameContext; RxFrameBuffer* mReceiveFrameBuffer; From 5b2cd323685d6ca9b1a2feb3aae26ed67aec9e43 Mon Sep 17 00:00:00 2001 From: shihchienc Date: Wed, 31 Jan 2024 07:13:52 +0000 Subject: [PATCH 4/6] [Thread] Implement write on socket interface Bug: 313425570 Test: build pass & manual test Change-Id: I2da14a563b795b0044362c1c248b53c1d3505d39 --- .../aidl/default/socket_interface.cpp | 12 ++++++++++ .../aidl/default/socket_interface.hpp | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/threadnetwork/aidl/default/socket_interface.cpp b/threadnetwork/aidl/default/socket_interface.cpp index a8b434af07..6b9b80eb07 100644 --- a/threadnetwork/aidl/default/socket_interface.cpp +++ b/threadnetwork/aidl/default/socket_interface.cpp @@ -83,6 +83,12 @@ void SocketInterface::Deinit(void) { mReceiveFrameBuffer = nullptr; } +otError SocketInterface::SendFrame(const uint8_t* aFrame, uint16_t aLength) { + Write(aFrame, aLength); + + return OT_ERROR_NONE; +} + void SocketInterface::UpdateFdSet(void* aMainloopContext) { otSysMainloopContext* context = reinterpret_cast(aMainloopContext); @@ -95,6 +101,12 @@ void SocketInterface::UpdateFdSet(void* aMainloopContext) { } } +void SocketInterface::Write(const uint8_t* aFrame, uint16_t aLength) { + ssize_t rval = TEMP_FAILURE_RETRY(write(mSockFd, aFrame, aLength)); + VerifyOrDie(rval >= 0, OT_EXIT_ERROR_ERRNO); + VerifyOrDie(rval > 0, OT_EXIT_FAILURE); +} + int SocketInterface::OpenFile(const ot::Url::Url& aRadioUrl) { int fd = -1; sockaddr_un serverAddress; diff --git a/threadnetwork/aidl/default/socket_interface.hpp b/threadnetwork/aidl/default/socket_interface.hpp index 23940f5fda..2dd315d125 100644 --- a/threadnetwork/aidl/default/socket_interface.hpp +++ b/threadnetwork/aidl/default/socket_interface.hpp @@ -72,6 +72,20 @@ class SocketInterface : public ot::Spinel::SpinelInterface { */ void Deinit(void); + /** + * Sends a Spinel frame to Radio Co-processor (RCP) over the + * socket. + * + * @param[in] aFrame A pointer to buffer containing the Spinel frame to + * send. + * @param[in] aLength The length (number of bytes) in the frame. + * + * @retval OT_ERROR_NONE Successfully sent the Spinel frame. + * @retval OT_ERROR_FAILED Failed to send a frame. + * + */ + otError SendFrame(const uint8_t* aFrame, uint16_t aLength); + /** * Updates the file descriptor sets with file descriptors used by the radio * driver. @@ -122,6 +136,15 @@ class SocketInterface : public ot::Spinel::SpinelInterface { } private: + /** + * Writes a given frame to the socket. + * + * @param[in] aFrame A pointer to buffer containing the frame to write. + * @param[in] aLength The length (number of bytes) in the frame. + * + */ + void Write(const uint8_t* aFrame, uint16_t aLength); + /** * Opens file specified by aRadioUrl. * From 1623351bc0af51511b762dfad4cf2ab1d7d4bbf3 Mon Sep 17 00:00:00 2001 From: shihchienc Date: Mon, 29 Jan 2024 10:07:47 +0000 Subject: [PATCH 5/6] [Thread] Implement read on socket interface Bug: 313425570 Test: build pass & manual test Change-Id: I4e6dfdfa73f7145e8f36d05abf1531d7796b4b9e --- .../aidl/default/socket_interface.cpp | 92 +++++++++++++++++++ .../aidl/default/socket_interface.hpp | 51 ++++++++++ 2 files changed, 143 insertions(+) diff --git a/threadnetwork/aidl/default/socket_interface.cpp b/threadnetwork/aidl/default/socket_interface.cpp index 6b9b80eb07..f874209aaf 100644 --- a/threadnetwork/aidl/default/socket_interface.cpp +++ b/threadnetwork/aidl/default/socket_interface.cpp @@ -89,6 +89,41 @@ otError SocketInterface::SendFrame(const uint8_t* aFrame, uint16_t aLength) { return OT_ERROR_NONE; } +otError SocketInterface::WaitForFrame(uint64_t aTimeoutUs) { + otError error = OT_ERROR_NONE; + struct timeval timeout; + timeout.tv_sec = static_cast(aTimeoutUs / US_PER_S); + timeout.tv_usec = static_cast(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) { otSysMainloopContext* context = reinterpret_cast(aMainloopContext); @@ -101,12 +136,69 @@ void SocketInterface::UpdateFdSet(void* aMainloopContext) { } } +void SocketInterface::Process(const void* aMainloopContext) { + const otSysMainloopContext* context = + reinterpret_cast(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(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) { ssize_t rval = TEMP_FAILURE_RETRY(write(mSockFd, aFrame, aLength)); VerifyOrDie(rval >= 0, OT_EXIT_ERROR_ERRNO); 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(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 fd = -1; sockaddr_un serverAddress; diff --git a/threadnetwork/aidl/default/socket_interface.hpp b/threadnetwork/aidl/default/socket_interface.hpp index 2dd315d125..f88e92670c 100644 --- a/threadnetwork/aidl/default/socket_interface.hpp +++ b/threadnetwork/aidl/default/socket_interface.hpp @@ -86,6 +86,21 @@ class SocketInterface : public ot::Spinel::SpinelInterface { */ 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 * driver. @@ -96,6 +111,15 @@ class SocketInterface : public ot::Spinel::SpinelInterface { */ 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. * @@ -136,6 +160,17 @@ class SocketInterface : public ot::Spinel::SpinelInterface { } 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. * @@ -145,6 +180,22 @@ class SocketInterface : public ot::Spinel::SpinelInterface { */ 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. * From 27711c319508b65a4cfb4e4209dc46a34d61f5dd Mon Sep 17 00:00:00 2001 From: shihchienc Date: Wed, 24 Jan 2024 09:05:34 +0000 Subject: [PATCH 6/6] [Thread] Add socket interface support in thread chip Bug: 313425570 Test: build pass & manual test Change-Id: Ie1b0c687cf529659521f1dd1457fcda35af1bf49 --- threadnetwork/aidl/default/thread_chip.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/threadnetwork/aidl/default/thread_chip.cpp b/threadnetwork/aidl/default/thread_chip.cpp index ed34e630b8..d1e1d4ceaf 100644 --- a/threadnetwork/aidl/default/thread_chip.cpp +++ b/threadnetwork/aidl/default/thread_chip.cpp @@ -24,6 +24,7 @@ #include #include "hdlc_interface.hpp" +#include "socket_interface.hpp" #include "spi_interface.hpp" namespace aidl { @@ -43,6 +44,8 @@ ThreadChip::ThreadChip(char* url) : mUrl(), mRxFrameBuffer(), mCallback(nullptr) mSpinelInterface = std::make_shared(mUrl); } else if (ot::Posix::HdlcInterface::IsInterfaceNameMatch(interfaceName)) { mSpinelInterface = std::make_shared(mUrl); + } else if (SocketInterface::IsInterfaceNameMatch(interfaceName)) { + mSpinelInterface = std::make_shared(mUrl); } else { ALOGE("The interface \"%s\" is not supported", interfaceName); exit(EXIT_FAILURE);