/* * * Copyright 2025 NXP. * * NXP Confidential. This software is owned or controlled by NXP and may only be * used strictly in accordance with the applicable license terms. By expressly * accepting such terms or by downloading,installing, activating and/or * otherwise using the software, you are agreeing that you have read,and that * you agree to comply with and are bound by, such license terms. If you do not * agree to be bound by the applicable license terms, then you may not retain, * install, activate or otherwise use the software. * */ #include "phNxpUciHal_ext.h" #include "phUwbTypes.h" #include #include #include /******************* Global variables *****************************************/ phNxpUciHalLog_Control_t nxpucihallog_ctrl; extern phNxpUciHal_Control_t nxpucihal_ctrl; extern uci_debug_log_file_t gLogFile; /****************************************************************************** * Function phNxpUciLog_initialize * * Description This function is called during the initialization of the UWB * * Returns void * ******************************************************************************/ void phNxpUciLog_initialize() { char UCI_Logger_log_path[100] = {0}; if (!gLogFile.is_log_file_required) { return; } gLogFile.debuglogFile = NULL; sprintf(UCI_Logger_log_path, "%suci_debug_log.txt", debug_log_path); if (NULL == (gLogFile.debuglogFile = fopen(UCI_Logger_log_path, "rb+"))) { NXPLOG_UCIHAL_D("unable to open log file"); if (NULL == (gLogFile.debuglogFile = fopen(UCI_Logger_log_path, "wb"))) { NXPLOG_UCIHAL_D("unable to create log file"); } else { long offset = 0; NXPLOG_UCIHAL_D("Created debug log file set 0 as offset"); fwrite(&offset, sizeof(offset), 1, gLogFile.debuglogFile); fwrite("\n", sizeof(char), 1, gLogFile.debuglogFile); } } else { long offset = 0; NXPLOG_UCIHAL_D("debug log file exist set offset"); if (1 != fread(&offset, sizeof(long), 1, gLogFile.debuglogFile)) { NXPLOG_UCIHAL_D("phNxpUciPropHal_initialize: fread() failed at %d", __LINE__); return; } if (fseek(gLogFile.debuglogFile, offset, SEEK_SET)) { NXPLOG_UCIHAL_E("phNxpUciHalProp_print_log: fseek() failed at %d", __LINE__); return; } } if (chmod(UCI_Logger_log_path, 0744) != 0) { NXPLOG_UCIHAL_E("Can't change chmod log"); } } /****************************************************************************** * Function phNxpUciHalProp_fw_crash * * Description FW crash dump log function * * Returns None * ******************************************************************************/ static void phNxpUciHalProp_fw_crash() { NXPLOG_UCIHAL_D("[%s]", __func__); tHAL_UWB_STATUS status; // Debug get error log command: GID = UCI_GID_PROPRIETARY // OID = EXT_UCI_MSG_DBG_GET_ERROR_LOG std::vector payload = {0x2E, 0x02, 0x00, 0x00}; phNxpUciHal_rx_handler_add(UCI_MT_RSP, UCI_GID_PROPRIETARY, EXT_UCI_MSG_DBG_GET_ERROR_LOG, true, phNxpUciHal_dump_log); status = phNxpUciHal_send_ext_cmd(payload.size(), payload.data()); if (status != HAL_UWB_STATUS_OK) { NXPLOG_UCIHAL_E("Failed to send firmware crash command"); return; } /* Send FW crash NTF to upper layer for triggering MW recovery */ phNxpUciHal_send_dev_error_status_ntf(); NXPLOG_UCIHAL_D("[%s] Firmware crash handling completed", __func__); } /****************************************************************************** * Function phNxpUciHalProp_trigger_fw_crash_log_dump * * Description dump FW crash log when fw is crashed * * ******************************************************************************/ void phNxpUciHalProp_trigger_fw_crash_log_dump() { nxpucihallog_ctrl.log_thread_handler = std::thread(&phNxpUciHalProp_fw_crash); nxpucihallog_ctrl.log_thread_handler.detach(); } /****************************************************************************** * Function phNxpUciHalProp_dump_log * * Description This function is responsible for collecting and processing * debug logs. It is triggered whenever debug log data needs * to be retrieved and analyzed. * * Returns void. * ******************************************************************************/ bool phNxpUciHal_dump_log(size_t data_len, const uint8_t *p_rx_data) { int cmd_len, len; bool isSkipPacket = false; const uint8_t mt = ((p_rx_data[0]) & UCI_MT_MASK) >> UCI_MT_SHIFT; const uint8_t gid = p_rx_data[0] & UCI_GID_MASK; const uint8_t oid = p_rx_data[1] & UCI_OID_MASK; const uint8_t pbf = (p_rx_data[0] & UCI_PBF_MASK) >> UCI_PBF_SHIFT; uint8_t isExtendedLength = (p_rx_data[EXTND_LEN_INDICATOR_OFFSET] & EXTND_LEN_INDICATOR_OFFSET_MASK); cmd_len = p_rx_data[NORMAL_MODE_LENGTH_OFFSET]; if (isExtendedLength) { cmd_len = ((cmd_len << EXTENDED_MODE_LEN_SHIFT) | p_rx_data[EXTENDED_MODE_LEN_OFFSET]); } if ((gid == UCI_GID_PROPRIETARY) && (oid == EXT_UCI_MSG_DBG_GET_ERROR_LOG)) { if (nxpucihal_ctrl.hal_ext_enabled == 1) { char FW_crash_log_path[100] = {0}; sprintf(FW_crash_log_path, "%suwb_FW_crash.log", debug_log_path); if (NULL == (nxpucihallog_ctrl.FwCrashLogFile = fopen(FW_crash_log_path, "wb"))) { NXPLOG_UCIHAL_E("unable to open log file %s", FW_crash_log_path); nxpucihal_ctrl.cmdrsp.WakeupError(UWBSTATUS_FAILED); } else { len = fwrite(&p_rx_data[UCI_NTF_PAYLOAD_OFFSET], 1, cmd_len, nxpucihallog_ctrl.FwCrashLogFile); fflush(nxpucihallog_ctrl.FwCrashLogFile); NXPLOG_UCIHAL_D("FW crash dump: %d bytes written", len); fclose(nxpucihallog_ctrl.FwCrashLogFile); } if (!pbf) { nxpucihal_ctrl.cmdrsp.Wakeup(gid, oid); } } isSkipPacket = true; } return isSkipPacket; } void phNxpUciHalProp_print_log(uint8_t what, const uint8_t *p_data, uint16_t len) { char print_buffer[len * 3 + 1]; char dd_mm_buffer[8]; char UCI_Logger_log_path[100] = {0}; const uint8_t mt = ((p_data[0]) & UCI_MT_MASK) >> UCI_MT_SHIFT; const uint8_t gid = p_data[0] & UCI_GID_MASK; const uint8_t oid = p_data[1] & UCI_OID_MASK; bool is_range_ntf = false; uint8_t status_index = 29; if (!gLogFile.is_log_file_required) { return; } if (gLogFile.debuglogFile == NULL) { NXPLOG_UCIHAL_E("debuglogFile file pointer is null..."); return; } char yy_time[20]; time_t current_time = time(0); tm *dd_mm_tm = localtime(¤t_time); strftime(yy_time, sizeof(yy_time), "%x %T", dd_mm_tm); if (gLogFile.fileSize < 100000) { if (!nxpucihal_ctrl.uwb_device_initialized) { // Check file size if (ftell(gLogFile.debuglogFile) + 5 + strlen(yy_time) + strlen(NXPLOG_ITEM_UCIR) + 4 > gLogFile.fileSize) { if (fseek(gLogFile.debuglogFile, 9L, SEEK_SET)) { NXPLOG_UCIHAL_E("phNxpUciHalProp_print_log: fseek() failed at %d", __LINE__); return; } if (ftell(gLogFile.debuglogFile) > gLogFile.fileSize) { return; } } if (mt == UCI_MT_RSP && p_data[4] != UCI_STATUS_OK) { fprintf(gLogFile.debuglogFile, "\n%s %s:", yy_time, NXPLOG_ITEM_UCIR); len = fwrite(p_data, 1, len, gLogFile.debuglogFile); fwrite("\n", 1, 1, gLogFile.debuglogFile); gLogFile.init_sequence_started = false; } if (!gLogFile.init_sequence_started) { fprintf(gLogFile.debuglogFile, "\n%s INIT", yy_time); } gLogFile.init_sequence_started = true; return; } gLogFile.init_sequence_started = false; if (((gid != UCI_GID_SESSION_MANAGE) || (oid != UCI_MSG_SESSION_SET_APP_CONFIG)) && ((gid != UCI_GID_PROPRIETARY_0X0F) || (oid != SET_VENDOR_SET_CALIBRATION))) { switch (mt) { case UCI_MT_CMD: len = UCI_MSG_HDR_SIZE; break; case UCI_MT_RSP: len = UCI_RESPONSE_PAYLOAD_OFFSET; break; case UCI_MT_NTF: // Handle range data ntf if ((gid == UCI_GID_SESSION_CONTROL) && (oid == UCI_OID_RANGE_DATA_NTF)) { // Sequence number - 4 // first 4 bytes // session handle - 4 // status if (p_data[4 + 15] == 0x00) { status_index += 2; } else { status_index += 8; } is_range_ntf = true; } break; default: break; } } } if ((gid == UCI_GID_PROPRIETARY && oid == EXT_UCI_MSG_DBG_DATA_LOGGER_NTF) || ((gid == UCI_GID_PROPRIETARY_0X0F) && (oid == EXT_UCI_MSG_DBG_PSDU_LOG_NTF)) || ((gid == UCI_GID_PROPRIETARY_0X0F) && (oid == EXT_UCI_MSG_DBG_CIR_LOG_NTF))) { return; } uint32_t file_size = ftell(gLogFile.debuglogFile); if ((file_size + (strlen(yy_time) + 1 + strlen(NXPLOG_ITEM_UCIX) + 1 + len) >= gLogFile.fileSize)) { int val = fseek(gLogFile.debuglogFile, 9L, SEEK_SET); if (ftell(gLogFile.debuglogFile) > gLogFile.fileSize) { return; } } switch (what) { case 0: { fprintf(gLogFile.debuglogFile, "\n%s %s:", yy_time, NXPLOG_ITEM_UCIX); } break; case 1: { fprintf(gLogFile.debuglogFile, "\n%s %s:", yy_time, NXPLOG_ITEM_UCIR); } break; default: return; break; } memset(print_buffer, 0, sizeof(print_buffer)); int i = 0, j = 0; if (is_range_ntf) { fwrite(&p_data[j], 1, 9, gLogFile.debuglogFile); fwrite(&p_data[status_index], 1, 1, gLogFile.debuglogFile); } else { len = fwrite(&p_data[j], 1, len, gLogFile.debuglogFile); fflush(gLogFile.debuglogFile); } } /****************************************************************************** * Function phNxpUciLog_deinitialize * * Description This function close files and frees up memory used by * proprietary hal. * * Returns void * ******************************************************************************/ void phNxpUciLog_deinitialize() { /* FW debug log dump file closed */ if (nxpucihallog_ctrl.FwCrashLogFile != NULL) { fclose(nxpucihallog_ctrl.FwCrashLogFile); } if (gLogFile.debuglogFile != NULL) { long offset = ftell(gLogFile.debuglogFile); fseek(gLogFile.debuglogFile, 0L, SEEK_SET); fwrite(&offset, sizeof(long), 1, gLogFile.debuglogFile); fwrite("\n", sizeof(char), 1, gLogFile.debuglogFile); fclose(gLogFile.debuglogFile); gLogFile.debuglogFile = NULL; } }