add Spinel SPI interface support

This commit enables the Thread Network HAL to support the Spinel
SPI interface.

Bug: 277286756
Test: Build and run otbr-agent on the emulator.
Change-Id: I6726eead5686f0afb33e5e2035ebc9021eca5afa
diff --git a/threadnetwork/aidl/default/Android.bp b/threadnetwork/aidl/default/Android.bp
index 736e808..8b938d2 100644
--- a/threadnetwork/aidl/default/Android.bp
+++ b/threadnetwork/aidl/default/Android.bp
@@ -29,6 +29,7 @@
         "openthread-hdlc",
         "openthread-platform",
         "openthread-posix",
+        "openthread-spi",
         "openthread-url",
     ],
 
@@ -68,6 +69,7 @@
         "openthread-hdlc",
         "openthread-platform",
         "openthread-posix",
+        "openthread-spi",
         "openthread-url",
     ],
 
diff --git a/threadnetwork/aidl/default/thread_chip.cpp b/threadnetwork/aidl/default/thread_chip.cpp
index e542c7c..94d1e93 100644
--- a/threadnetwork/aidl/default/thread_chip.cpp
+++ b/threadnetwork/aidl/default/thread_chip.cpp
@@ -21,17 +21,36 @@
 #include <android/binder_process.h>
 #include <utils/Log.h>
 
