blob: b8f6390075b27aadc858292936a418fafbc40049 [file] [log] [blame]
/*
* Copyright 2012-2019, 2022-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 <sys/stat.h>
#include <array>
#include <string.h>
#include <map>
#include <unordered_set>
#include <vector>
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <log/log.h>
#include <phNxpLog.h>
#include <phNxpUciHal.h>
#include <phNxpUciHal_Adaptation.h>
#include <phNxpUciHal_ext.h>
#include <phTmlUwb_spi.h>
#include "hal_nxpuwb.h"
#include "phNxpConfig.h"
#include "phNxpUciHal_utils.h"
using namespace std;
using android::base::StringPrintf;
extern map<uint16_t, vector<uint16_t>> input_map;
extern map<uint16_t, vector<uint16_t>> conf_map;
/*********************** Global Variables *************************************/
/* UCI HAL Control structure */
phNxpUciHal_Control_t nxpucihal_ctrl;
/* TML Context */
extern phTmlUwb_Context_t* gpphTmlUwb_Context;
bool uwb_debug_enabled = false;
bool uwb_device_initialized = false;
bool uwb_get_platform_id = false;
uint32_t timeoutTimerId = 0;
char persistant_log_path[120];
static uint8_t Rx_data[UCI_MAX_DATA_LEN];
uint8_t channel_5_support = 1;
uint8_t channel_9_support = 1;
short conf_tx_power = 0;
bool uwb_enable = true;
/* AOA support handling */
bool isAntennaRxPairDefined = false;
int numberOfAntennaPairs = 0;
/**************** local methods used in this file only ************************/
static void phNxpUciHal_open_complete(tHAL_UWB_STATUS status);
static void phNxpUciHal_write_complete(void* pContext,
phTmlUwb_TransactInfo_t* pInfo);
static void phNxpUciHal_close_complete(tHAL_UWB_STATUS status);
static void phNxpUciHal_kill_client_thread(
phNxpUciHal_Control_t* p_nxpucihal_ctrl);
static void* phNxpUciHal_client_thread(void* arg);
extern int phNxpUciHal_fw_download();
static void phNxpUciHal_getVersionInfo();
/******************************************************************************
* Function phNxpUciHal_client_thread
*
* Description This function is a thread handler which handles all TML and
* UCI messages.
*
* Returns void
*
******************************************************************************/
static void* phNxpUciHal_client_thread(void* arg) {
phNxpUciHal_Control_t* p_nxpucihal_ctrl = (phNxpUciHal_Control_t*)arg;
phLibUwb_Message_t msg;
NXPLOG_UCIHAL_D("thread started");
p_nxpucihal_ctrl->thread_running = 1;
while (p_nxpucihal_ctrl->thread_running == 1) {
/* Fetch next message from the UWB stack message queue */
if (phDal4Uwb_msgrcv(p_nxpucihal_ctrl->gDrvCfg.nClientId, &msg, 0, 0) ==
-1) {
NXPLOG_UCIHAL_E("UWB client received bad message");
continue;
}
if (p_nxpucihal_ctrl->thread_running == 0) {
break;
}
switch (msg.eMsgType) {
case PH_LIBUWB_DEFERREDCALL_MSG: {
phLibUwb_DeferredCall_t* deferCall =
(phLibUwb_DeferredCall_t*)(msg.pMsgData);
REENTRANCE_LOCK();
deferCall->pCallback(deferCall->pParameter);
REENTRANCE_UNLOCK();
break;
}
case UCI_HAL_OPEN_CPLT_MSG: {
REENTRANCE_LOCK();
if (nxpucihal_ctrl.p_uwb_stack_cback != NULL) {
/* Send the event */
(*nxpucihal_ctrl.p_uwb_stack_cback)(HAL_UWB_OPEN_CPLT_EVT,
HAL_UWB_STATUS_OK);
}
REENTRANCE_UNLOCK();
break;
}
case UCI_HAL_CLOSE_CPLT_MSG: {
REENTRANCE_LOCK();
if (nxpucihal_ctrl.p_uwb_stack_cback != NULL) {
/* Send the event */
(*nxpucihal_ctrl.p_uwb_stack_cback)(HAL_UWB_CLOSE_CPLT_EVT,
HAL_UWB_STATUS_OK);
phNxpUciHal_kill_client_thread(&nxpucihal_ctrl);
}
REENTRANCE_UNLOCK();
break;
}
case UCI_HAL_INIT_CPLT_MSG: {
REENTRANCE_LOCK();
if (nxpucihal_ctrl.p_uwb_stack_cback != NULL) {
/* Send the event */
(*nxpucihal_ctrl.p_uwb_stack_cback)(HAL_UWB_INIT_CPLT_EVT,
HAL_UWB_STATUS_OK);
}
REENTRANCE_UNLOCK();
break;
}
case UCI_HAL_ERROR_MSG: {
REENTRANCE_LOCK();
if (nxpucihal_ctrl.p_uwb_stack_cback != NULL) {
/* Send the event */
(*nxpucihal_ctrl.p_uwb_stack_cback)(HAL_UWB_ERROR_EVT,
HAL_UWB_ERROR_EVT);
}
REENTRANCE_UNLOCK();
break;
}
}
}
NXPLOG_UCIHAL_D("NxpUciHal thread stopped");
pthread_exit(NULL);
return NULL;
}
/*************************************************************************************
* Function handlingVendorSpecificAppConfig
*
* Description This function removes the vendor specific app config from
*UCI command
*
* Returns void
*
*************************************************************************************/
void handlingVendorSpecificAppConfig(uint16_t *data_len, uint8_t *p_data) {
// removing the vendor specific app config as it's not supported by FW
static const std::unordered_set<uint16_t> tags_to_del {
UCI_PARAM_ID_TX_ADAPTIVE_PAYLOAD_POWER,
UCI_PARAM_ID_AOA_AZIMUTH_MEASUREMENTS,
UCI_PARAM_ID_AOA_ELEVATION_MEASUREMENTS,
UCI_PARAM_ID_RANGE_MEASUREMENTS
};
uint8_t mt = 0, gid = 0, oid = 0;
mt = (*(p_data)&UCI_MT_MASK) >> UCI_MT_SHIFT;
gid = p_data[0] & UCI_GID_MASK;
oid = p_data[1] & UCI_OID_MASK;
if (mt == UCI_MT_CMD) {
if ((gid == UCI_GID_SESSION_MANAGE) &&
(oid == UCI_MSG_SESSION_SET_APP_CONFIG)) {
uint16_t dataLength = *data_len, numOfbytes = 0, numOfConfigs = 0;
/* Create local copy of cmd_data for data manipulation*/
uint8_t uciCmd[UCI_MAX_DATA_LEN];
if (sizeof(uciCmd) < dataLength) {
return;
}
memcpy(uciCmd, p_data, dataLength);
uint16_t startOfByteManipulation = UCI_MSG_HDR_SIZE +
UCI_CMD_SESSION_ID_OFFSET +
UCI_CMD_NUM_CONFIG_PARAM_LENGTH;
for (uint16_t i = startOfByteManipulation, j = startOfByteManipulation;
i < dataLength;) {
uint16_t tag;
uint8_t len;
uint8_t param_len;
tag = p_data[i];
if (tag >= 0xe0 && tag <= 0xe2) {
if ((i + 3) > dataLength)
return;
tag = (tag << 8) | p_data[i + 1];
len = p_data[i + 2];
param_len = 3 + len;
} else {
if ((i + 2) > dataLength)
return;
len = p_data[i + 1];
param_len = 2 + len;
}
if ((i + param_len) > dataLength)
return;
if (tags_to_del.find(tag) == tags_to_del.end()) {
memcpy(&uciCmd[j], &p_data[i], param_len);
i += param_len;
j += param_len;
} else {
i += param_len;
NXPLOG_UCIHAL_D("Removed param payload with Tag ID:0x%x", tag);
numOfConfigs++;
numOfbytes += param_len;
}
}
// uci number of config params update
if (uciCmd[UCI_CMD_NUM_CONFIG_PARAM_BYTE] < numOfConfigs)
return;
uciCmd[UCI_CMD_NUM_CONFIG_PARAM_BYTE] -= numOfConfigs;
// uci command length update
if (dataLength < numOfbytes)
return;
dataLength -= numOfbytes;
// uci cmd app config length update
uint16_t header_len = (uciCmd[UCI_CMD_LENGTH_PARAM_BYTE1] & 0xFF) |
((uciCmd[UCI_CMD_LENGTH_PARAM_BYTE2] & 0xFF) << 8);
if (header_len < numOfbytes)
return;
header_len -= numOfbytes;
uciCmd[UCI_CMD_LENGTH_PARAM_BYTE2] = (header_len & 0xFF00) >> 8;
uciCmd[UCI_CMD_LENGTH_PARAM_BYTE1] = (header_len & 0xFF);
memcpy(p_data, uciCmd, dataLength);
*data_len = dataLength;
}
}
}
bool isCountryCodeMapCreated = false;
/******************************************************************************
* Function phNxpUciHal_parse
*
* Description This function parses all the data passing through the HAL.
*
* Returns It returns true if the incoming command to be skipped.
*
******************************************************************************/
bool phNxpUciHal_parse(uint16_t data_len, const uint8_t *p_data) {
uint8_t mt = 0, gid = 0, oid = 0;
uint16_t arrLen = 0, tag = 0, idx = 0;
bool ret = false;
map<uint16_t, vector<uint16_t>>::iterator itr;
vector<uint16_t>::iterator v_itr;
mt = (*(p_data)&UCI_MT_MASK) >> UCI_MT_SHIFT;
gid = p_data[0] & UCI_GID_MASK;
oid = p_data[1] & UCI_OID_MASK;
if (mt == UCI_MT_CMD) {
if ((gid == UCI_GID_ANDROID) && (oid == UCI_MSG_ANDROID_SET_COUNTRY_CODE)) {
if (data_len < 6) {
return true;
}
char country_code[2];
country_code[0] = (char)p_data[4];
country_code[1] = (char)p_data[5];
if ((country_code[0] == '0') && (country_code[1] == '0')) {
NXPLOG_UCIHAL_D("Country code %c%c is Invalid!", country_code[0], country_code[1]);
} else {
NxpConfig_SetCountryCode(country_code);
}
// send country code response to upper layer
nxpucihal_ctrl.rx_data_len = 5;
static uint8_t rsp_data[5];
rsp_data[0] = 0x4c;
rsp_data[1] = 0x01;
rsp_data[2] = 0x00;
rsp_data[3] = 0x01;
if (uwb_enable) {
rsp_data[4] = 0x00; // Response Success
} else {
NXPLOG_UCIHAL_D("Country code uwb disable "
"UCI_STATUS_CODE_ANDROID_REGULATION_UWB_OFF!");
rsp_data[4] = UCI_STATUS_CODE_ANDROID_REGULATION_UWB_OFF;
}
ret = true;
(*nxpucihal_ctrl.p_uwb_stack_data_cback)(nxpucihal_ctrl.rx_data_len,
rsp_data);
} else if ((gid == UCI_GID_PROPRIETARY_0x0F) &&
(oid == SET_VENDOR_SET_CALIBRATION)) {
if (p_data[UCI_MSG_HDR_SIZE + 1] ==
VENDOR_CALIB_PARAM_TX_POWER_PER_ANTENNA) {
phNxpUciHal_processCalibParamTxPowerPerAntenna(conf_tx_power, p_data,
data_len);
}
} else if ((gid == UCI_GID_SESSION_MANAGE) &&
(oid == UCI_MSG_SESSION_SET_APP_CONFIG)) {
uint8_t index =
4 /*UCI_MSG_HDR_SIZE*/ + 4 /*Session_Id*/ + 1 /*Num of configs*/;
uint8_t len = p_data[UCI_MSG_HDR_SIZE - 1];
len = len + UCI_MSG_HDR_SIZE; // length should be size of payload + size
// of header
uint8_t tagId, length, channel_number, no_of_config;
no_of_config = p_data[8];
while (index < len) {
tagId = p_data[index++];
length = p_data[index++];
if (tagId == UCI_PARAM_ID_CHANNEL_NUMBER) {
channel_number = p_data[index];
if (((channel_number == CHANNEL_NUM_5) && !channel_5_support) ||
((channel_number == CHANNEL_NUM_9) && !channel_9_support)) {
NXPLOG_UCIHAL_D("Country code blocked channel");
// send setAppConfig response with COUNTRY_CODE_BLOCKED response
nxpucihal_ctrl.rx_data_len = 8;
static uint8_t rsp_data[8];
rsp_data[0] = 0x41;
rsp_data[1] = 0x03;
rsp_data[2] = 0x00;
rsp_data[3] = 0x04; // Length
rsp_data[4] = 0x02;
rsp_data[5] = 0x01;
rsp_data[6] = 0x04;
rsp_data[7] = UCI_STATUS_COUNTRY_CODE_BLOCKED_CHANNEL;
ret = true;
(*nxpucihal_ctrl.p_uwb_stack_data_cback)(
nxpucihal_ctrl.rx_data_len, rsp_data);
break;
}
}
index += length;
}
}
} else if (mt == UCI_MT_RSP) {
if ((gid == UCI_GID_CORE) && (oid == UCI_MSG_CORE_GET_CAPS_INFO)) {
// do not modify caps if the country code is not received from upper
// layer.
if (isCountryCodeMapCreated == false) {
return false;
}
// Check UWBS Caps response status
if (p_data[4] == 0) {
idx = UCI_PKT_HDR_LEN + UCI_PKT_PAYLOAD_STATUS_LEN +
UCI_PKT_NUM_CAPS_LEN;
if (get_input_map(p_data, data_len, idx)) {
NXPLOG_UCIHAL_D("Input Map created");
} else {
NXPLOG_UCIHAL_D("Input Map creation failed");
return false;
}
} else {
return false;
}
// Compare the maps for Tags and modify input map if Values are
// different
for (itr = input_map.begin(); itr != input_map.end(); ++itr) {
tag = itr->first;
// Check for the Tag in both maps
if ((conf_map.count(tag)) == 1) {
if (tag == UWB_CHANNELS || tag == CCC_UWB_CHANNELS) {
NXPLOG_UCIHAL_D(
"Tag = 0x%02X , modify UWB_CHANNELS based on country conf ",
tag);
for (uint32_t j = 0; j < (itr->second).size(); j++) {
(input_map[tag])[j] =
((conf_map[tag])[j]) & ((input_map[tag])[j]);
}
}
} else {
// TAG not found do nothing
}
}
// convert the modified input map to p_caps_resp array
memset(nxpucihal_ctrl.p_caps_resp, 0, UCI_MAX_DATA_LEN);
// Header information from Input array is updated in initial bytes
nxpucihal_ctrl.p_caps_resp[0] = p_data[0];
nxpucihal_ctrl.p_caps_resp[1] = p_data[1];
nxpucihal_ctrl.p_caps_resp[2] = p_data[2];
nxpucihal_ctrl.p_caps_resp[4] = p_data[4];
for (itr = input_map.begin(); itr != input_map.end(); ++itr) {
tag = itr->first;
// If Tag is 0xE0 or 0xE1 or 0xE2,Tag will be of 2 bytes
if (((tag >> 8) >= 0xE0) && ((tag >> 8) <= 0xE2)) {
nxpucihal_ctrl.p_caps_resp[idx++] = (tag & 0xFF00) >> 8;
nxpucihal_ctrl.p_caps_resp[idx++] = (tag & 0x00FF);
} else {
nxpucihal_ctrl.p_caps_resp[idx++] = tag;
}
for (v_itr = itr->second.begin(); v_itr != itr->second.end();
++v_itr) {
nxpucihal_ctrl.p_caps_resp[idx++] = (*v_itr);
}
}
arrLen = idx;
// exclude the initial header data
nxpucihal_ctrl.p_caps_resp[3] = arrLen - UCI_PKT_HDR_LEN;
// update the number of parameter TLVs.
nxpucihal_ctrl.p_caps_resp[5] = input_map.size();
input_map.clear();
// send GET CAPS INFO response to the Upper Layer
(*nxpucihal_ctrl.p_uwb_stack_data_cback)(arrLen,
nxpucihal_ctrl.p_caps_resp);
// skip the incoming packet as we have send the modified response
// already
nxpucihal_ctrl.isSkipPacket = 1;
ret = false;
}
} else {
ret = false;
}
return ret;
}
/******************************************************************************
* Function phNxpUciHal_kill_client_thread
*
* Description This function safely kill the client thread and clean all
* resources.
*
* Returns void.
*
******************************************************************************/
static void phNxpUciHal_kill_client_thread(
phNxpUciHal_Control_t* p_nxpucihal_ctrl) {
NXPLOG_UCIHAL_D("Terminating phNxpUciHal client thread...");
p_nxpucihal_ctrl->p_uwb_stack_cback = NULL;
p_nxpucihal_ctrl->p_uwb_stack_data_cback = NULL;
p_nxpucihal_ctrl->thread_running = 0;
return;
}
/******************************************************************************
* Function phNxpUciHal_open
*
* Description This function is called by libuwb-uci during the
* initialization of the UWBC. It opens the physical connection
* with UWBC (SRXXX) and creates required client thread for
* operation.
* After open is complete, status is informed to libuwb-uci
* through callback function.
*
* Returns This function return UWBSTATUS_SUCCES (0) in case of success
* In case of failure returns other failure value.
*
******************************************************************************/
tHAL_UWB_STATUS phNxpUciHal_open(uwb_stack_callback_t* p_cback,
uwb_stack_data_callback_t* p_data_cback) {
phOsalUwb_Config_t tOsalConfig;
phTmlUwb_Config_t tTmlConfig;
char* uwb_dev_node = NULL;
const uint16_t max_len = 260;
tHAL_UWB_STATUS wConfigStatus = UWBSTATUS_SUCCESS;
pthread_attr_t attr;
if (nxpucihal_ctrl.halStatus == HAL_STATUS_OPEN) {
NXPLOG_UCIHAL_E("phNxpUciHal_open already open");
return UWBSTATUS_SUCCESS;
}
NxpConfig_Init();
/* initialize trace level */
phNxpLog_InitializeLogLevel();
/*Create the timer for extns write response*/
timeoutTimerId = phOsalUwb_Timer_Create();
if (phNxpUciHal_init_monitor() == NULL) {
NXPLOG_UCIHAL_E("Init monitor failed");
return UWBSTATUS_FAILED;
}
CONCURRENCY_LOCK();
memset(&nxpucihal_ctrl, 0x00, sizeof(nxpucihal_ctrl));
memset(&tOsalConfig, 0x00, sizeof(tOsalConfig));
memset(&tTmlConfig, 0x00, sizeof(tTmlConfig));
uwb_dev_node = (char*)nxp_malloc(max_len * sizeof(char));
if (uwb_dev_node == NULL) {
NXPLOG_UCIHAL_E("malloc of uwb_dev_node failed ");
goto clean_and_return;
} else {
NXPLOG_UCIHAL_E("Assigning the default helios Node: dev/srxxx");
strcpy(uwb_dev_node, "/dev/srxxx");
}
/* By default HAL status is HAL_STATUS_OPEN */
nxpucihal_ctrl.halStatus = HAL_STATUS_OPEN;
nxpucihal_ctrl.p_uwb_stack_cback = p_cback;
nxpucihal_ctrl.p_uwb_stack_data_cback = p_data_cback;
nxpucihal_ctrl.fw_dwnld_mode = false;
/* Configure hardware link */
nxpucihal_ctrl.gDrvCfg.nClientId = phDal4Uwb_msgget(0, 0600);
nxpucihal_ctrl.gDrvCfg.nLinkType = ENUM_LINK_TYPE_SPI;
tTmlConfig.pDevName = (int8_t*)uwb_dev_node;
tOsalConfig.dwCallbackThreadId = (uintptr_t)nxpucihal_ctrl.gDrvCfg.nClientId;
tOsalConfig.pLogFile = NULL;
tTmlConfig.dwGetMsgThreadId = (uintptr_t)nxpucihal_ctrl.gDrvCfg.nClientId;
/* Initialize TML layer */
wConfigStatus = phTmlUwb_Init(&tTmlConfig);
if (wConfigStatus != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("phTmlUwb_Init Failed");
goto clean_and_return;
} else {
if (uwb_dev_node != NULL) {
free(uwb_dev_node);
uwb_dev_node = NULL;
}
}
/* Create the client thread */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (pthread_create(&nxpucihal_ctrl.client_thread, &attr,
phNxpUciHal_client_thread, &nxpucihal_ctrl) != 0) {
NXPLOG_UCIHAL_E("pthread_create failed");
wConfigStatus = phTmlUwb_Shutdown();
goto clean_and_return;
}
CONCURRENCY_UNLOCK();
#if 0
/* call read pending */
status = phTmlUwb_Read(
nxpucihal_ctrl.p_cmd_data, UCI_MAX_DATA_LEN,
(pphTmlUwb_TransactCompletionCb_t)&phNxpUciHal_read_complete, NULL);
if (status != UWBSTATUS_PENDING) {
NXPLOG_UCIHAL_E("TML Read status error status = %x", status);
wConfigStatus = phTmlUwb_Shutdown();
wConfigStatus = UWBSTATUS_FAILED;
goto clean_and_return;
}
#endif
pthread_attr_destroy(&attr);
/* Call open complete */
phNxpUciHal_open_complete(wConfigStatus);
return wConfigStatus;
clean_and_return:
CONCURRENCY_UNLOCK();
if (uwb_dev_node != NULL) {
free(uwb_dev_node);
uwb_dev_node = NULL;
}
/* Report error status */
(*nxpucihal_ctrl.p_uwb_stack_cback)(HAL_UWB_OPEN_CPLT_EVT, HAL_UWB_ERROR_EVT);
nxpucihal_ctrl.p_uwb_stack_cback = NULL;
nxpucihal_ctrl.p_uwb_stack_data_cback = NULL;
phNxpUciHal_cleanup_monitor();
nxpucihal_ctrl.halStatus = HAL_STATUS_CLOSE;
pthread_attr_destroy(&attr);
return wConfigStatus;
}
/******************************************************************************
* Function phNxpUciHal_open_complete
*
* Description This function inform the status of phNxpUciHal_open
* function to libuwb-uci.
*
* Returns void.
*
******************************************************************************/
static void phNxpUciHal_open_complete(tHAL_UWB_STATUS status) {
static phLibUwb_Message_t msg;
if (status == UWBSTATUS_SUCCESS) {
msg.eMsgType = UCI_HAL_OPEN_CPLT_MSG;
nxpucihal_ctrl.hal_open_status = true;
nxpucihal_ctrl.halStatus = HAL_STATUS_OPEN;
} else {
msg.eMsgType = UCI_HAL_ERROR_MSG;
}
msg.pMsgData = NULL;
msg.Size = 0;
phTmlUwb_DeferredCall(gpphTmlUwb_Context->dwCallbackThreadId,
(phLibUwb_Message_t*)&msg);
return;
}
/******************************************************************************
* Function phNxpUciHal_write
*
* Description This function write the data to UWBC through physical
* interface (e.g. SPI) using the driver interface.
* Before sending the data to UWBC, phNxpUciHal_write_ext
* is called to check if there is any extension processing
* is required for the UCI packet being sent out.
*
* Returns It returns number of bytes successfully written to UWBC.
*
******************************************************************************/
tHAL_UWB_STATUS phNxpUciHal_write(uint16_t data_len, const uint8_t* p_data) {
if (nxpucihal_ctrl.halStatus != HAL_STATUS_OPEN) {
return UWBSTATUS_FAILED;
}
uint16_t len = 0;
CONCURRENCY_LOCK();
phNxpUciHal_process_ext_cmd_rsp(data_len, p_data, &len);
CONCURRENCY_UNLOCK();
/* No data written */
return len;
}
/******************************************************************************
* Function phNxpUciHal_write_unlocked
*
* Description This is the actual function which is being called by
* phNxpUciHal_write. This function writes the data to UWBC.
* It waits till write callback provide the result of write
* process.
*
* Returns It returns number of bytes successfully written to UWBC.
*
******************************************************************************/
tHAL_UWB_STATUS phNxpUciHal_write_unlocked(uint16_t data_len, const uint8_t* p_data) {
tHAL_UWB_STATUS status;
uint8_t mt, pbf, gid, oid;
phNxpUciHal_Sem_t cb_data;
/* Create the local semaphore */
if (phNxpUciHal_init_cb_data(&cb_data, NULL) != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_D("phNxpUciHal_write_unlocked Create cb data failed");
data_len = 0;
goto clean_and_return;
}
if ((data_len > UCI_MAX_DATA_LEN) || (data_len < UCI_PKT_HDR_LEN)) {
NXPLOG_UCIHAL_E("Invalid data_len");
data_len = 0;
goto clean_and_return;
}
/* Create local copy of cmd_data */
memcpy(nxpucihal_ctrl.p_cmd_data, p_data, data_len);
nxpucihal_ctrl.cmd_len = data_len;
data_len = nxpucihal_ctrl.cmd_len;
UCI_MSG_PRS_HDR0(p_data, mt, pbf, gid);
UCI_MSG_PRS_HDR1(p_data, oid);
/*vendor specific params handling*/
handlingVendorSpecificAppConfig(&nxpucihal_ctrl.cmd_len,
nxpucihal_ctrl.p_cmd_data);
/* Vendor Specific Parsing logic */
nxpucihal_ctrl.hal_parse_enabled =
phNxpUciHal_parse(nxpucihal_ctrl.cmd_len, nxpucihal_ctrl.p_cmd_data);
if (nxpucihal_ctrl.hal_parse_enabled) {
goto clean_and_return;
}
status = phTmlUwb_Write(
(uint8_t*)nxpucihal_ctrl.p_cmd_data, (uint16_t)nxpucihal_ctrl.cmd_len,
(pphTmlUwb_TransactCompletionCb_t)&phNxpUciHal_write_complete,
(void*)&cb_data);
if (status != UWBSTATUS_PENDING) {
NXPLOG_UCIHAL_E("write_unlocked status error");
data_len = 0;
goto clean_and_return;
}
/* Wait for callback response */
if (SEM_WAIT(cb_data)) {
NXPLOG_UCIHAL_E("write_unlocked semaphore error");
data_len = 0;
goto clean_and_return;
}
clean_and_return:
phNxpUciHal_cleanup_cb_data(&cb_data);
return data_len;
}
/******************************************************************************
* Function phNxpUciHal_write_complete
*
* Description This function handles write callback.
*
* Returns void.
*
******************************************************************************/
static void phNxpUciHal_write_complete(void* pContext,
phTmlUwb_TransactInfo_t* pInfo) {
phNxpUciHal_Sem_t* p_cb_data = (phNxpUciHal_Sem_t*)pContext;
if (pInfo->wStatus == UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_D("write successful status = 0x%x", pInfo->wStatus);
} else {
NXPLOG_UCIHAL_E("write error status = 0x%x", pInfo->wStatus);
}
p_cb_data->status = pInfo->wStatus;
SEM_POST(p_cb_data);
return;
}
/******************************************************************************
* Function phNxpUciHal_parse_get_capsInfo
*
* Description parse the caps info response as per FIRA 2.0.
*
* Returns void.
*
******************************************************************************/
void phNxpUciHal_parse_get_capsInfo(uint16_t data_len, uint8_t *p_data) {
uint8_t *p = p_data;
uint8_t pDeviceCapsInfo[UCI_MAX_DATA_LEN];
uint8_t *pp = pDeviceCapsInfo;
uint8_t tagId = 0, subTagId = 0, len = 0;
uint8_t mt = 0, gid = 0, oid = 0;
uint8_t capsLen = p_data[5];
uint8_t dataLen = p_data[3];
mt = (*(p_data)&UCI_MT_MASK) >> UCI_MT_SHIFT;
gid = p_data[0] & UCI_GID_MASK;
oid = p_data[1] & UCI_OID_MASK;
uint8_t *p_caps_value;
if (mt == UCI_MT_RSP) {
if ((gid == UCI_GID_CORE) && (oid == UCI_MSG_CORE_GET_CAPS_INFO)) {
if (p_data[4] == 0) {
for (uint16_t index = 6; index < data_len;) {
tagId = p_data[index++];
if (tagId != 0xE0 && tagId != 0xE3) {
len = p_data[index++];
/* b0 = Azimuth AoA -90 degree to 90 degree
* b1 = Azimuth AoA -180 degree to 180 degree
* b2 = Elevation AoA
* b3 = AoA FOM
*/
if (AOA_SUPPORT_TAG_ID == tagId) {
if (isAntennaRxPairDefined) {
if (numberOfAntennaPairs == 1) {
*p_caps_value = 1;
} else if (numberOfAntennaPairs > 1) {
// If antenna pair more than 1 then it will support both b0
// = Azimuth AoA -90° to 90° and b2=Elevation AoA then value
// will set to 5
*p_caps_value = 5;
}
} else {
*p_caps_value = 0;
}
} else {
p_caps_value = (uint8_t *)(p_data + index);
}
UINT8_TO_STREAM(pp, tagId);
UINT8_TO_STREAM(pp, len);
if (tagId == CCC_SUPPORTED_PROTOCOL_VERSIONS_ID) {
UINT8_TO_STREAM(pp, p_caps_value[len - 1]);
UINT8_TO_STREAM(pp, p_caps_value[0]);
} else {
ARRAY_TO_STREAM(pp, p_caps_value, len);
}
index = index + len;
} else { // ignore vendor specific data
if ((index + 1) >= data_len) {
break;
}
subTagId = p_data[index++];
if ((index + 1) > data_len) {
break;
}
len = p_data[index++];
index = index + len;
capsLen--;
dataLen =
dataLen - (len + 3); // from datalen substract tagId,
// subTagId, len and value of config
}
}
// mapping device caps according to Fira 2.0
// TODO: Remove once FW support available
std::array<uint8_t, NXP_MAX_CONFIG_STRING_LEN> buffer;
buffer.fill(0);
uint8_t *vendorConfig = NULL;
long retlen = 0;
int numberOfParams = 0;
if (NxpConfig_GetByteArray(NAME_UWB_VENDOR_CAPABILITY,
buffer.data(), buffer.size(),
&retlen)) {
if (retlen > 0) {
vendorConfig = buffer.data();
ARRAY_TO_STREAM(pp, vendorConfig, retlen);
dataLen += retlen;
// calculate number of params
int index = 0, paramId, length;
do {
paramId = vendorConfig[index++];
length = vendorConfig[index++];
index = index + length;
numberOfParams++;
} while (index < retlen);
NXPLOG_UCIHAL_D("Get caps read info from config file, length: "
"%ld, numberOfParams: %d",
retlen, numberOfParams);
nxpucihal_ctrl.rx_data_len = UCI_MSG_HDR_SIZE + dataLen;
UCI_MSG_BLD_HDR0(p, UCI_MT_RSP, UCI_GID_CORE);
UCI_MSG_BLD_HDR1(p, UCI_MSG_CORE_GET_CAPS_INFO);
UINT8_TO_STREAM(p, 0x00);
UINT8_TO_STREAM(p, dataLen);
UINT8_TO_STREAM(p, 0x00); // status
UINT8_TO_STREAM(p, (capsLen + numberOfParams));
ARRAY_TO_STREAM(p, pDeviceCapsInfo, dataLen);
} else {
NXPLOG_UCIHAL_E("Reading config file for %s failed!!!",
NAME_UWB_VENDOR_CAPABILITY);
}
}
}
phNxpUciHal_print_packet("RECV", nxpucihal_ctrl.p_rx_data,
nxpucihal_ctrl.rx_data_len);
}
}
}
/******************************************************************************
* Function phNxpUciHal_read_complete
*
* Description This function is called whenever there is an UCI packet
* received from UWBC. It could be RSP or NTF packet. This
* function provide the received UCI packet to libuwb-uci
* using data callback of libuwb-uci.
* There is a pending read called from each
* phNxpUciHal_read_complete so each a packet received from
* UWBC can be provide to libuwb-uci.
*
* Returns void.
*
******************************************************************************/
void phNxpUciHal_read_complete(void* pContext,
phTmlUwb_TransactInfo_t* pInfo) {
tHAL_UWB_STATUS status;
uint8_t gid = 0, oid = 0, pbf = 0, mt = 0;
UNUSED(pContext);
if (nxpucihal_ctrl.read_retry_cnt == 1) {
nxpucihal_ctrl.read_retry_cnt = 0;
}
if (pInfo->wStatus == UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_D("read successful status = 0x%x", pInfo->wStatus);
nxpucihal_ctrl.p_rx_data = pInfo->pBuff;
nxpucihal_ctrl.rx_data_len = pInfo->wLength;
mt = ((nxpucihal_ctrl.p_rx_data[0]) & UCI_MT_MASK) >> UCI_MT_SHIFT;
gid = nxpucihal_ctrl.p_rx_data[0] & UCI_GID_MASK;
oid = nxpucihal_ctrl.p_rx_data[1] & UCI_OID_MASK;
pbf = (nxpucihal_ctrl.p_rx_data[0] & UCI_PBF_MASK) >> UCI_PBF_SHIFT;
if (gid == UCI_GID_CORE && oid == UCI_OID_GET_CAPS_INFO) {
phNxpUciHal_parse_get_capsInfo(nxpucihal_ctrl.rx_data_len,
nxpucihal_ctrl.p_rx_data);
}
nxpucihal_ctrl.isSkipPacket = 0;
phNxpUciHal_parse(nxpucihal_ctrl.rx_data_len, nxpucihal_ctrl.p_rx_data);
phNxpUciHal_process_response();
if(!uwb_device_initialized) {
if (pbf) {
/* XXX: fix the whole logic if this really happens */
NXPLOG_UCIHAL_E("FIXME: Fragmented packets received during device-init!");
}
if((gid == UCI_GID_CORE) && (oid == UCI_MSG_CORE_DEVICE_STATUS_NTF)) {
nxpucihal_ctrl.uwbc_device_state = nxpucihal_ctrl.p_rx_data[UCI_RESPONSE_STATUS_OFFSET];
if(nxpucihal_ctrl.uwbc_device_state == UWB_DEVICE_INIT || nxpucihal_ctrl.uwbc_device_state == UWB_DEVICE_READY) {
nxpucihal_ctrl.isSkipPacket = 1;
SEM_POST(&(nxpucihal_ctrl.dev_status_ntf_wait));
}
}
if ((gid == UCI_GID_PROPRIETARY) && (oid == UCI_MSG_BINDING_STATUS_NTF)) {
nxpucihal_ctrl.uwb_binding_status =
nxpucihal_ctrl.p_rx_data[UCI_RESPONSE_STATUS_OFFSET];
nxpucihal_ctrl.isSkipPacket = 1;
SEM_POST(&(nxpucihal_ctrl.uwb_binding_status_ntf_wait));
}
if ((mt == UCI_MT_NTF) && (gid == UCI_GID_PROPRIETARY_0X0F) &&
(oid == UCI_MSG_UWB_ESE_BINDING_NTF)) {
nxpucihal_ctrl.uwb_binding_count =
nxpucihal_ctrl.p_rx_data[UCI_RESPONSE_STATUS_OFFSET + 1];
nxpucihal_ctrl.uwb_binding_status =
nxpucihal_ctrl.p_rx_data[UCI_RESPONSE_STATUS_OFFSET + 2];
nxpucihal_ctrl.isSkipPacket = 1;
SEM_POST(&(nxpucihal_ctrl.uwb_do_bind_ntf_wait));
}
if ((mt == UCI_MT_NTF) && (gid == UCI_GID_PROPRIETARY_0X0F) &&
(oid == UWB_ESE_BINDING_CHECK_NTF)) {
nxpucihal_ctrl.uwb_binding_status =
nxpucihal_ctrl.p_rx_data[UCI_RESPONSE_STATUS_OFFSET];
nxpucihal_ctrl.p_rx_data[0] = 0x6E;
nxpucihal_ctrl.p_rx_data[1] = 0x06;
nxpucihal_ctrl.p_rx_data[2] = 0x00;
nxpucihal_ctrl.p_rx_data[3] = 0x01;
nxpucihal_ctrl.p_rx_data[4] = nxpucihal_ctrl.uwb_binding_status;
nxpucihal_ctrl.rx_data_len = 5;
SEM_POST(&(nxpucihal_ctrl.uwb_get_binding_status_ntf_wait));
}
}
// phNxpUciHal_process_ext_cmd_rsp() is waiting for the response packet
// set this true to wake it up for other reasons
bool bWakeupExtCmd = (mt == UCI_MT_RSP);
/* DBG packets not yet supported, just ignore them silently */
if (!nxpucihal_ctrl.isSkipPacket) {
if ((mt == UCI_MT_NTF) && (gid == UCI_GID_INTERNAL) &&
(oid == UCI_EXT_PARAM_DBG_RFRAME_LOG_NTF)) {
nxpucihal_ctrl.isSkipPacket = 1;
}
}
// Handle retransmissions
if (!nxpucihal_ctrl.isSkipPacket) {
if (!pbf && mt == UCI_MT_NTF && gid == UCI_GID_CORE && oid == UCI_MSG_CORE_GENERIC_ERROR_NTF) {
uint8_t status_code = nxpucihal_ctrl.p_rx_data[UCI_RESPONSE_STATUS_OFFSET];
if (status_code == UCI_STATUS_COMMAND_RETRY) {
nxpucihal_ctrl.ext_cb_data.status = UWBSTATUS_COMMAND_RETRANSMIT;
nxpucihal_ctrl.isSkipPacket = 1;
bWakeupExtCmd = true;
} else if (status_code == UCI_STATUS_INVALID_MSG_SIZE) {
nxpucihal_ctrl.ext_cb_data.status = UWBSTATUS_INVALID_COMMAND_LENGTH;
nxpucihal_ctrl.isSkipPacket = 1;
bWakeupExtCmd = true;
}
}
}
// Check status code only for extension commands
if (!nxpucihal_ctrl.isSkipPacket) {
if (mt == UCI_MT_RSP) {
if (nxpucihal_ctrl.hal_ext_enabled) {
nxpucihal_ctrl.isSkipPacket = 1;
if (pbf) {
/* XXX: fix the whole logic if this really happens */
NXPLOG_UCIHAL_E("FIXME: Fragmented packets received while processing internal commands!");
}
uint8_t status_code = (nxpucihal_ctrl.rx_data_len > UCI_RESPONSE_STATUS_OFFSET) ?
nxpucihal_ctrl.p_rx_data[UCI_RESPONSE_STATUS_OFFSET] : UCI_STATUS_UNKNOWN;
if (status_code == UCI_STATUS_OK) {
nxpucihal_ctrl.ext_cb_data.status = UWBSTATUS_SUCCESS;
} else if ((gid == UCI_GID_CORE) && (oid == UCI_MSG_CORE_SET_CONFIG)){
/* check if any configurations are not supported then ignore the
* UWBSTATUS_FEATURE_NOT_SUPPORTED status code*/
nxpucihal_ctrl.ext_cb_data.status = phNxpUciHal_process_ext_rsp(nxpucihal_ctrl.rx_data_len, nxpucihal_ctrl.p_rx_data);
} else {
nxpucihal_ctrl.ext_cb_data.status = UWBSTATUS_FAILED;
NXPLOG_UCIHAL_E("Got error status code(0x%x) from internal command.", status_code);
usleep(1); // XXX: not sure if it's really needed
}
}
}
}
if (bWakeupExtCmd && nxpucihal_ctrl.ext_cb_waiting) {
SEM_POST(&(nxpucihal_ctrl.ext_cb_data));
}
if (!nxpucihal_ctrl.isSkipPacket) {
/* Read successful, send the event to higher layer */
if ((nxpucihal_ctrl.p_uwb_stack_data_cback != NULL) && (nxpucihal_ctrl.rx_data_len <= UCI_MAX_PAYLOAD_LEN)) {
(*nxpucihal_ctrl.p_uwb_stack_data_cback)(nxpucihal_ctrl.rx_data_len, nxpucihal_ctrl.p_rx_data);
}
}
} else { // pInfo->wStatus != UWBSTATUS_SUCCESS
NXPLOG_UCIHAL_E("read error status = 0x%x", pInfo->wStatus);
}
/* Disable junk data check for each UCI packet*/
if(nxpucihal_ctrl.fw_dwnld_mode) {
if((gid == UCI_GID_CORE) && (oid == UCI_MSG_CORE_DEVICE_STATUS_NTF)){
nxpucihal_ctrl.fw_dwnld_mode = false;
}
}
/* Read again because read must be pending always.*/
if (nxpucihal_ctrl.halStatus != HAL_STATUS_CLOSE) {
status = phTmlUwb_Read(
Rx_data, UCI_MAX_DATA_LEN,
(pphTmlUwb_TransactCompletionCb_t)&phNxpUciHal_read_complete, NULL);
if (status != UWBSTATUS_PENDING) {
NXPLOG_UCIHAL_E("read status error status = %x", status);
/* TODO: Not sure how to handle this ? */
}
}
}
/******************************************************************************
* Function phNxpUciHal_close
*
* Description This function close the UWBC interface and free all
* resources.This is called by libuwb-uci on UWB service stop.
*
* Returns Always return UWBSTATUS_SUCCESS (0).
*
******************************************************************************/
tHAL_UWB_STATUS phNxpUciHal_close() {
tHAL_UWB_STATUS status;
if (nxpucihal_ctrl.halStatus == HAL_STATUS_CLOSE) {
NXPLOG_UCIHAL_E("phNxpUciHal_close is already closed, ignoring close");
return UWBSTATUS_FAILED;
}
uwb_device_initialized = false;
CONCURRENCY_LOCK();
nxpucihal_ctrl.halStatus = HAL_STATUS_CLOSE;
if (NULL != gpphTmlUwb_Context->pDevHandle) {
phNxpUciHal_close_complete(UWBSTATUS_SUCCESS);
/* Abort any pending read and write */
status = phTmlUwb_ReadAbort();
status = phTmlUwb_WriteAbort();
phOsalUwb_Timer_Cleanup();
status = phTmlUwb_Shutdown();
phDal4Uwb_msgrelease(nxpucihal_ctrl.gDrvCfg.nClientId);
memset(&nxpucihal_ctrl, 0x00, sizeof(nxpucihal_ctrl));
NXPLOG_UCIHAL_D("phNxpUciHal_close - phOsalUwb_DeInit completed");
}
CONCURRENCY_UNLOCK();
phNxpUciHal_cleanup_monitor();
/* Return success always */
return UWBSTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpUciHal_close_complete
*
* Description This function inform libuwb-uci about result of
* phNxpUciHal_close.
*
* Returns void.
*
******************************************************************************/
void phNxpUciHal_close_complete(tHAL_UWB_STATUS status) {
static phLibUwb_Message_t msg;
if (status == UWBSTATUS_SUCCESS) {
msg.eMsgType = UCI_HAL_CLOSE_CPLT_MSG;
} else {
msg.eMsgType = UCI_HAL_ERROR_MSG;
}
msg.pMsgData = NULL;
msg.Size = 0;
phTmlUwb_DeferredCall(gpphTmlUwb_Context->dwCallbackThreadId, &msg);
return;
}
/******************************************************************************
* Function phNxpUciHal_init_complete
*
* Description This function inform libuwb-uci about result of
* phNxpUciHal_coreInitialization.
*
* Returns void.
*
******************************************************************************/
void phNxpUciHal_init_complete(tHAL_UWB_STATUS status) {
static phLibUwb_Message_t msg;
if (status == UWBSTATUS_SUCCESS) {
msg.eMsgType = UCI_HAL_INIT_CPLT_MSG;
} else {
msg.eMsgType = UCI_HAL_ERROR_MSG;
}
msg.pMsgData = NULL;
msg.Size = 0;
phTmlUwb_DeferredCall(gpphTmlUwb_Context->dwCallbackThreadId, &msg);
return;
}
/******************************************************************************
* Function phNxpUciHal_sendGetCoreDeviceInfo
*
* Description This function send Core device Info command.
*
* Returns status.
*
******************************************************************************/
static uint8_t phNxpUciHal_sendGetCoreDeviceInfo(void)
{
if (nxpucihal_ctrl.isDevInfoCached) {
return UWBSTATUS_SUCCESS;
}
const uint8_t getCoreDeviceInfoConfig[] = {0x20, 0x02, 0x00, 0x00};
uint8_t getCoreDeviceInfoCmdLen = 4;
tHAL_UWB_STATUS status = phNxpUciHal_send_ext_cmd(getCoreDeviceInfoCmdLen, getCoreDeviceInfoConfig);
return status;
}
/******************************************************************************
* Function parseAntennaConfig
*
* Description This function parse the antenna config and update required
* params
*
* Returns void
*
******************************************************************************/
void parseAntennaConfig(uint16_t dataLength, const uint8_t *data) {
if (dataLength > 0) {
uint8_t index =
UCI_MSG_HDR_SIZE + 1; // Excluding the header and number of params
uint8_t tagId, subTagId;
int length;
while (index < dataLength) {
tagId = data[index++];
subTagId = data[index++];
length = data[index++];
if ((ANTENNA_RX_PAIR_DEFINE_TAG_ID == tagId) &&
(ANTENNA_RX_PAIR_DEFINE_SUB_TAG_ID == subTagId)) {
isAntennaRxPairDefined = true;
numberOfAntennaPairs = data[index];
NXPLOG_UCIHAL_D("numberOfAntennaPairs:%d", numberOfAntennaPairs);
break;
} else {
index = index + length;
}
};
} else {
NXPLOG_UCIHAL_E("Reading config file for %s failed!!!",
NAME_UWB_CORE_EXT_DEVICE_DEFAULT_CONFIG);
}
}
/******************************************************************************
* Function phNxpUciHal_configureLowPowerMode
*
* Description This function applies low power mode value from config file
*
* Returns success/Failure
*
******************************************************************************/
bool phNxpUciHal_configureLowPowerMode() {
uint8_t configValue;
unsigned long num = 1;
bool isSendSuccess = false;
if (NxpConfig_GetNum(NAME_NXP_UWB_LOW_POWER_MODE, &configValue, num)) {
// Core set config packet: GID=0x00 OID=0x04
const std::vector<uint8_t> packet(
{((UCI_MT_CMD << UCI_MT_SHIFT) | UCI_GID_CORE), UCI_MSG_CORE_SET_CONFIG,
0x00, 0x04, 0x01, LOW_POWER_MODE_TAG_ID, LOW_POWER_MODE_LENGTH,
configValue});
if (phNxpUciHal_send_ext_cmd(packet.size(), packet.data()) ==
UWBSTATUS_SUCCESS) {
isSendSuccess = true;
}
} else {
NXPLOG_UCIHAL_E("NAME_NXP_UWB_LOW_POWER_MODE config read failed");
}
return isSendSuccess;
}
/******************************************************************************
* Function phNxpUciHal_applyVendorConfig
*
* Description This function applies the vendor config from config file
*
* Returns status
*
******************************************************************************/
tHAL_UWB_STATUS phNxpUciHal_applyVendorConfig() {
NXPLOG_UCIHAL_D(" phNxpUciHal_applyVendorConfig Enter..");
std::array<uint8_t, NXP_MAX_CONFIG_STRING_LEN> buffer;
uint8_t *vendorConfig = NULL;
tHAL_UWB_STATUS status;
buffer.fill(0);
long retlen = 0;
if (nxpucihal_ctrl.fw_boot_mode == USER_FW_BOOT_MODE) {
if (NxpConfig_GetByteArray(NAME_UWB_USER_FW_BOOT_MODE_CONFIG,
buffer.data(), buffer.size(),
&retlen)) {
if ((retlen > 0) && (retlen <= UCI_MAX_DATA_LEN)) {
vendorConfig = buffer.data();
status = phNxpUciHal_send_ext_cmd(retlen, vendorConfig);
NXPLOG_UCIHAL_D(
" phNxpUciHal_send_ext_cmd :: status value for %s is %d ",
NAME_UWB_USER_FW_BOOT_MODE_CONFIG, status);
if (status != UWBSTATUS_SUCCESS) {
return status;
}
}
}
}
if (NxpConfig_GetByteArray(NAME_NXP_UWB_EXTENDED_NTF_CONFIG,
buffer.data(), buffer.size(),
&retlen)) {
if (retlen > 0) {
vendorConfig = buffer.data();
status = phNxpUciHal_send_ext_cmd(retlen, vendorConfig);
NXPLOG_UCIHAL_D(" phNxpUciHal_send_ext_cmd :: status value for %s is %d ",
NAME_NXP_UWB_EXTENDED_NTF_CONFIG, status);
if (status != UWBSTATUS_SUCCESS) {
return status;
}
}
}
if (nxpucihal_ctrl.device_type == DEVICE_TYPE_SR1xxT) {
if (NxpConfig_GetByteArray(NAME_UWB_CORE_EXT_DEVICE_SR1XX_T_CONFIG,
buffer.data(), buffer.size(),
&retlen)) {
if (retlen > 0) {
vendorConfig = buffer.data();
status = phNxpUciHal_send_ext_cmd(retlen, vendorConfig);
NXPLOG_UCIHAL_D(
" phNxpUciHal_send_ext_cmd :: status value for %s is %d ",
NAME_UWB_CORE_EXT_DEVICE_SR1XX_T_CONFIG, status);
// AOA support handling
parseAntennaConfig(retlen, vendorConfig);
if (status != UWBSTATUS_SUCCESS) {
return status;
}
}
}
} else if (nxpucihal_ctrl.device_type == DEVICE_TYPE_SR1xxS) {
if (NxpConfig_GetByteArray(NAME_UWB_CORE_EXT_DEVICE_SR1XX_S_CONFIG,
buffer.data(), buffer.size(),
&retlen)) {
if (retlen > 0) {
vendorConfig = buffer.data();
status = phNxpUciHal_send_ext_cmd(retlen, vendorConfig);
NXPLOG_UCIHAL_D(
" phNxpUciHal_send_ext_cmd :: status value for %s is %d ",
NAME_UWB_CORE_EXT_DEVICE_SR1XX_S_CONFIG, status);
// AOA support handling
parseAntennaConfig(retlen, vendorConfig);
if (status != UWBSTATUS_SUCCESS) {
return status;
}
}
}
} else {
NXPLOG_UCIHAL_D("phNxpUciHal_sendGetCoreDeviceInfo deviceType default");
if (NxpConfig_GetByteArray(NAME_UWB_CORE_EXT_DEVICE_DEFAULT_CONFIG,
buffer.data(), buffer.size(),
&retlen)) {
if (retlen > 0) {
vendorConfig = buffer.data();
status = phNxpUciHal_send_ext_cmd(retlen, vendorConfig);
NXPLOG_UCIHAL_D(
" phNxpUciHal_send_ext_cmd :: status value for %s is %d ",
NAME_UWB_CORE_EXT_DEVICE_DEFAULT_CONFIG, status);
// AOA support handling
parseAntennaConfig(retlen, vendorConfig);
if (status != UWBSTATUS_SUCCESS) {
return status;
}
}
}
}
if (NxpConfig_GetByteArray(NAME_NXP_UWB_XTAL_38MHZ_CONFIG,
buffer.data(), buffer.size(),
&retlen)) {
if (retlen > 0) {
vendorConfig = buffer.data();
status = phNxpUciHal_send_ext_cmd(retlen, vendorConfig);
NXPLOG_UCIHAL_D(" phNxpUciHal_send_ext_cmd :: status value for %s is %d ",
NAME_NXP_UWB_XTAL_38MHZ_CONFIG, status);
if (status != UWBSTATUS_SUCCESS) {
return status;
}
}
}
for(int i = 1;i <= 10;i++) {
std::string str = NAME_NXP_CORE_CONF_BLK;
std::string value = std::to_string(i);
std::string name = str + value;
NXPLOG_UCIHAL_D(" phNxpUciHal_applyVendorConfig :: Name of the config block is %s", name.c_str());
if (NxpConfig_GetByteArray(name.c_str(), buffer.data(), buffer.size(), &retlen)) {
if ((retlen > 0) && (retlen <= UCI_MAX_DATA_LEN)) {
vendorConfig = buffer.data();
status = phNxpUciHal_send_ext_cmd(retlen,vendorConfig);
NXPLOG_UCIHAL_D(" phNxpUciHal_send_ext_cmd :: status value for %s is %d ", name.c_str(),status);
if(status != UWBSTATUS_SUCCESS) {
return status;
}
}
} else {
NXPLOG_UCIHAL_D(
" phNxpUciHal_applyVendorConfig::%s not available in the config file",
name.c_str());
}
}
// low power mode
if (!phNxpUciHal_configureLowPowerMode()) {
NXPLOG_UCIHAL_E("phNxpUciHal_send_ext_cmd for %s failed",
NAME_NXP_UWB_LOW_POWER_MODE);
}
return UWBSTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpUciHal_uwb_reset
*
* Description This function will send UWB reset command
*
* Returns status
*
******************************************************************************/
tHAL_UWB_STATUS phNxpUciHal_uwb_reset() {
tHAL_UWB_STATUS status;
uint8_t buffer[] = {0x20, 0x00, 0x00, 0x01, 0x00};
status = phNxpUciHal_send_ext_cmd(sizeof(buffer), buffer);
if(status != UWBSTATUS_SUCCESS) {
return status;
}
return UWBSTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpUciHal_disable_dpd
*
* Description This function sends disable dpd command
*
* Returns status
*
******************************************************************************/
static tHAL_UWB_STATUS phNxpUciHal_disable_dpd() {
tHAL_UWB_STATUS status;
uint8_t buffer[] = {0x20, 0x04, 0x00, 0x04, 0x01, 0x01, 0x01, 0x00};
status = phNxpUciHal_send_ext_cmd(sizeof(buffer), buffer);
if (status != UWBSTATUS_SUCCESS) {
return status;
}
return UWBSTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpUciHal_do_bind
*
* Description This function sends bind request command
*
* Returns status
*
******************************************************************************/
static tHAL_UWB_STATUS phNxpUciHal_do_bind() {
tHAL_UWB_STATUS status;
uint8_t buffer[] = {0x2F, 0x31, 0x00, 0x00};
status = phNxpUciHal_send_ext_cmd(sizeof(buffer), buffer);
if (status != UWBSTATUS_SUCCESS) {
return status;
}
phNxpUciHal_sem_timed_wait(&nxpucihal_ctrl.uwb_do_bind_ntf_wait);
if (nxpucihal_ctrl.uwb_do_bind_ntf_wait.status != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("uwb_do_bind_ntf_wait semaphore timed out");
return UWBSTATUS_FAILED;
}
return UWBSTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpUciHal_get_binding_status
*
* Description This function request for ese binding status
*
* Returns status
*
******************************************************************************/
static tHAL_UWB_STATUS phNxpUciHal_get_binding_status() {
tHAL_UWB_STATUS status;
uint8_t lock_cmd[] = {0x2F, 0x32, 0x00, 0x00};
status = phNxpUciHal_send_ext_cmd(sizeof(lock_cmd), lock_cmd);
if (status != UWBSTATUS_SUCCESS) {
return status;
}
phNxpUciHal_sem_timed_wait(&nxpucihal_ctrl.uwb_get_binding_status_ntf_wait);
if (nxpucihal_ctrl.uwb_get_binding_status_ntf_wait.status !=
UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("uwb_get_binding_status_ntf_wait semaphore timed out");
return UWBSTATUS_FAILED;
}
return UWBSTATUS_SUCCESS;
}
/******************************************************************************
* Function phNxpUciHal_parse_binding_status_ntf
*
* Description This function parses the binding status notification
*
* Returns status
*
******************************************************************************/
static tHAL_UWB_STATUS phNxpUciHal_parse_binding_status_ntf() {
tHAL_UWB_STATUS status = UWBSTATUS_SUCCESS;
uint8_t binding_status = nxpucihal_ctrl.uwb_binding_status;
switch (binding_status) {
case UWB_DEVICE_NOT_BOUND: {
/* disable dpd */
status = phNxpUciHal_disable_dpd();
if (status != UWBSTATUS_SUCCESS) {
return status;
}
/* perform bind using do_bind command */
status = phNxpUciHal_do_bind();
if (status != UWBSTATUS_SUCCESS) {
return status;
}
if (nxpucihal_ctrl.uwb_binding_status == UWB_DEVICE_BOUND_UNLOCKED &&
nxpucihal_ctrl.uwb_binding_count < 3) {
/* perform lock using get_binding_status command */
status = phNxpUciHal_get_binding_status();
if (status != UWBSTATUS_SUCCESS) {
return status;
}
}
} break;
case UWB_DEVICE_BOUND_UNLOCKED: {
/* disable dpd */
uint8_t status = phNxpUciHal_disable_dpd();
if (status != UWBSTATUS_SUCCESS) {
return status;
}
/* perform lock using get_binding_status command */
status = phNxpUciHal_get_binding_status();
if (status != UWBSTATUS_SUCCESS) {
return status;
}
phNxpUciHal_sem_timed_wait(&nxpucihal_ctrl.uwb_get_binding_status_ntf_wait);
if (nxpucihal_ctrl.uwb_get_binding_status_ntf_wait.status !=
UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("uwb_get_binding_status_ntf_wait semaphore timed out");
/* Sending originial binding status notification to upper layer */
uint8_t data_len = 5;
uint8_t buffer[data_len];
buffer[0] = 0x6E;
buffer[1] = 0x06;
buffer[2] = 0x00;
buffer[3] = 0x01;
buffer[4] = nxpucihal_ctrl.uwb_binding_status;
if (nxpucihal_ctrl.p_uwb_stack_data_cback != NULL) {
(*nxpucihal_ctrl.p_uwb_stack_data_cback)(data_len, buffer);
}
}
} break;
case UWB_DEVICE_BOUND_LOCKED: {
// do nothing
} break;
default: {
NXPLOG_UCIHAL_E("[%s] unknown binding status:%d", __func__, binding_status);
}
}
return status;
}
/******************************************************************************
* Function phNxpUciHal_coreInitialization
*
* Description This function performs core initialization
*
* Returns status
*
******************************************************************************/
tHAL_UWB_STATUS phNxpUciHal_coreInitialization() {
tHAL_UWB_STATUS status;
uint8_t fwd_retry_count = 0;
uint8_t dev_ready_ntf[] = {0x60, 0x01, 0x00, 0x01, 0x01};
nxpucihal_ctrl.isRecoveryTimerStarted = false;
if (nxpucihal_ctrl.halStatus != HAL_STATUS_OPEN) {
NXPLOG_UCIHAL_E("HAL not initialized");
return UWBSTATUS_FAILED;
}
NXPLOG_UCIHAL_D(" Start FW download");
/* Create the local semaphore */
if (phNxpUciHal_init_cb_data(&nxpucihal_ctrl.dev_status_ntf_wait, NULL) !=
UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("Create dev_status_ntf_wait failed");
return UWBSTATUS_FAILED;
}
if (phNxpUciHal_init_cb_data(&nxpucihal_ctrl.uwb_binding_status_ntf_wait, NULL) !=
UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("Create uwb_binding_status_ntf_wait failed");
return UWBSTATUS_FAILED;
}
if (phNxpUciHal_init_cb_data(&nxpucihal_ctrl.uwb_get_binding_status_ntf_wait,
NULL) != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("Create uwb_get_binding_status_ntf_wait failed");
return UWBSTATUS_FAILED;
}
if (phNxpUciHal_init_cb_data(&nxpucihal_ctrl.uwb_do_bind_ntf_wait, NULL) !=
UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("Create uwb_do_bind_ntf_wait failed");
return UWBSTATUS_FAILED;
}
nxpucihal_ctrl.fw_dwnld_mode = true; /* system in FW download mode*/
uwb_device_initialized = false;
fwd_retry:
nxpucihal_ctrl.uwbc_device_state = UWB_DEVICE_ERROR;
nxpucihal_ctrl.uwb_binding_status = UWB_DEVICE_UNKNOWN;
status = phNxpUciHal_fw_download();
if(status == UWBSTATUS_SUCCESS) {
status = phTmlUwb_Read( Rx_data, UCI_MAX_DATA_LEN,
(pphTmlUwb_TransactCompletionCb_t)&phNxpUciHal_read_complete, NULL);
if (status != UWBSTATUS_PENDING) {
NXPLOG_UCIHAL_E("read status error status = %x", status);
goto failure;
}
phNxpUciHal_sem_timed_wait(&nxpucihal_ctrl.dev_status_ntf_wait);
if (nxpucihal_ctrl.dev_status_ntf_wait.status != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("UWB_DEVICE_INIT dev_status_ntf_wait semaphore timed out");
goto failure;
}
if(nxpucihal_ctrl.uwbc_device_state != UWB_DEVICE_INIT) {
NXPLOG_UCIHAL_E("UWB_DEVICE_INIT not received uwbc_device_state = %x",nxpucihal_ctrl.uwbc_device_state);
goto failure;
}
status = phNxpUciHal_set_board_config();
if (status != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("%s: Set Board Config Failed", __func__);
goto failure;
}
phNxpUciHal_sem_timed_wait(&nxpucihal_ctrl.dev_status_ntf_wait);
if (nxpucihal_ctrl.dev_status_ntf_wait.status != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("UWB_DEVICE_READY dev_status_ntf_wait semaphore timed out");
goto failure;
}
if(nxpucihal_ctrl.uwbc_device_state != UWB_DEVICE_READY) {
NXPLOG_UCIHAL_E("UWB_DEVICE_READY not received uwbc_device_state = %x",nxpucihal_ctrl.uwbc_device_state);
goto failure;
}
NXPLOG_UCIHAL_D("%s: Send device reset", __func__);
status = phNxpUciHal_uwb_reset();
if (status != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("%s: device reset Failed", __func__);
goto failure;
}
phNxpUciHal_sem_timed_wait(&nxpucihal_ctrl.dev_status_ntf_wait);
if (nxpucihal_ctrl.dev_status_ntf_wait.status != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("UWB_DEVICE_READY dev_status_ntf_wait semaphore timed out");
goto failure;
}
if(nxpucihal_ctrl.uwbc_device_state != UWB_DEVICE_READY) {
NXPLOG_UCIHAL_E("UWB_DEVICE_READY not received uwbc_device_state = %x",nxpucihal_ctrl.uwbc_device_state);
goto failure;
}
status = phNxpUciHal_sendGetCoreDeviceInfo();
NXPLOG_UCIHAL_D("phNxpUciHal_sendGetCoreDeviceInfo status %d ",
status);
if (status != UWBSTATUS_SUCCESS) {
return status;
}
phNxpUciHal_sem_timed_wait(&nxpucihal_ctrl.uwb_binding_status_ntf_wait);
if (nxpucihal_ctrl.uwb_binding_status_ntf_wait.status == UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_D("binding status notification received");
if (nxpucihal_ctrl.fw_boot_mode == USER_FW_BOOT_MODE) {
status = phNxpUciHal_parse_binding_status_ntf();
if (status != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("binding failed with status %d", status);
}
}
} else {
NXPLOG_UCIHAL_D("%s:binding status notification timed out",
__func__);
}
status = phNxpUciHal_applyVendorConfig();
if (status != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_E("%s: Apply vendor Config Failed", __func__);
goto failure;
}
phNxpUciHal_extcal_handle_coreinit();
uwb_device_initialized = true;
phNxpUciHal_getVersionInfo();
phNxpUciHal_init_complete(UWBSTATUS_SUCCESS);
} else if(status == UWBSTATUS_FILE_NOT_FOUND) {
NXPLOG_UCIHAL_E("FW download File Not found: status= %x", status);
goto failure;
} else {
NXPLOG_UCIHAL_E("FW download is failed FW download recovery starts: status= %x", status);
fwd_retry_count++;
if(fwd_retry_count <= FWD_MAX_RETRY_COUNT) {
phTmlUwb_Chip_Reset();
usleep(5000);
goto fwd_retry;
} else {
goto failure;
}
}
if (nxpucihal_ctrl.p_uwb_stack_data_cback != NULL) {
(*nxpucihal_ctrl.p_uwb_stack_data_cback)((sizeof(dev_ready_ntf)/sizeof(uint8_t)),
dev_ready_ntf);
}
phNxpUciHal_cleanup_cb_data(&nxpucihal_ctrl.dev_status_ntf_wait);
phNxpUciHal_cleanup_cb_data(
&nxpucihal_ctrl.uwb_get_binding_status_ntf_wait);
phNxpUciHal_cleanup_cb_data(&nxpucihal_ctrl.uwb_do_bind_ntf_wait);
phNxpUciHal_cleanup_cb_data(&nxpucihal_ctrl.uwb_binding_status_ntf_wait);
return status;
failure:
phNxpUciHal_init_complete(UWBSTATUS_FAILED);
phNxpUciHal_cleanup_cb_data(&nxpucihal_ctrl.dev_status_ntf_wait);
phNxpUciHal_cleanup_cb_data(
&nxpucihal_ctrl.uwb_get_binding_status_ntf_wait);
phNxpUciHal_cleanup_cb_data(&nxpucihal_ctrl.uwb_do_bind_ntf_wait);
phNxpUciHal_cleanup_cb_data(&nxpucihal_ctrl.uwb_binding_status_ntf_wait);
return UWBSTATUS_FAILED;
}
/******************************************************************************
* Function phNxpUciHal_sessionInitialization
*
* Description This function performs session initialization
*
* Returns status
*
******************************************************************************/
tHAL_UWB_STATUS phNxpUciHal_sessionInitialization(uint32_t sessionId) {
NXPLOG_UCIHAL_D(" %s: Enter", __func__);
std::array<uint8_t, NXP_MAX_CONFIG_STRING_LEN> buffer;
uint8_t vendorConfig[NXP_MAX_CONFIG_STRING_LEN] = {0x2F, 0x00, 0x00};
tHAL_UWB_STATUS status = UWBSTATUS_SUCCESS;
buffer.fill(0);
int max_config_length = NXP_MAX_CONFIG_STRING_LEN - UCI_MSG_HDR_SIZE
- sizeof(sessionId);
long retlen = 0, cmdlen = 0;
bool appConfigStatus = false;
if (nxpucihal_ctrl.halStatus != HAL_STATUS_OPEN) {
NXPLOG_UCIHAL_E("HAL not initialized");
return UWBSTATUS_FAILED;
}
if(nxpucihal_ctrl.device_type == DEVICE_TYPE_SR1xxT) {
appConfigStatus = NxpConfig_GetByteArray(NAME_NXP_UWB_EXT_APP_SR1XX_T_CONFIG,
buffer.data(), buffer.size(),
&retlen);
} else if (nxpucihal_ctrl.device_type == DEVICE_TYPE_SR1xxS) {
appConfigStatus = NxpConfig_GetByteArray(NAME_NXP_UWB_EXT_APP_SR1XX_S_CONFIG,
buffer.data(), buffer.size(),
&retlen);
} else {
appConfigStatus = NxpConfig_GetByteArray(NAME_NXP_UWB_EXT_APP_DEFAULT_CONFIG,
buffer.data(), buffer.size(),
&retlen);
}
if (appConfigStatus) {
if ((retlen > 0) && (retlen <= max_config_length)) {
vendorConfig[3] = sizeof(sessionId) + retlen;
memcpy(vendorConfig + 4, &sessionId, sizeof(sessionId));
memcpy(vendorConfig + 8, buffer.data(), retlen);
cmdlen = UCI_MSG_HDR_SIZE + sizeof(sessionId) + retlen;
status = phNxpUciHal_send_ext_cmd(cmdlen, vendorConfig);
if (status != UWBSTATUS_SUCCESS) {
NXPLOG_UCIHAL_D(" %s: Apply vendor App Config Failed", __func__);
return UWBSTATUS_SUCCESS;
}
} else {
NXPLOG_UCIHAL_D(" %s: Invalid retlen", __func__);
return UWBSTATUS_SUCCESS;
}
}
return status;
}
/******************************************************************************
* Function phNxpUciHal_GetMwVersion
*
* Description This function gets the middleware version
*
* Returns phNxpUciHal_MW_Version_t
*
******************************************************************************/
phNxpUciHal_MW_Version_t phNxpUciHal_GetMwVersion() {
phNxpUciHal_MW_Version_t mwVer;
mwVer.validation = NXP_CHIP_SR100;
mwVer.android_version = NXP_ANDROID_VERSION;
NXPLOG_UCIHAL_D("0x%x:UWB MW Major Version:", UWB_NXP_MW_VERSION_MAJ);
NXPLOG_UCIHAL_D("0x%x:UWB MW Minor Version:", UWB_NXP_MW_VERSION_MIN);
mwVer.major_version = UWB_NXP_MW_VERSION_MAJ;
mwVer.minor_version = UWB_NXP_MW_VERSION_MIN;
mwVer.rc_version = UWB_NXP_ANDROID_MW_RC_VERSION;
mwVer.mw_drop = UWB_NXP_ANDROID_MW_DROP_VERSION;
return mwVer;
}
/******************************************************************************
* Function phNxpUciHal_getVersionInfo
*
* Description This function request for version information
*
* Returns void
*
******************************************************************************/
void phNxpUciHal_getVersionInfo() {
phNxpUciHal_MW_Version_t mwVersion = phNxpUciHal_GetMwVersion();
if (mwVersion.rc_version) { /* for RC release*/
ALOGI("MW Version: UWB_SW_Android_U_HKY_D%02x.%02x_RC%02x",
mwVersion.major_version, mwVersion.minor_version,
mwVersion.rc_version);
} else if (mwVersion.mw_drop) { /* For Drops */
ALOGI("MW Version: UWB_SW_Android_U_HKY_D%02x.%02x_DROP%02x",
mwVersion.major_version, mwVersion.minor_version, mwVersion.mw_drop);
} else { /* for Major Releases*/
ALOGI("MW Version: UWB_SW_Android_U_HKY_D%02x.%02x",
mwVersion.major_version, mwVersion.minor_version);
}
if (nxpucihal_ctrl.fw_version.rc_version) {
ALOGI("FW Version: %02x.%02x_RC%02x", nxpucihal_ctrl.fw_version.major_version,
nxpucihal_ctrl.fw_version.minor_version, nxpucihal_ctrl.fw_version.rc_version);
} else {
ALOGI("FW Version: %02x.%02x", nxpucihal_ctrl.fw_version.major_version,
nxpucihal_ctrl.fw_version.minor_version);
}
}