| /****************************************************************************** |
| * |
| * Copyright (C) 1999-2012 Broadcom Corporation |
| * Copyright 2018-2019 NXP |
| * |
| * 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 "UwbAdaptation.h" |
| |
| #include <aidl/android/hardware/uwb/BnUwb.h> |
| #include <aidl/android/hardware/uwb/BnUwbClientCallback.h> |
| #include <aidl/android/hardware/uwb/IUwb.h> |
| #include <aidl/android/hardware/uwb/IUwbChip.h> |
| #include <android-base/logging.h> |
| #include <android/binder_ibinder.h> |
| #include <android/binder_manager.h> |
| #include <android/binder_process.h> |
| #include <binder/IMemory.h> |
| #include <binder/IServiceManager.h> |
| #include <binder/MemoryDealer.h> |
| #include <cutils/properties.h> |
| #include <pthread.h> |
| |
| #include <algorithm> |
| |
| #include "uci_log.h" |
| #include "uwa_api.h" |
| #include "uwb_config.h" |
| #include "uwb_hal_int.h" |
| #include "uwb_int.h" |
| #include "uwb_target.h" |
| |
| using IUwbV1_0 = aidl::android::hardware::uwb::IUwb; |
| using IUwbChipV1_0 = aidl::android::hardware::uwb::IUwbChip; |
| using UwbStatus = aidl::android::hardware::uwb::UwbStatus; |
| using aidl::android::hardware::uwb::BnUwbClientCallback; |
| using aidl::android::hardware::uwb::IUwbClientCallback; |
| |
| std::string UWB_HAL_SERVICE_NAME = "android.hardware.uwb.IUwb/default"; |
| extern bool uwb_debug_enabled; |
| |
| bool uwb_debug_enabled = false; |
| bool IsdebugLogEnabled = false; |
| |
| extern void phUwb_GKI_shutdown(); |
| |
| UwbAdaptation* UwbAdaptation::mpInstance = NULL; |
| ThreadMutex UwbAdaptation::sLock; |
| ThreadMutex UwbAdaptation::sIoctlLock; |
| std::mutex sIoctlMutex; |
| |
| tHAL_UWB_CBACK* UwbAdaptation::mHalCallback = NULL; |
| tHAL_UWB_DATA_CBACK* UwbAdaptation::mHalDataCallback = NULL; |
| std::shared_ptr<IUwbChipV1_0> mHal = nullptr; |
| |
| namespace { |
| void initializeGlobalDebugEnabledFlag() { |
| uwb_debug_enabled = true; |
| |
| UCI_TRACE_I("%s: Debug log is enabled =%u", __func__, uwb_debug_enabled); |
| } |
| |
| std::shared_ptr<IUwbChipV1_0> getHalService() { |
| ::ndk::SpAIBinder binder(AServiceManager_getService(UWB_HAL_SERVICE_NAME.c_str())); |
| std::shared_ptr<IUwbV1_0> iUwb = IUwbV1_0::fromBinder(binder); |
| if (iUwb == nullptr) { |
| ALOGE("Failed to connect to the AIDL HAL service."); |
| return nullptr; |
| } |
| std::vector<std::string> chipNames; |
| ndk::ScopedAStatus status = iUwb->getChips(&chipNames); |
| if (!status.isOk() || chipNames.empty()) { |
| ALOGE("Failed to retrieve the HAL chip names"); |
| return nullptr; |
| } |
| // TODO (b/197638976): We pick the first chip here. Need to fix this |
| // for supporting multiple chips in the future. |
| std::shared_ptr<IUwbChipV1_0> iUwbChip; |
| status = iUwb->getChip(chipNames.front(), &iUwbChip); |
| if (!status.isOk() || iUwbChip == nullptr) { |
| ALOGE("Failed to retrieve the HAL chip"); |
| return nullptr; |
| } |
| return iUwbChip; |
| } |
| |
| } // namespace |
| |
| class UwbClientCallback |
| : public aidl::android::hardware::uwb::BnUwbClientCallback { |
| public: |
| UwbClientCallback(tHAL_UWB_CBACK* eventCallback, |
| tHAL_UWB_DATA_CBACK dataCallback) { |
| mEventCallback = eventCallback; |
| mDataCallback = dataCallback; |
| }; |
| virtual ~UwbClientCallback() = default; |
| |
| ::ndk::ScopedAStatus onHalEvent( |
| aidl::android::hardware::uwb::UwbEvent event, |
| aidl::android::hardware::uwb::UwbStatus event_status) override { |
| mEventCallback((uint8_t)event, (uint16_t)event_status); |
| return ::ndk::ScopedAStatus::ok(); |
| }; |
| |
| ::ndk::ScopedAStatus onUciMessage(const std::vector<uint8_t>& data) override { |
| std::vector<uint8_t> copy = data; |
| mDataCallback(copy.size(), ©[0]); |
| return ::ndk::ScopedAStatus::ok(); |
| }; |
| |
| private: |
| tHAL_UWB_CBACK* mEventCallback; |
| tHAL_UWB_DATA_CBACK* mDataCallback; |
| }; |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::UwbAdaptation() |
| ** |
| ** Description: class constructor |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| UwbAdaptation::UwbAdaptation() { |
| memset(&mHalEntryFuncs, 0, sizeof(mHalEntryFuncs)); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::~UwbAdaptation() |
| ** |
| ** Description: class destructor |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| UwbAdaptation::~UwbAdaptation() { mpInstance = NULL; } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::GetInstance() |
| ** |
| ** Description: access class singleton |
| ** |
| ** Returns: pointer to the singleton object |
| ** |
| *******************************************************************************/ |
| UwbAdaptation& UwbAdaptation::GetInstance() { |
| AutoThreadMutex a(sLock); |
| |
| if (!mpInstance) mpInstance = new UwbAdaptation; |
| CHECK(mpInstance); |
| return *mpInstance; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::Initialize() |
| ** |
| ** Description: class initializer |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| void UwbAdaptation::Initialize() { |
| const char* func = "UwbAdaptation::Initialize"; |
| UNUSED(func); |
| UCI_TRACE_I("%s: enter", func); |
| initializeGlobalDebugEnabledFlag(); |
| phUwb_GKI_init(); |
| phUwb_GKI_enable(); |
| phUwb_GKI_create_task((TASKPTR)UWBA_TASK, BTU_TASK, (int8_t*)"UWBA_TASK", 0, |
| 0, (pthread_cond_t*)NULL, NULL); |
| { |
| AutoThreadMutex guard(mCondVar); |
| phUwb_GKI_create_task((TASKPTR)Thread, MMI_TASK, (int8_t*)"UWBA_THREAD", 0, |
| 0, (pthread_cond_t*)NULL, NULL); |
| mCondVar.wait(); |
| } |
| |
| mHalCallback = NULL; |
| memset(&mHalEntryFuncs, 0, sizeof(mHalEntryFuncs)); |
| InitializeHalDeviceContext(); |
| UCI_TRACE_I("%s: exit", func); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::Finalize(bool exitStatus) |
| ** |
| ** Description: class finalizer |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| void UwbAdaptation::Finalize(bool graceExit) { |
| const char* func = "UwbAdaptation::Finalize"; |
| UNUSED(func); |
| AutoThreadMutex a(sLock); |
| |
| UCI_TRACE_I("%s: enter, graceful: %d", func, graceExit); |
| phUwb_GKI_shutdown(); |
| |
| memset(&mHalEntryFuncs, 0, sizeof(mHalEntryFuncs)); |
| if (graceExit) { |
| UwbConfig::clear(); |
| } |
| |
| UCI_TRACE_I("%s: exit", func); |
| delete this; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::signal() |
| ** |
| ** Description: signal the CondVar to release the thread that is waiting |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| void UwbAdaptation::signal() { mCondVar.signal(); } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::UWBA_TASK() |
| ** |
| ** Description: UWBA_TASK runs the GKI main task |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| uint32_t UwbAdaptation::UWBA_TASK(__attribute__((unused)) uint32_t arg) { |
| const char* func = "UwbAdaptation::UWBA_TASK"; |
| UNUSED(func); |
| UCI_TRACE_I("%s: enter", func); |
| phUwb_GKI_run(0); |
| UCI_TRACE_I("%s: exit", func); |
| return 0; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::Thread() |
| ** |
| ** Description: Creates work threads |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| uint32_t UwbAdaptation::Thread(__attribute__((unused)) uint32_t arg) { |
| const char* func = "UwbAdaptation::Thread"; |
| UNUSED(func); |
| UCI_TRACE_I("%s: enter", func); |
| |
| { |
| ThreadCondVar CondVar; |
| AutoThreadMutex guard(CondVar); |
| phUwb_GKI_create_task((TASKPTR)uwb_task, UWB_TASK, (int8_t*)"UWB_TASK", 0, |
| 0, (pthread_cond_t*)CondVar, |
| (pthread_mutex_t*)CondVar); |
| CondVar.wait(); |
| } |
| |
| UwbAdaptation::GetInstance().signal(); |
| |
| phUwb_GKI_exit_task(phUwb_GKI_get_taskid()); |
| UCI_TRACE_I("%s: exit", func); |
| return 0; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::GetHalEntryFuncs() |
| ** |
| ** Description: Get the set of HAL entry points. |
| ** |
| ** Returns: Functions pointers for HAL entry points. |
| ** |
| *******************************************************************************/ |
| tHAL_UWB_ENTRY* UwbAdaptation::GetHalEntryFuncs() { return &mHalEntryFuncs; } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::InitializeHalDeviceContext |
| ** |
| ** Description: Ask the generic Android HAL to find the Broadcom-specific HAL. |
| ** |
| ** Returns: None. |
| ** |
| *******************************************************************************/ |
| void UwbAdaptation::InitializeHalDeviceContext() { |
| const char* func = "UwbAdaptation::InitializeHalDeviceContext"; |
| UNUSED(func); |
| UCI_TRACE_I("%s: enter", func); |
| |
| mHalEntryFuncs.open = HalOpen; |
| mHalEntryFuncs.close = HalClose; |
| mHalEntryFuncs.write = HalWrite; |
| mHalEntryFuncs.CoreInitialization = CoreInitialization; |
| mHalEntryFuncs.SessionInitialization = SessionInitialization; |
| mHal = getHalService(); |
| if (mHal == nullptr) { |
| UCI_TRACE_I("%s: Failed to retrieve the UWB HAL!", func); |
| } else { |
| UCI_TRACE_I("%s: IUwb::getService() returned %p (%s)", func, mHal.get(), |
| (mHal->isRemote() ? "remote" : "local")); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::HalOpen |
| ** |
| ** Description: Turn on controller, download firmware. |
| ** |
| ** Returns: None. |
| ** |
| *******************************************************************************/ |
| void UwbAdaptation::HalOpen(tHAL_UWB_CBACK* p_hal_cback, |
| tHAL_UWB_DATA_CBACK* p_data_cback) { |
| const char* func = "UwbAdaptation::HalOpen"; |
| UNUSED(func); |
| UCI_TRACE_I("%s", func); |
| ndk::ScopedAStatus status; |
| std::shared_ptr<IUwbClientCallback> mCallback; |
| mCallback = |
| ndk::SharedRefBase::make<UwbClientCallback>(p_hal_cback, p_data_cback); |
| |
| if (mHal != nullptr) { |
| status = mHal->open(mCallback); |
| } else { |
| UCI_TRACE_E("%s mHal is NULL", func); |
| } |
| } |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::HalClose |
| ** |
| ** Description: Turn off controller. |
| ** |
| ** Returns: None. |
| ** |
| *******************************************************************************/ |
| void UwbAdaptation::HalClose() { |
| const char* func = "UwbAdaptation::HalClose"; |
| UNUSED(func); |
| ndk::ScopedAStatus status; |
| UCI_TRACE_I("%s HalClose Enter", func); |
| if (mHal != nullptr) status = mHal->close(); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::HalWrite |
| ** |
| ** Description: Write UCI message to the controller. |
| ** |
| ** Returns: None. |
| ** |
| *******************************************************************************/ |
| void UwbAdaptation::HalWrite(__attribute__((unused)) uint16_t data_len, |
| __attribute__((unused)) uint8_t* p_data) { |
| const char* func = "UwbAdaptation::HalWrite"; |
| UNUSED(func); |
| UCI_TRACE_I("%s: Enter", func); |
| std::vector<uint8_t> data; |
| if (p_data == NULL) { |
| UCI_TRACE_E("p_data is null"); |
| return; |
| } |
| int ret; |
| copy(&p_data[0], &p_data[data_len], back_inserter(data)); |
| if (mHal != nullptr) { |
| mHal->sendUciMessage(data, &ret); |
| } else { |
| UCI_TRACE_E("mHal is NULL"); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::CoreInitialization |
| ** |
| ** Description: Performs UWB CoreInitialization. |
| ** |
| ** Returns: UwbStatus::OK on success and UwbStatus::FAILED on error. |
| ** |
| *******************************************************************************/ |
| tUWB_STATUS UwbAdaptation::CoreInitialization() { |
| const char* func = "UwbAdaptation::CoreInitialization"; |
| UNUSED(func); |
| UCI_TRACE_I("%s: enter", func); |
| if (mHal != nullptr) { |
| if (!mHal->coreInit().isOk()) return UWB_STATUS_FAILED; |
| } else { |
| UCI_TRACE_E("mHal is NULL"); |
| return UWB_STATUS_FAILED; |
| } |
| return UWB_STATUS_OK; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: UwbAdaptation::SessionInitialization |
| ** |
| ** Description: Performs UWB SessionInitialization. |
| ** |
| ** Returns: UwbStatus::OK on success and UwbStatus::FAILED on error. |
| ** |
| *******************************************************************************/ |
| tUWB_STATUS UwbAdaptation::SessionInitialization(int sessionId) { |
| const char* func = "UwbAdaptation::SessionInitialization"; |
| UNUSED(func); |
| UCI_TRACE_I("%s: enter", func); |
| if (mHal != nullptr) { |
| if (!mHal->sessionInit(sessionId).isOk()) return UWB_STATUS_FAILED; |
| } else { |
| UCI_TRACE_E("mHal is NULL"); |
| return UWB_STATUS_FAILED; |
| } |
| return UWB_STATUS_OK; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: ThreadMutex::ThreadMutex() |
| ** |
| ** Description: class constructor |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| ThreadMutex::ThreadMutex() { |
| pthread_mutexattr_t mutexAttr; |
| |
| pthread_mutexattr_init(&mutexAttr); |
| pthread_mutex_init(&mMutex, &mutexAttr); |
| pthread_mutexattr_destroy(&mutexAttr); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: ThreadMutex::~ThreadMutex() |
| ** |
| ** Description: class destructor |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| ThreadMutex::~ThreadMutex() { pthread_mutex_destroy(&mMutex); } |
| |
| /******************************************************************************* |
| ** |
| ** Function: ThreadMutex::lock() |
| ** |
| ** Description: lock the mutex |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| void ThreadMutex::lock() { pthread_mutex_lock(&mMutex); } |
| |
| /******************************************************************************* |
| ** |
| ** Function: ThreadMutex::unblock() |
| ** |
| ** Description: unlock the mutex |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| void ThreadMutex::unlock() { pthread_mutex_unlock(&mMutex); } |
| |
| /******************************************************************************* |
| ** |
| ** Function: ThreadCondVar::ThreadCondVar() |
| ** |
| ** Description: class constructor |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| ThreadCondVar::ThreadCondVar() { |
| pthread_condattr_t CondAttr; |
| |
| pthread_condattr_init(&CondAttr); |
| pthread_cond_init(&mCondVar, &CondAttr); |
| |
| pthread_condattr_destroy(&CondAttr); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: ThreadCondVar::~ThreadCondVar() |
| ** |
| ** Description: class destructor |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| ThreadCondVar::~ThreadCondVar() { pthread_cond_destroy(&mCondVar); } |
| |
| /******************************************************************************* |
| ** |
| ** Function: ThreadCondVar::wait() |
| ** |
| ** Description: wait on the mCondVar |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| void ThreadCondVar::wait() { |
| pthread_cond_wait(&mCondVar, *this); |
| pthread_mutex_unlock(*this); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: ThreadCondVar::signal() |
| ** |
| ** Description: signal the mCondVar |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| void ThreadCondVar::signal() { |
| AutoThreadMutex a(*this); |
| pthread_cond_signal(&mCondVar); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: AutoThreadMutex::AutoThreadMutex() |
| ** |
| ** Description: class constructor, automatically lock the mutex |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| AutoThreadMutex::AutoThreadMutex(ThreadMutex& m) : mm(m) { mm.lock(); } |
| |
| /******************************************************************************* |
| ** |
| ** Function: AutoThreadMutex::~AutoThreadMutex() |
| ** |
| ** Description: class destructor, automatically unlock the mutex |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| AutoThreadMutex::~AutoThreadMutex() { mm.unlock(); } |