Merge "[Thread] Implement hardware reset" into main
diff --git a/threadnetwork/aidl/default/socket_interface.cpp b/threadnetwork/aidl/default/socket_interface.cpp
index 0544502..339fd6b 100644
--- a/threadnetwork/aidl/default/socket_interface.cpp
+++ b/threadnetwork/aidl/default/socket_interface.cpp
@@ -33,6 +33,7 @@
#include <unistd.h>
#include <string>
+#include <vector>
#include "common/code_utils.hpp"
#include "openthread/openthread-system.h"
@@ -49,10 +50,8 @@
: mReceiveFrameCallback(nullptr),
mReceiveFrameContext(nullptr),
mReceiveFrameBuffer(nullptr),
- mSockFd(-1),
mRadioUrl(aRadioUrl) {
- memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
- mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor;
+ ResetStates();
}
otError SocketInterface::Init(ReceiveFrameCallback aCallback, void* aCallbackContext,
@@ -120,13 +119,50 @@
} else if (rval == 0) {
ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT);
} else {
- DieNowWithMessage("wait response", OT_EXIT_FAILURE);
+ DieNowWithMessage("Wait response", OT_EXIT_FAILURE);
}
exit:
return error;
}
+otError SocketInterface::WaitForHardwareResetCompletion(uint32_t aTimeoutMs) {
+ otError error = OT_ERROR_NONE;
+ int retries = 0;
+ int rval;
+
+ while (mIsHardwareResetting && retries++ < kMaxRetriesForSocketCloseCheck) {
+ struct timeval timeout;
+ timeout.tv_sec = static_cast<time_t>(aTimeoutMs / MS_PER_S);
+ timeout.tv_usec = static_cast<suseconds_t>((aTimeoutMs % MS_PER_S) * MS_PER_S);
+
+ fd_set readFds;
+
+ FD_ZERO(&readFds);
+ FD_SET(mSockFd, &readFds);
+
+ rval = TEMP_FAILURE_RETRY(select(mSockFd + 1, &readFds, nullptr, nullptr, &timeout));
+
+ if (rval > 0) {
+ Read();
+ } else if (rval < 0) {
+ DieNowWithMessage("Wait response", OT_EXIT_ERROR_ERRNO);
+ } else {
+ LogInfo("Waiting for hardware reset, retry attempt: %d, max attempt: %d", retries,
+ kMaxRetriesForSocketCloseCheck);
+ }
+ }
+
+ VerifyOrExit(!mIsHardwareResetting, error = OT_ERROR_FAILED);
+
+ WaitForSocketFileCreated(mRadioUrl.GetPath());
+ mSockFd = OpenFile(mRadioUrl);
+ VerifyOrExit(mSockFd != -1, error = OT_ERROR_FAILED);
+
+exit:
+ return error;
+}
+
void SocketInterface::UpdateFdSet(void* aMainloopContext) {
otSysMainloopContext* context = reinterpret_cast<otSysMainloopContext*>(aMainloopContext);
@@ -150,6 +186,16 @@
}
}
+otError SocketInterface::HardwareReset(void) {
+ otError error = OT_ERROR_NONE;
+ std::vector<uint8_t> resetCommand = {SPINEL_HEADER_FLAG, SPINEL_CMD_RESET, 0x04};
+
+ mIsHardwareResetting = true;
+ SendFrame(resetCommand.data(), resetCommand.size());
+
+ return WaitForHardwareResetCompletion(kMaxSelectTimeMs);
+}
+
void SocketInterface::Read(void) {
uint8_t buffer[kMaxFrameSize];
@@ -160,8 +206,13 @@
} else if (rval < 0) {
DieNow(OT_EXIT_ERROR_ERRNO);
} else {
- LogCrit("Socket connection is closed by remote.");
- exit(OT_EXIT_FAILURE);
+ if (mIsHardwareResetting) {
+ LogInfo("Socket connection is closed due to hardware reset.");
+ ResetStates();
+ } else {
+ LogCrit("Socket connection is closed by remote.");
+ exit(OT_EXIT_FAILURE);
+ }
}
}
@@ -298,6 +349,13 @@
return stat(aPath, &st) == 0 && S_ISSOCK(st.st_mode);
}
+void SocketInterface::ResetStates() {
+ mSockFd = -1;
+ mIsHardwareResetting = false;
+ memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
+ mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor;
+}
+
} // namespace threadnetwork
} // namespace hardware
} // namespace android
diff --git a/threadnetwork/aidl/default/socket_interface.hpp b/threadnetwork/aidl/default/socket_interface.hpp
index 6f3be7f..494d76a 100644
--- a/threadnetwork/aidl/default/socket_interface.hpp
+++ b/threadnetwork/aidl/default/socket_interface.hpp
@@ -136,10 +136,10 @@
* Hardware resets the RCP.
*
* @retval OT_ERROR_NONE Successfully reset the RCP.
- * @retval OT_ERROR_NOT_IMPLEMENT The hardware reset is not implemented.
+ * @retval OT_ERROR_FAILED Hardware reset is failed.
*
*/
- otError HardwareReset(void) { return OT_ERROR_NOT_IMPLEMENTED; }
+ otError HardwareReset(void);
/**
* Returns the RCP interface metrics.
@@ -237,9 +237,26 @@
*/
void WaitForSocketFileCreated(const char* aPath);
+ /**
+ * Wait for the hardware reset completion signal.
+ *
+ * @retval OT_ERROR_NONE Hardware reset is successfully.
+ * @retval OT_ERROR_FAILED Hardware reset is failed.
+ *
+ */
+ otError WaitForHardwareResetCompletion(uint32_t aTimeoutMs);
+
+ /**
+ * Reset socket interface to intitial state.
+ *
+ */
+ void ResetStates(void);
+
enum {
- kMaxSelectTimeMs = 2000, ///< Maximum wait time in Milliseconds for file
- ///< descriptor to become available.
+ kMaxSelectTimeMs = 2000, ///< Maximum wait time in Milliseconds for file
+ ///< descriptor to become available.
+ kMaxRetriesForSocketCloseCheck = 3, ///< Maximum retry times for checking
+ ///< if socket is closed.
};
ReceiveFrameCallback mReceiveFrameCallback;
@@ -249,6 +266,8 @@
int mSockFd;
const ot::Url::Url& mRadioUrl;
+ bool mIsHardwareResetting;
+
otRcpInterfaceMetrics mInterfaceMetrics;
// Non-copyable, intentionally not implemented.