/* * Copyright 2012-2020, 2023 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 #include #include #include #include #include using namespace std; map> input_map; map> conf_map; /****************** Semaphore and mutex helper functions **********************/ /* Semaphore and mutex monitor */ struct phNxpUciHal_Monitor { public: static std::unique_ptr Create() { //auto monitor = std::unique_ptr(new phNxpUciHal_Monitor()); auto monitor = std::make_unique(); if (pthread_mutex_init(&monitor->reentrance_mutex_, NULL) == -1) { return nullptr; } if (pthread_mutex_init(&monitor->concurrency_mutex_, NULL) == -1) { pthread_mutex_destroy(&monitor->reentrance_mutex_); return nullptr; } return monitor; } virtual ~phNxpUciHal_Monitor() { pthread_mutex_destroy(&concurrency_mutex_); ReentranceUnlock(); pthread_mutex_destroy(&reentrance_mutex_); for (auto p : sems_) { NXPLOG_UCIHAL_E("Unreleased semaphore %p", p); p->status = UWBSTATUS_FAILED; sem_post(&p->sem); } sems_.clear(); } void AddSem(phNxpUciHal_Sem_t* pCallbackData) { std::lock_guard lock(lock_); auto it = sems_.find(pCallbackData); if (it == sems_.end()) { sems_.insert(pCallbackData); } else { NXPLOG_UCIHAL_E("phNxpUciHal_init_cb_data: duplicated semaphore %p", pCallbackData); } } void RemoveSem(phNxpUciHal_Sem_t* pCallbackData) { std::lock_guard lock(lock_); auto it = sems_.find(pCallbackData); if (it == sems_.end()) { NXPLOG_UCIHAL_E("phNxpUciHal_cleanup_cb_data: orphan semaphore %p", pCallbackData); } else { sems_.erase(it); } } void Reentrancelock() { pthread_mutex_lock(&reentrance_mutex_); } void ReentranceUnlock() { pthread_mutex_unlock(&reentrance_mutex_); } void Concurrencylock() { pthread_mutex_lock(&concurrency_mutex_); } void ConcurrencyUnlock() { pthread_mutex_unlock(&concurrency_mutex_); } private: std::unordered_set sems_; std::mutex lock_; // Mutex protecting native library against reentrance pthread_mutex_t reentrance_mutex_; // Mutex protecting native library against concurrency pthread_mutex_t concurrency_mutex_; }; static std::unique_ptr nxpucihal_monitor; /******************************************************************************* ** ** Function phNxpUciHal_init_monitor ** ** Description Initialize the semaphore monitor ** ** Returns Pointer to monitor, otherwise NULL if failed ** *******************************************************************************/ bool phNxpUciHal_init_monitor(void) { NXPLOG_UCIHAL_D("Entering phNxpUciHal_init_monitor"); nxpucihal_monitor = phNxpUciHal_Monitor::Create(); if (nxpucihal_monitor == nullptr) { NXPLOG_UCIHAL_E("nxphal_monitor creation failed"); return false; } return true; } /******************************************************************************* ** ** Function phNxpUciHal_cleanup_monitor ** ** Description Clean up semaphore monitor ** ** Returns None ** *******************************************************************************/ void phNxpUciHal_cleanup_monitor(void) { nxpucihal_monitor = nullptr; } /* Initialize the callback data */ tHAL_UWB_STATUS phNxpUciHal_init_cb_data(phNxpUciHal_Sem_t* pCallbackData, void* pContext) { /* Create semaphore */ if (sem_init(&pCallbackData->sem, 0, 0) == -1) { NXPLOG_UCIHAL_E("Semaphore creation failed"); return UWBSTATUS_FAILED; } /* Set default status value */ pCallbackData->status = UWBSTATUS_FAILED; /* Copy the context */ pCallbackData->pContext = pContext; /* Add to active semaphore list */ if (nxpucihal_monitor != nullptr) { nxpucihal_monitor->AddSem(pCallbackData); } return UWBSTATUS_SUCCESS; } /******************************************************************************* ** ** Function phNxpUciHal_cleanup_cb_data ** ** Description Clean up callback data ** ** Returns None ** *******************************************************************************/ void phNxpUciHal_cleanup_cb_data(phNxpUciHal_Sem_t* pCallbackData) { /* Destroy semaphore */ if (sem_destroy(&pCallbackData->sem)) { NXPLOG_UCIHAL_E( "phNxpUciHal_cleanup_cb_data: Failed to destroy semaphore"); } if (nxpucihal_monitor != nullptr) { nxpucihal_monitor->RemoveSem(pCallbackData); } } void REENTRANCE_LOCK() { if (nxpucihal_monitor != nullptr) { nxpucihal_monitor->Reentrancelock(); } } void REENTRANCE_UNLOCK() { if (nxpucihal_monitor != nullptr) { nxpucihal_monitor->ReentranceUnlock(); } } void CONCURRENCY_LOCK() { if (nxpucihal_monitor != nullptr) { nxpucihal_monitor->Concurrencylock(); } } void CONCURRENCY_UNLOCK() { if (nxpucihal_monitor != nullptr) { nxpucihal_monitor->ConcurrencyUnlock(); } } int phNxpUciHal_sem_timed_wait_msec(phNxpUciHal_Sem_t* pCallbackData, long msec) { int ret; struct timespec absTimeout; if (clock_gettime(CLOCK_MONOTONIC, &absTimeout) == -1) { NXPLOG_UCIHAL_E("clock_gettime failed"); return -1; } if (msec > 1000L) { absTimeout.tv_sec += msec / 1000L; msec = msec % 1000L; } absTimeout.tv_nsec += msec * 1000000L; if (absTimeout.tv_nsec > 1000000000L) { absTimeout.tv_nsec -= 1000000000L; absTimeout.tv_sec += 1; } while ((ret = sem_timedwait_monotonic_np(&pCallbackData->sem, &absTimeout)) == -1 && errno == EINTR) { continue; } if (ret == -1 && errno == ETIMEDOUT) { pCallbackData->status = UWBSTATUS_RESPONSE_TIMEOUT; NXPLOG_UCIHAL_E("wait semaphore timed out"); return -1; } return 0; } /* END Semaphore and mutex helper functions */ /**************************** Other functions *********************************/ /******************************************************************************* ** ** Function phNxpUciHal_print_packet ** ** Description Print packet ** ** Returns None ** *******************************************************************************/ void phNxpUciHal_print_packet(enum phNxpUciHal_Pkt_Type what, const uint8_t* p_data, uint16_t len) { uint32_t i; char print_buffer[len * 3 + 1]; if ((gLog_level.ucix_log_level >= NXPLOG_LOG_DEBUG_LOGLEVEL)) { /* OK to print */ } else { /* Nothing to print... * Why prepare buffer without printing? */ return; } memset(print_buffer, 0, sizeof(print_buffer)); for (i = 0; i < len; i++) { snprintf(&print_buffer[i * 2], 3, "%02X", p_data[i]); } switch(what) { case NXP_TML_UCI_CMD_AP_2_UWBS: { NXPLOG_UCIX_D("len = %3d > %s", len, print_buffer); } break; case NXP_TML_UCI_RSP_NTF_UWBS_2_AP: { NXPLOG_UCIR_D("len = %3d < %s", len, print_buffer); } break; case NXP_TML_FW_DNLD_CMD_AP_2_UWBS: { // TODO: Should be NXPLOG_FWDNLD_D NXPLOG_UCIX_D("len = %3d > (FW)%s", len, print_buffer); } break; case NXP_TML_FW_DNLD_RSP_UWBS_2_AP: { // TODO: Should be NXPLOG_FWDNLD_D NXPLOG_UCIR_D("len = %3d < (FW)%s", len, print_buffer); } break; } return; } /******************************************************************************* ** ** Function phNxpUciHal_emergency_recovery ** ** Description Emergency recovery in case of no other way out ** ** Returns None ** *******************************************************************************/ void phNxpUciHal_emergency_recovery(void) { NXPLOG_UCIHAL_E("%s: abort()", __func__); abort(); } /******************************************************************************* ** ** Function phNxpUciHal_byteArrayToDouble ** ** Description convert byte array to double ** ** Returns double ** *******************************************************************************/ double phNxpUciHal_byteArrayToDouble(const uint8_t* p_data) { double d; int size_d = sizeof(d); uint8_t ptr[size_d],ptr_1[size_d]; memcpy(&ptr, p_data, size_d); for(int i=0;i> decodeTlvBytes(const std::vector &ext_ids, const uint8_t *tlv_bytes, size_t tlv_len) { std::map> ret; size_t i = 0; while ((i + 1) < tlv_len) { uint16_t tag; uint8_t len; uint8_t byte0 = tlv_bytes[i++]; uint8_t byte1 = tlv_bytes[i++]; if (std::find(ext_ids.begin(), ext_ids.end(), byte0) != ext_ids.end()) { if (i >= tlv_len) { NXPLOG_UCIHAL_E("Failed to decode TLV bytes (offset=%zu).", i); break; } tag = (byte0 << 8) | byte1; // 2 bytes tag as big endiann len = tlv_bytes[i++]; } else { tag = byte0; len = byte1; } if ((i + len) > tlv_len) { NXPLOG_UCIHAL_E("Failed to decode TLV bytes (offset=%zu).", i); break; } ret[tag] = std::vector(&tlv_bytes[i], &tlv_bytes[i + len]); i += len; } return ret; } std::vector encodeTlvBytes(const std::map> &tlvs) { std::vector bytes; for (auto const & [tag, val] : tlvs) { // Tag if (tag > 0xff) { bytes.push_back(tag >> 8); } bytes.push_back(tag & 0xff); // Length bytes.push_back(val.size()); // Value bytes.insert(bytes.end(), val.begin(), val.end()); } return bytes; }