/* * Copyright (C) 2022 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. */ #include "thread_chip.hpp" #include #include #include #include #include #include #include "hdlc_interface.hpp" #include "socket_interface.hpp" #include "spi_interface.hpp" namespace aidl { namespace android { namespace hardware { namespace threadnetwork { ThreadChip::ThreadChip(const char* url) : mUrl(url), mRxFrameBuffer(), mCallback(nullptr) { const char* interfaceName; interfaceName = mUrl.GetProtocol(); CHECK_NE(interfaceName, nullptr); if (ot::Posix::SpiInterface::IsInterfaceNameMatch(interfaceName)) { 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); } CHECK_NE(mSpinelInterface, nullptr); mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient( AIBinder_DeathRecipient_new(ThreadChip::onBinderDiedJump)); AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinkedJump); } void ThreadChip::onBinderDiedJump(void* context) { reinterpret_cast(context)->onBinderDied(); } void ThreadChip::onBinderDied(void) { ALOGW("Thread Network HAL client is dead"); } void ThreadChip::onBinderUnlinkedJump(void* context) { reinterpret_cast(context)->onBinderUnlinked(); } void ThreadChip::onBinderUnlinked(void) { ALOGW("ThreadChip binder is unlinked"); deinitChip(); } void ThreadChip::handleReceivedFrameJump(void* context) { static_cast(context)->handleReceivedFrame(); } void ThreadChip::handleReceivedFrame(void) { if (mCallback != nullptr) { mCallback->onReceiveSpinelFrame(std::vector( mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetFrame() + mRxFrameBuffer.GetLength())); } mRxFrameBuffer.DiscardFrame(); } ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr& in_callback) { ndk::ScopedAStatus status = initChip(in_callback); if (status.isOk()) { AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this); ALOGI("Open IThreadChip successfully"); } else { ALOGW("Failed to open IThreadChip: %s", status.getDescription().c_str()); } return status; } ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr& in_callback) { if (in_callback == nullptr) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } else if (mCallback == nullptr) { if (mSpinelInterface->Init(handleReceivedFrameJump, this, mRxFrameBuffer) != OT_ERROR_NONE) { return errorStatus(ERROR_FAILED, "Failed to initialize the interface"); } mCallback = in_callback; ot::Posix::Mainloop::Manager::Get().Add(*this); return ndk::ScopedAStatus::ok(); } else { return errorStatus(ERROR_BUSY, "Interface has been opened"); } } ndk::ScopedAStatus ThreadChip::close() { ndk::ScopedAStatus status; std::shared_ptr callback = mCallback; status = deinitChip(); if (status.isOk()) { if (callback != nullptr) { AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this); } ALOGI("Close IThreadChip successfully"); } else { ALOGW("Failed to close IThreadChip: %s", status.getDescription().c_str()); } return status; } ndk::ScopedAStatus ThreadChip::deinitChip() { if (mCallback != nullptr) { mSpinelInterface->Deinit(); ot::Posix::Mainloop::Manager::Get().Remove(*this); mCallback = nullptr; return ndk::ScopedAStatus::ok(); } return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector& in_frame) { ndk::ScopedAStatus status; otError error; if (mCallback == nullptr) { status = errorStatus(ERROR_FAILED, "The interface is not open"); } else { error = mSpinelInterface->SendFrame(reinterpret_cast(in_frame.data()), in_frame.size()); if (error == OT_ERROR_NONE) { status = ndk::ScopedAStatus::ok(); } else if (error == OT_ERROR_NO_BUFS) { status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send"); } else if (error == OT_ERROR_BUSY) { status = errorStatus(ERROR_BUSY, "The interface is busy"); } else { status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame"); } } if (!status.isOk()) { ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str()); } return status; } ndk::ScopedAStatus ThreadChip::hardwareReset() { if (mSpinelInterface->HardwareReset() == OT_ERROR_NOT_IMPLEMENTED) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } ALOGI("reset()"); return ndk::ScopedAStatus::ok(); } void ThreadChip::Update(otSysMainloopContext& context) { if (mCallback != nullptr) { mSpinelInterface->UpdateFdSet(&context); } } void ThreadChip::Process(const otSysMainloopContext& context) { if (mCallback != nullptr) { mSpinelInterface->Process(&context); } } ndk::ScopedAStatus ThreadChip::errorStatus(int32_t error, const char* message) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(error, message)); } } // namespace threadnetwork } // namespace hardware } // namespace android } // namespace aidl