+#include "hdlc_interface.hpp"
+#include "spi_interface.hpp"
+
 namespace aidl {
 namespace android {
 namespace hardware {
 namespace threadnetwork {
 
-ThreadChip::ThreadChip(char* url)
-    : mUrl(),
-      mInterface(handleReceivedFrame, this, mRxFrameBuffer),
-      mRxFrameBuffer(),
-      mCallback(nullptr) {
+ThreadChip::ThreadChip(char* url) : mUrl(), mRxFrameBuffer(), mCallback(nullptr) {
+    static const char kHdlcProtocol[] = "spinel+hdlc";
+    static const char kSpiProtocol[] = "spinel+spi";
+    const char* protocol;
+
     CHECK_EQ(mUrl.Init(url), 0);
+
+    protocol = mUrl.GetProtocol();
+    CHECK_NE(protocol, nullptr);
+
+    if (memcmp(protocol, kSpiProtocol, strlen(kSpiProtocol)) == 0) {
+        mSpinelInterface = std::make_shared<ot::Posix::SpiInterface>(handleReceivedFrameJump, this,
+                                                                     mRxFrameBuffer);
+    } else if (memcmp(protocol, kHdlcProtocol, strlen(kHdlcProtocol)) == 0) {
+        mSpinelInterface = std::make_shared<ot::Posix::HdlcInterface>(handleReceivedFrameJump, this,
+                                                                      mRxFrameBuffer);
+    } else {
+        ALOGE("The protocol \"%s\" is not supported!", protocol);
+        exit(1);
+    }
+
+    CHECK_NE(mSpinelInterface, nullptr);
 }
 
 void ThreadChip::clientDeathCallback(void* context) {
@@ -43,7 +62,7 @@
     close();
 }
 
-void ThreadChip::handleReceivedFrame(void* context) {
+void ThreadChip::handleReceivedFrameJump(void* context) {
     static_cast<ThreadChip*>(context)->handleReceivedFrame();
 }
 
@@ -70,7 +89,7 @@
     mBinderDeathRecipient = AIBinder_DeathRecipient_new(clientDeathCallback);
     VerifyOrExit(AIBinder_linkToDeath(binder, mBinderDeathRecipient, this) == STATUS_OK,
                  status = errorStatus(ERROR_FAILED, "Failed to link the binder to death"));
-    VerifyOrExit(mInterface.Init(mUrl) == OT_ERROR_NONE,
+    VerifyOrExit(mSpinelInterface->Init(mUrl) == OT_ERROR_NONE,
                  status = errorStatus(ERROR_FAILED, "Failed to initialize the interface"));
 
     mCallback = in_callback;
@@ -94,7 +113,7 @@
 ndk::ScopedAStatus ThreadChip::close() {
     VerifyOrExit(mCallback != nullptr);
     mCallback = nullptr;
-    mInterface.Deinit();
+    mSpinelInterface->Deinit();
 
     ot::Posix::Mainloop::Manager::Get().Remove(*this);
 
@@ -113,8 +132,8 @@
     VerifyOrExit(mCallback != nullptr,
                  status = errorStatus(ERROR_FAILED, "The interface is not open"));
 
-    error = mInterface.SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
-                                 in_frame.size());
+    error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
+                                        in_frame.size());
     if (error == OT_ERROR_NONE) {
         status = ndk::ScopedAStatus::ok();
     } else if (error == OT_ERROR_NO_BUFS) {
@@ -134,20 +153,20 @@
 }
 
 ndk::ScopedAStatus ThreadChip::reset() {
-    mInterface.HardwareReset();
+    mSpinelInterface->HardwareReset();
     ALOGI("reset()");
     return ndk::ScopedAStatus::ok();
 }
 
 void ThreadChip::Update(otSysMainloopContext& context) {
     if (mCallback != nullptr) {
-        mInterface.UpdateFdSet(&context);
+        mSpinelInterface->UpdateFdSet(&context);
     }
 }
 
 void ThreadChip::Process(const otSysMainloopContext& context) {
     if (mCallback != nullptr) {
-        mInterface.Process(&context);
+        mSpinelInterface->Process(&context);
     }
 }
 
diff --git a/threadnetwork/aidl/default/thread_chip.hpp b/threadnetwork/aidl/default/thread_chip.hpp
index d93dfef..294190a 100644
--- a/threadnetwork/aidl/default/thread_chip.hpp
+++ b/threadnetwork/aidl/default/thread_chip.hpp
@@ -19,7 +19,6 @@
 #include <aidl/android/hardware/threadnetwork/BnThreadChip.h>
 #include <aidl/android/hardware/threadnetwork/IThreadChipCallback.h>
 
-#include "hdlc_interface.hpp"
 #include "lib/spinel/spinel_interface.hpp"
 #include "mainloop.hpp"
 
@@ -45,12 +44,12 @@
   private:
     static void clientDeathCallback(void* context);
     void clientDeathCallback(void);
-    static void handleReceivedFrame(void* context);
+    static void handleReceivedFrameJump(void* context);
     void handleReceivedFrame(void);
     ndk::ScopedAStatus errorStatus(int32_t error, const char* message);
 
     ot::Url::Url mUrl;
-    ot::Posix::HdlcInterface mInterface;
+    std::shared_ptr<ot::Spinel::SpinelInterface> mSpinelInterface;
     ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
     std::shared_ptr<IThreadChipCallback> mCallback;
     AIBinder_DeathRecipient* mBinderDeathRecipient;
diff --git a/threadnetwork/aidl/default/utils.cpp b/threadnetwork/aidl/default/utils.cpp
index b4da7d7..1cb42ec 100644
--- a/threadnetwork/aidl/default/utils.cpp
+++ b/threadnetwork/aidl/default/utils.cpp
@@ -36,6 +36,45 @@
     va_end(args);
 }
 
+void otLogNotePlat(const char* format, ...) {
+    va_list args;
+
+    va_start(args, format);
+    __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
+    va_end(args);
+}
+
+void otLogInfoPlat(const char* format, ...) {
+    va_list args;
+
+    va_start(args, format);
+    __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
+    va_end(args);
+}
+
+void otLogDebgPlat(const char* format, ...) {
+    va_list args;
+
+    va_start(args, format);
+    __android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, format, args);
+    va_end(args);
+}
+
+void otDumpDebgPlat(const char* aText, const void* aData, uint16_t aDataLength) {
+    constexpr uint16_t kBufSize = 512;
+    char buf[kBufSize];
+
+    if ((aText != nullptr) && (aData != nullptr)) {
+        const uint8_t* data = reinterpret_cast<const uint8_t*>(aData);
+
+        for (uint16_t i = 0; (i < aDataLength) && (i < (kBufSize - 1) / 3); i++) {
+            snprintf(buf + (i * 3), (kBufSize - 1) - (i * 3), "%02x ", data[i]);
+        }
+
+        __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "%s: %s", aText, buf);
+    }
+}
+
 OT_TOOL_WEAK void otPlatAlarmMilliFired(otInstance* aInstance) {
     OT_UNUSED_VARIABLE(aInstance);
 }