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
This commit is contained in:
Zhanglong Xia 2023-07-03 10:52:45 +08:00
parent 59b018679b
commit 7ae6d6f4ff
4 changed files with 75 additions and 16 deletions

View file

@ -29,6 +29,7 @@ cc_defaults {
"openthread-hdlc", "openthread-hdlc",
"openthread-platform", "openthread-platform",
"openthread-posix", "openthread-posix",
"openthread-spi",
"openthread-url", "openthread-url",
], ],
@ -68,6 +69,7 @@ cc_fuzz {
"openthread-hdlc", "openthread-hdlc",
"openthread-platform", "openthread-platform",
"openthread-posix", "openthread-posix",
"openthread-spi",
"openthread-url", "openthread-url",
], ],

View file

@ -21,17 +21,36 @@
#include <android/binder_process.h> #include <android/binder_process.h>
#include <utils/Log.h> #include <utils/Log.h>
#include "hdlc_interface.hpp"
#include "spi_interface.hpp"
namespace aidl { namespace aidl {
namespace android { namespace android {
namespace hardware { namespace hardware {
namespace threadnetwork { namespace threadnetwork {
ThreadChip::ThreadChip(char* url) ThreadChip::ThreadChip(char* url) : mUrl(), mRxFrameBuffer(), mCallback(nullptr) {
: mUrl(), static const char kHdlcProtocol[] = "spinel+hdlc";
mInterface(handleReceivedFrame, this, mRxFrameBuffer), static const char kSpiProtocol[] = "spinel+spi";
mRxFrameBuffer(), const char* protocol;
mCallback(nullptr) {
CHECK_EQ(mUrl.Init(url), 0); 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) { void ThreadChip::clientDeathCallback(void* context) {
@ -43,7 +62,7 @@ void ThreadChip::clientDeathCallback(void) {
close(); close();
} }
void ThreadChip::handleReceivedFrame(void* context) { void ThreadChip::handleReceivedFrameJump(void* context) {
static_cast<ThreadChip*>(context)->handleReceivedFrame(); static_cast<ThreadChip*>(context)->handleReceivedFrame();
} }
@ -70,7 +89,7 @@ ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr<IThreadChipCallback>&
mBinderDeathRecipient = AIBinder_DeathRecipient_new(clientDeathCallback); mBinderDeathRecipient = AIBinder_DeathRecipient_new(clientDeathCallback);
VerifyOrExit(AIBinder_linkToDeath(binder, mBinderDeathRecipient, this) == STATUS_OK, VerifyOrExit(AIBinder_linkToDeath(binder, mBinderDeathRecipient, this) == STATUS_OK,
status = errorStatus(ERROR_FAILED, "Failed to link the binder to death")); 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")); status = errorStatus(ERROR_FAILED, "Failed to initialize the interface"));
mCallback = in_callback; mCallback = in_callback;
@ -94,7 +113,7 @@ exit:
ndk::ScopedAStatus ThreadChip::close() { ndk::ScopedAStatus ThreadChip::close() {
VerifyOrExit(mCallback != nullptr); VerifyOrExit(mCallback != nullptr);
mCallback = nullptr; mCallback = nullptr;
mInterface.Deinit(); mSpinelInterface->Deinit();
ot::Posix::Mainloop::Manager::Get().Remove(*this); ot::Posix::Mainloop::Manager::Get().Remove(*this);
@ -113,7 +132,7 @@ ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector<uint8_t>& in_fr
VerifyOrExit(mCallback != nullptr, VerifyOrExit(mCallback != nullptr,
status = errorStatus(ERROR_FAILED, "The interface is not open")); status = errorStatus(ERROR_FAILED, "The interface is not open"));
error = mInterface.SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()), error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
in_frame.size()); in_frame.size());
if (error == OT_ERROR_NONE) { if (error == OT_ERROR_NONE) {
status = ndk::ScopedAStatus::ok(); status = ndk::ScopedAStatus::ok();
@ -134,20 +153,20 @@ exit:
} }
ndk::ScopedAStatus ThreadChip::reset() { ndk::ScopedAStatus ThreadChip::reset() {
mInterface.HardwareReset(); mSpinelInterface->HardwareReset();
ALOGI("reset()"); ALOGI("reset()");
return ndk::ScopedAStatus::ok(); return ndk::ScopedAStatus::ok();
} }
void ThreadChip::Update(otSysMainloopContext& context) { void ThreadChip::Update(otSysMainloopContext& context) {
if (mCallback != nullptr) { if (mCallback != nullptr) {
mInterface.UpdateFdSet(&context); mSpinelInterface->UpdateFdSet(&context);
} }
} }
void ThreadChip::Process(const otSysMainloopContext& context) { void ThreadChip::Process(const otSysMainloopContext& context) {
if (mCallback != nullptr) { if (mCallback != nullptr) {
mInterface.Process(&context); mSpinelInterface->Process(&context);
} }
} }

View file

@ -19,7 +19,6 @@
#include <aidl/android/hardware/threadnetwork/BnThreadChip.h> #include <aidl/android/hardware/threadnetwork/BnThreadChip.h>
#include <aidl/android/hardware/threadnetwork/IThreadChipCallback.h> #include <aidl/android/hardware/threadnetwork/IThreadChipCallback.h>
#include "hdlc_interface.hpp"
#include "lib/spinel/spinel_interface.hpp" #include "lib/spinel/spinel_interface.hpp"
#include "mainloop.hpp" #include "mainloop.hpp"
@ -45,12 +44,12 @@ class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source {
private: private:
static void clientDeathCallback(void* context); static void clientDeathCallback(void* context);
void clientDeathCallback(void); void clientDeathCallback(void);
static void handleReceivedFrame(void* context); static void handleReceivedFrameJump(void* context);
void handleReceivedFrame(void); void handleReceivedFrame(void);
ndk::ScopedAStatus errorStatus(int32_t error, const char* message); ndk::ScopedAStatus errorStatus(int32_t error, const char* message);
ot::Url::Url mUrl; ot::Url::Url mUrl;
ot::Posix::HdlcInterface mInterface; std::shared_ptr<ot::Spinel::SpinelInterface> mSpinelInterface;
ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer; ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
std::shared_ptr<IThreadChipCallback> mCallback; std::shared_ptr<IThreadChipCallback> mCallback;
AIBinder_DeathRecipient* mBinderDeathRecipient; AIBinder_DeathRecipient* mBinderDeathRecipient;

View file

@ -36,6 +36,45 @@ void otLogWarnPlat(const char* format, ...) {
va_end(args); 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_TOOL_WEAK void otPlatAlarmMilliFired(otInstance* aInstance) {
OT_UNUSED_VARIABLE(aInstance); OT_UNUSED_VARIABLE(aInstance);
} }