/* * Copyright (C) 2021 The Android Open Source Project * * Copyright 2021 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 "UwbJniInternal.h" #include "JniLog.h" #include "ScopedJniEnv.h" #include "SyncEvent.h" #include "UwbAdaptation.h" #include "UwbEventManager.h" #include "uwb_api.h" #include "uwb_config.h" #include "uwb_hal_int.h" #define INVALID_SESSION_ID 0xFFFFFFFF namespace android { const char *UWB_NATIVE_MANAGER_CLASS_NAME = "com/android/server/uwb/jni/NativeUwbManager"; bool uwb_debug_enabled = true; static conformanceTestData_t ConformanceDataConf; static std::map sAveragedRangingData; static std::mutex sSessionMutex; bool gIsUwaEnabled = false; bool gIsMaxPpmValueAvailable = false; static SyncEvent sUwaEnableEvent; // event for UWA_Enable() static SyncEvent sUwaDisableEvent; // event for UWA_Disable static SyncEvent sUwaSetConfigEvent; // event for Set_Config.... static SyncEvent sUwaSetAppConfigEvent; // event for Set_AppConfig.... static SyncEvent sUwaGetConfigEvent; // event for Get_Config.... static SyncEvent sUwaGetAppConfigEvent; // event for Get_AppConfig.... static SyncEvent sUwaDeviceResetEvent; // event for deviceResetEvent static SyncEvent sUwaRngStartEvent; // event for ranging start static SyncEvent sUwaRngStopEvent; // event for ranging stop static SyncEvent sUwadeviceNtfEvent; // event for device status NTF static SyncEvent sUwaSessionInitEvent; // event for sessionInit resp static SyncEvent sUwaSessionDeInitEvent; // event for sessionDeInit resp static SyncEvent sUwaGetSessionCountEvent; // event for get session count response static SyncEvent sUwaGetDeviceInfoEvent; // event for get Device Info static SyncEvent sUwaGetRangingCountEvent; // event for get ranging count response static SyncEvent sUwaGetSessionStatusEvent; // event for get the session status static SyncEvent sUwaMulticastListUpdateEvent; // event for // UWA_ControllerMulticastListUpdate static SyncEvent sUwaSendBlinkDataEvent; static SyncEvent sErrNotify; static SyncEvent sUwaSetCountryCodeEvent; // event for // UWA_ControllerSetCountryCode static SyncEvent sUwaSendRawUciEvt; // event for UWA_SendRawCommand static SyncEvent sUwaGetDeviceCapsEvent; // event for Get Device Capabilities static deviceInfo_t sUwbDeviceInfo; static uint8_t sSetAppConfig[UCI_MAX_PAYLOAD_SIZE]; static uint8_t sGetAppConfig[UCI_MAX_PAYLOAD_SIZE]; static uint8_t sGetCoreConfig[UCI_MAX_PAYLOAD_SIZE]; static uint8_t sSetCoreConfig[UCI_MAX_PAYLOAD_SIZE]; static uint8_t sUwbDeviceCapability[UCI_MAX_PKT_SIZE]; static uint8_t sSendRawResData[UCI_MAX_PAYLOAD_SIZE]; static uint32_t sRangingCount = 0; static uint8_t sNoOfAppConfigIds = 0x00; static uint8_t sNoOfCoreConfigIds = 0x00; static uint8_t sSessionCount = -1; static uint16_t sDevCapInfoLen = 0; static uint16_t sDevCapInfoIds = 0x00; static uint16_t sGetCoreConfigLen; static uint16_t sGetAppConfigLen; static uint16_t sSetAppConfigLen; static uint8_t sGetAppConfigStatus; static uint8_t sSetAppConfigStatus; static uint8_t sSendBlinkDataStatus; static uint16_t sSendRawResLen; /* command response status */ static bool sSessionInitStatus = false; static bool sSessionDeInitStatus = false; static bool sIsDeviceResetDone = false; // whether Reset Performed is Successful is done or not static bool sRangeStartStatus = false; static bool sRangeStopStatus = false; static bool sSetAppConfigRespStatus = false; static bool sGetAppConfigRespStatus = false; static bool sMulticastListUpdateStatus = false; static bool sSetCountryCodeStatus = false; static bool sGetDeviceCapsRespStatus = false; static uint8_t sSessionState = UWB_UNKNOWN_SESSION; static eUWBS_DEVICE_STATUS_t sDeviceState = UWBS_STATUS_ERROR; static UwbEventManager &uwbEventManager = UwbEventManager::getInstance(); jint MSB_BITMASK = 0x000000FF; /* Function to calculate and update ranging data averaging value into ranging * data notification */ static void update_ranging_data_average(tUWA_RANGE_DATA_NTF *rangingDataNtf) { static const char fn[] = "update_ranging_data_average"; UNUSED(fn); // Get Current Session Data SessionRangingData &sessionData = sAveragedRangingData[rangingDataNtf->session_id]; // Calculate the Average of N Distances for every Anchor, Where N is Sampling // Rate for that Anchor for (int i = 0; i < rangingDataNtf->no_of_measurements; i++) { // Get current Two way measures object tUWA_TWR_RANGING_MEASR &twr_range_measr = rangingDataNtf->ranging_measures.twr_range_measr[i]; // Get the Current Anchor Distance Queue auto &anchorDistanceQueue = sessionData.anchors[i]; JNI_TRACE_I("%s: Input Distance is: %d", fn, twr_range_measr.distance); // If Number of distances in Queue is more than Sampling Rate if (anchorDistanceQueue.size() >= sessionData.samplingRate) { // Remove items from the queue until items in the queue is one less than // sampling rate while (anchorDistanceQueue.size() >= sessionData.samplingRate) { JNI_TRACE_I("%s: Distance Popped from Queue: %d", fn, anchorDistanceQueue.front()); anchorDistanceQueue.pop_front(); } } // Push the New distance item into the Anchor Distance Queue anchorDistanceQueue.push_back(twr_range_measr.distance); // Calculate average of items(Except where distance is FFFF) // in the Queue and update averaged distance into the distance field uint32_t divider = 0; uint32_t sum = 0; for (auto it = anchorDistanceQueue.begin(); it != anchorDistanceQueue.end(); ++it) { if (*it != 0xFFFF) { sum = (uint32_t)(sum + *it); divider++; } } if (divider > 0) { twr_range_measr.distance = sum / divider; } else { twr_range_measr.distance = 0xFFFF; } JNI_TRACE_I("%s: Averaged Distance is: %d", fn, twr_range_measr.distance); } } /******************************************************************************* ** ** Function: notifyRangeDataNotification ** ** Description: Notify the Range data to application ** ** Returns: void ** *******************************************************************************/ void notifyRangeDataNotification(tUWA_RANGE_DATA_NTF *ranging_data) { static const char fn[] = "notifyRangeDataNotification"; UNUSED(fn); JNI_TRACE_I("%s: Enter", fn); if (ranging_data->ranging_measure_type == ONE_WAY_RANGING) { uwbEventManager.onRangeDataNotificationReceived(ranging_data); } else { { std::unique_lock lock(sSessionMutex); unsigned int session_id = ranging_data->session_id; auto it = sAveragedRangingData.find(session_id); if (it != sAveragedRangingData.end()) { if (sAveragedRangingData[session_id].samplingRate > 1) { JNI_TRACE_I("%s: Before Averaging", fn); update_ranging_data_average(ranging_data); JNI_TRACE_I("%s: After Averaging", fn); } } } uwbEventManager.onRangeDataNotificationReceived(ranging_data); } } /******************************************************************************* ** ** Function: uwaDeviceManagementCallback ** ** Description: Receive device management events from UCI stack. ** dmEvent: Device-management event ID. ** eventData: Data associated with event ID. ** ** Returns: None ** *******************************************************************************/ static void uwaDeviceManagementCallback(uint8_t dmEvent, tUWA_DM_CBACK_DATA *eventData) { static const char fn[] = "uwaDeviceManagementCallback"; UNUSED(fn); JNI_TRACE_I("%s: enter; event=0x%X", fn, dmEvent); switch (dmEvent) { case UWA_DM_ENABLE_EVT: /* Result of UWA_Enable */ { SyncEventGuard guard(sUwaEnableEvent); JNI_TRACE_I("%s: uwa_dm_enable_EVT; status=0x%X", fn, eventData->status); gIsUwaEnabled = eventData->status == UWA_STATUS_OK; sUwaEnableEvent.notifyOne(); } break; case UWA_DM_DISABLE_EVT: /* Result of UWA_Disable */ { SyncEventGuard guard(sUwaDisableEvent); JNI_TRACE_I("%s: UWA_DM_DISABLE_EVT", fn); gIsUwaEnabled = false; sUwaDisableEvent.notifyOne(); } break; case UWA_DM_DEVICE_RESET_RSP_EVT: // result of UWA_SendDeviceReset { JNI_TRACE_I("%s: UWA_DM_DEVICE_RESET_RSP_EVT", fn); SyncEventGuard guard(sUwaDeviceResetEvent); if (eventData->status != UWA_STATUS_OK) { JNI_TRACE_E("%s: UWA_DM_DEVICE_RESET_RSP_EVT failed", fn); } else { sIsDeviceResetDone = true; } sUwaDeviceResetEvent.notifyOne(); } break; case UWA_DM_DEVICE_STATUS_NTF_EVT: JNI_TRACE_I("%s: UWA_DM_DEVICE_STATUS_NTF_EVT", fn); { JNI_TRACE_I("device status = %x", eventData->dev_status.status); SyncEventGuard guard(sUwadeviceNtfEvent); sDeviceState = (eUWBS_DEVICE_STATUS_t)eventData->dev_status.status; if (sDeviceState == UWBS_STATUS_ERROR) sErrNotify.notifyAll(); else sUwadeviceNtfEvent.notifyOne(); uwbEventManager.onDeviceStateNotificationReceived(sDeviceState); } break; case UWA_DM_CORE_GET_DEVICE_INFO_RSP_EVT: JNI_TRACE_I("%s: UWA_DM_CORE_GET_DEVICE_INFO_RSP_EVT", fn); { SyncEventGuard guard(sUwaGetDeviceInfoEvent); if (eventData->status == UWA_STATUS_OK) { sUwbDeviceInfo.uciVersion = eventData->sGet_device_info.uci_version; sUwbDeviceInfo.macVersion = eventData->sGet_device_info.mac_version; sUwbDeviceInfo.phyVersion = eventData->sGet_device_info.phy_version; sUwbDeviceInfo.uciTestVersion = eventData->sGet_device_info.uciTest_version; uwbEventManager.onVendorDeviceInfo(eventData->sGet_device_info.vendor_info, eventData->sGet_device_info.vendor_info_len); } else { JNI_TRACE_E("%s: UWA_DM_CORE_GET_DEVICE_INFO_RSP_EVT failed", fn); } sUwaGetDeviceInfoEvent.notifyOne(); } break; case UWA_DM_CORE_SET_CONFIG_RSP_EVT: // result of UWA_SetCoreConfig JNI_TRACE_I("%s: UWA_DM_CORE_SET_CONFIG_RSP_EVT", fn); { if (eventData->status != UWA_STATUS_OK) { JNI_TRACE_E("%s: UWA_DM_CORE_SET_CONFIG_RSP_EVT failed", fn); } if (eventData->sCore_set_config.tlv_size > 0) { memcpy(sSetCoreConfig, eventData->sCore_set_config.param_ids, eventData->sCore_set_config.tlv_size); } SyncEventGuard guard(sUwaSetConfigEvent); sUwaSetConfigEvent.notifyOne(); } break; case UWA_DM_CORE_GET_CONFIG_RSP_EVT: /* Result of UWA_GetCoreConfig */ JNI_TRACE_I("%s: UWA_DM_CORE_GET_CONFIG_RSP_EVT", fn); { SyncEventGuard guard(sUwaGetConfigEvent); if (eventData->status == UWA_STATUS_OK) { sGetCoreConfigLen = eventData->sCore_get_config.tlv_size; sNoOfCoreConfigIds = eventData->sCore_get_config.no_of_ids; } else { JNI_TRACE_E("%s: UWA_DM_GET_CONFIG failed", fn); /* As of now will cary the failed ids list till this point */ sGetCoreConfigLen = 0; sNoOfCoreConfigIds = 0; } if (eventData->sCore_get_config.tlv_size > 0 && eventData->sCore_get_config.tlv_size <= sizeof(sGetCoreConfig)) { memcpy(sGetCoreConfig, eventData->sCore_get_config.param_tlvs, eventData->sCore_get_config.tlv_size); } sUwaGetConfigEvent.notifyOne(); } break; case UWA_DM_SESSION_INIT_RSP_EVT: JNI_TRACE_I("%s: UWA_DM_SESSION_INIT_RSP_EVT", fn); { SyncEventGuard guard(sUwaSessionInitEvent); if (eventData->status == UWA_STATUS_OK) { sSessionInitStatus = true; JNI_TRACE_I("%s: UWA_DM_SESSION_INIT_RSP_EVT Success", fn); } else { JNI_TRACE_E("%s: UWA_DM_SESSION_INIT_RSP_EVT failed", fn); } sUwaSessionInitEvent.notifyOne(); } break; case UWA_DM_SESSION_DEINIT_RSP_EVT: JNI_TRACE_I("%s: UWA_DM_SESSION_DEINIT_RSP_EVT", fn); { SyncEventGuard guard(sUwaSessionDeInitEvent); if (eventData->status == UWA_STATUS_OK) { sSessionDeInitStatus = true; JNI_TRACE_I("%s: UWA_DM_SESSION_DEINIT_RSP_EVT Success", fn); } else { JNI_TRACE_E("%s: UWA_DM_SESSION_DEINIT_RSP_EVT failed", fn); } sUwaSessionDeInitEvent.notifyOne(); } break; case UWA_DM_SESSION_STATUS_NTF_EVT: JNI_TRACE_I("%s: UWA_DM_SESSION_STATUS_NTF_EVT", fn); { unsigned int session_id = eventData->sSessionStatus.session_id; if (UWB_SESSION_DEINITIALIZED == eventData->sSessionStatus.state) { std::unique_lock lock(sSessionMutex); auto it = sAveragedRangingData.find(session_id); if (it != sAveragedRangingData.end()) { sAveragedRangingData.erase(session_id); JNI_TRACE_E("%s: deinit: Averaging Disabled for Session %d", fn, session_id); } } uwbEventManager.onSessionStatusNotificationReceived( eventData->sSessionStatus.session_id, eventData->sSessionStatus.state, eventData->sSessionStatus.reason_code); } break; case UWA_DM_SESSION_SET_CONFIG_RSP_EVT: // result of UWA_SetAppConfig JNI_TRACE_I("%s: UWA_DM_SESSION_SET_CONFIG_RSP_EVT", fn); { SyncEventGuard guard(sUwaSetAppConfigEvent); sSetAppConfigRespStatus = true; sSetAppConfigStatus = eventData->status; sSetAppConfigLen = eventData->sApp_set_config.tlv_size; sNoOfAppConfigIds = eventData->sApp_set_config.num_param_id; if (eventData->sApp_set_config.tlv_size > 0) { memcpy(sSetAppConfig, eventData->sApp_set_config.param_ids, eventData->sApp_set_config.tlv_size); } sUwaSetAppConfigEvent.notifyOne(); } break; case UWA_DM_SESSION_GET_CONFIG_RSP_EVT: /* Result of UWA_GetAppConfig */ JNI_TRACE_I("%s: UWA_DM_SESSION_GET_CONFIG_RSP_EVT", fn); { SyncEventGuard guard(sUwaGetAppConfigEvent); sGetAppConfigRespStatus = true; sGetAppConfigStatus = eventData->status; sGetAppConfigLen = eventData->sApp_get_config.tlv_size; sNoOfAppConfigIds = eventData->sApp_get_config.no_of_ids; if (eventData->sApp_get_config.tlv_size > 0) { memcpy(sGetAppConfig, eventData->sApp_get_config.param_tlvs, eventData->sApp_get_config.tlv_size); } sUwaGetAppConfigEvent.notifyOne(); } break; case UWA_DM_RANGE_START_RSP_EVT: /* result of range start command */ JNI_TRACE_I("%s: UWA_DM_RANGE_START_RSP_EVT", fn); { SyncEventGuard guard(sUwaRngStartEvent); if (eventData->status == UWA_STATUS_OK) { sRangeStartStatus = true; JNI_TRACE_I("%s: UWA_DM_RANGE_START_RSP_EVT Success", fn); } else { sRangeStartStatus = false; JNI_TRACE_E("%s: UWA_DM_RANGE_START_RSP_EVT failed", fn); } sUwaRngStartEvent.notifyOne(); } break; case UWA_DM_RANGE_STOP_RSP_EVT: /* result of range stop command */ JNI_TRACE_I("%s: UWA_DM_RANGE_STOP_RSP_EVT", fn); { SyncEventGuard guard(sUwaRngStopEvent); if (eventData->status == UWA_STATUS_OK) { sRangeStopStatus = true; JNI_TRACE_I("%s: UWA_DM_RANGE_STOP_RSP_EVT Success", fn); } else { sRangeStopStatus = false; JNI_TRACE_E("%s: UWA_DM_RANGE_STOP_RSP_EVT failed", fn); } sUwaRngStopEvent.notifyOne(); } break; case UWA_DM_GET_RANGE_COUNT_RSP_EVT: JNI_TRACE_I("%s: UWA_DM_GET_RANGE_COUNT_RSP_EVT", fn); { SyncEventGuard guard(sUwaGetRangingCountEvent); if (eventData->status == UWA_STATUS_OK) { sRangingCount = eventData->sGet_range_cnt.count; } else { JNI_TRACE_E("%s: get range count Request is failed", fn); sRangingCount = 0; } sUwaGetRangingCountEvent.notifyOne(); } break; case UWA_DM_RANGE_DATA_NTF_EVT: JNI_TRACE_I("%s: UWA_DM_RANGE_DATA_NTF_EVT", fn); { notifyRangeDataNotification(&eventData->sRange_data); } break; case UWA_DM_SESSION_GET_COUNT_RSP_EVT: JNI_TRACE_I("%s: UWA_DM_SESSION_GET_COUNT_RSP_EVT", fn); { SyncEventGuard guard(sUwaGetSessionCountEvent); if (eventData->status == UWA_STATUS_OK) { sSessionCount = eventData->sGet_session_cnt.count; } else { JNI_TRACE_E("%s: get session count Request is failed", fn); sSessionCount = -1; } sUwaGetSessionCountEvent.notifyOne(); } break; case UWA_DM_SESSION_GET_STATE_RSP_EVT: JNI_TRACE_I("%s: UWA_DM_SESSION_GET_STATE_RSP_EVT", fn); { SyncEventGuard guard(sUwaGetSessionStatusEvent); if (eventData->status == UWA_STATUS_OK) { sSessionState = eventData->sGet_session_state.session_state; } else { JNI_TRACE_E("%s: get session state Request is failed", fn); sSessionState = UWB_UNKNOWN_SESSION; } sUwaGetSessionStatusEvent.notifyOne(); } break; case UWA_DM_SESSION_MC_LIST_UPDATE_RSP_EVT: /* result of session update multicast list */ JNI_TRACE_I("%s: UWA_DM_SESSION_MC_LIST_UPDATE_RSP_EVT", fn); { SyncEventGuard guard(sUwaMulticastListUpdateEvent); if (eventData->status == UWA_STATUS_OK) { sMulticastListUpdateStatus = true; JNI_TRACE_I("%s: UWA_DM_SESSION_MC_LIST_UPDATE_RSP_EVT Success", fn); } else { JNI_TRACE_E("%s: UWA_DM_SESSION_MC_LIST_UPDATE_RSP_EVT failed", fn); } sUwaMulticastListUpdateEvent.notifyOne(); } break; case UWA_DM_SESSION_MC_LIST_UPDATE_NTF_EVT: JNI_TRACE_I("%s: UWA_DM_SESSION_MC_LIST_UPDATE_NTF_EVT", fn); { uwbEventManager.onMulticastListUpdateNotificationReceived( &eventData->sMulticast_list_ntf); } break; case UWA_DM_SET_COUNTRY_CODE_RSP_EVT: JNI_TRACE_I("%s: UWA_DM_COUNTRY_CODE_UPDATE_RSP_EVT", fn); { SyncEventGuard guard(sUwaSetCountryCodeEvent); if (eventData->status == UWA_STATUS_OK) { sSetCountryCodeStatus = true; JNI_TRACE_I("%s: UWA_DM_COUNTRY_CODE_UPDATE_RSP_EVT Success", fn); } else { JNI_TRACE_E("%s: UWA_DM_COUNTRY_CODE_UPDATE_RSP_EVT failed", fn); } sUwaSetCountryCodeEvent.notifyOne(); } break; case UWA_DM_SEND_BLINK_DATA_RSP_EVT: JNI_TRACE_I("%s: UWA_DM_SEND_BLINK_DATA_RSP_EVT", fn); { SyncEventGuard guard(sUwaSendBlinkDataEvent); sSendBlinkDataStatus = eventData->status; sUwaSendBlinkDataEvent.notifyOne(); } break; case UWA_DM_GET_CORE_DEVICE_CAP_RSP_EVT: JNI_TRACE_D("%s: UWA_DM_API_CORE_GET_DEVICE_CAPABILITY_EVT", fn); { SyncEventGuard guard(sUwaGetDeviceCapsEvent); sGetDeviceCapsRespStatus = true; sDevCapInfoLen = 0; if (eventData->sGet_device_capability.status == UWA_STATUS_OK) { sDevCapInfoIds = eventData->sGet_device_capability.no_of_tlvs; sDevCapInfoLen = eventData->sGet_device_capability.tlv_buffer_len; if (eventData->sGet_device_capability.tlv_buffer_len > 0 && (eventData->sGet_device_capability.tlv_buffer_len <= UCI_MAX_PKT_SIZE)) { memcpy(sUwbDeviceCapability, eventData->sGet_device_capability.tlv_buffer, eventData->sGet_device_capability.tlv_buffer_len); } } sUwaGetDeviceCapsEvent.notifyOne(); } break; case UWA_DM_SEND_BLINK_DATA_NTF_EVT: JNI_TRACE_I("%s: UWA_DM_SEND_BLINK_DATA_NTF_EVT", fn); { uwbEventManager.onBlinkDataTxNotificationReceived( eventData->sBlink_data_ntf.repetition_count_status); } break; case UWA_VENDOR_SPECIFIC_UCI_NTF_EVT: JNI_TRACE_I("%s: UWA_VENDOR_SPECIfIC_UCI_NTF_EVT", fn); { uint8_t mt, pbf, gid, oid, *ntf_data, *p_ntf_hdr; uint16_t len = eventData->sVendor_specific_ntf.len-UCI_MSG_HDR_SIZE; p_ntf_hdr = eventData->sVendor_specific_ntf.data; ntf_data = (uint8_t *) eventData->sVendor_specific_ntf.data + UCI_MSG_HDR_SIZE; UCI_MSG_PRS_HDR0(p_ntf_hdr, mt, pbf, gid); UCI_MSG_PRS_HDR1(p_ntf_hdr, oid); uwbEventManager.onVendorUciNotificationReceived(gid, oid, ntf_data, len); } break; case UWA_DM_CONFORMANCE_NTF_EVT: JNI_TRACE_I("%s: UWA_DM_CONFORMANCE_NTF_EVT", fn); { uwbEventManager.onRawUciNotificationReceived(eventData->sConformance_ntf.data, eventData->sConformance_ntf.length); } break; case UWA_DM_CORE_GEN_ERR_STATUS_EVT: JNI_TRACE_I("%s: UWA_DM_CORE_GEN_ERR_STATUS_EVT", fn); { uwbEventManager.onCoreGenericErrorNotificationReceived( eventData->sCore_gen_err_status.status); } break; // case UWA_DM_UWBS_RESP_TIMEOUT_EVT: // JNI_TRACE_I("%s: UWA_DM_UWBS_RESP_TIMEOUT_EVT", fn); // { // sErrNotify.notifyAll(); // sDeviceState = UWBS_STATUS_TIMEOUT; // uwbEventManager.onDeviceStateNotificationReceived(sDeviceState); // } // break; default: JNI_TRACE_I("%s: unhandled event", fn); break; } } /******************************************************************************* ** ** Function: CommandResponse_Cb ** ** Description: Receive response from the stack for raw command sent from * jni. ** ** event: event ID. ** paramLength: length of the response ** pResponseBuffer: pointer to data ** ** Returns: None ** *******************************************************************************/ static void CommandResponse_Cb(uint8_t event, uint16_t paramLength, uint8_t *pResponseBuffer) { JNI_TRACE_I("%s: Entry", __func__); if ((paramLength > UCI_RESPONSE_STATUS_OFFSET) && (pResponseBuffer != NULL)) { JNI_TRACE_I("CommandResponse_Cb Received length data = 0x%x status = 0x%x", paramLength, pResponseBuffer[UCI_RESPONSE_STATUS_OFFSET]); sSendRawResLen = paramLength-UCI_MSG_HDR_SIZE; memcpy(sSendRawResData, pResponseBuffer+UCI_MSG_HDR_SIZE, sSendRawResLen); } else { JNI_TRACE_E("%s:CommandResponse_Cb responseBuffer is NULL or Length < " "UCI_RESPONSE_STATUS_OFFSET", __func__); } SyncEventGuard guard(sUwaSendRawUciEvt); sUwaSendRawUciEvt.notifyOne(); JNI_TRACE_I("%s: Exit", __func__); } /******************************************************************************* ** ** Function: setAppConfiguration ** ** Description: Set the session specific App Config ** ** Params: session_id: Session Id of the required App Config ** noOfParams: Number of Params need to configure ** paramLen: Total Params Lentgh ** appConfigParams: AppConfigs List in TLV format ** ** Returns: If Success UWA_STATUS_OK else UWA_STATUS_FAILED ** *******************************************************************************/ static tUWA_STATUS setAppConfiguration(uint32_t session_id, uint8_t noOfParams, uint8_t paramLen, uint8_t appConfigParams[]) { static const char fn[] = "setAppConfiguration"; UNUSED(fn); tUWA_STATUS status; sSetAppConfigRespStatus = false; SyncEventGuard guard(sUwaSetAppConfigEvent); status = UWA_SetAppConfig(session_id, noOfParams, paramLen, appConfigParams); if (status == UWA_STATUS_OK) { sUwaSetAppConfigEvent.wait(UWB_CMD_TIMEOUT); JNI_TRACE_I("%s: Success UWA_SetAppConfig Command", fn); } else { JNI_TRACE_E("%s: Failed UWA_SetAppConfig Command", fn); return UWA_STATUS_FAILED; } return (sSetAppConfigRespStatus) ? UWA_STATUS_OK : UWA_STATUS_FAILED; } /******************************************************************************* ** ** Function: sendRawUci ** ** Description: Invoked this API to send raw uci cmds ** ** Params: rawCmd: Ponter to the raw uci command ** cmdLen: Length of the command ** rsoData: Pointer to the response for sendRawUci cmd ** rspLen: Length of response ** ** Returns: If Success UWA_STATUS_OK else UWA_STATUS_FAILED ** *******************************************************************************/ static tUWA_STATUS sendRawUci(uint8_t gid, uint8_t oid, uint8_t *rawCmd, uint16_t cmdLen) { tUWA_STATUS status = UWA_STATUS_FAILED; uint8_t* pp; uint8_t* p; uint16_t len = cmdLen+UCI_MSG_HDR_SIZE; p = pp = (uint8_t *) phUwb_GKI_getbuf(len); if (pp != NULL) { SyncEventGuard guard(sUwaSendRawUciEvt); UCI_MSG_BLD_HDR0(pp, UCI_MT_CMD, gid); UCI_MSG_BLD_HDR1(pp, oid); UINT8_TO_STREAM(pp, 0x00); if (cmdLen ==1 && rawCmd[0] == 0 ) { UINT8_TO_STREAM(pp, 0); ARRAY_TO_STREAM(pp, rawCmd, 1); } else { UINT8_TO_STREAM(pp,cmdLen); ARRAY_TO_STREAM(pp, rawCmd, cmdLen); } status = UWA_SendRawCommand(len, p, CommandResponse_Cb); phUwb_GKI_freebuf(p); if (status == UWA_STATUS_OK) { JNI_TRACE_I("%s: Success UWA_SendRawCommand", __func__); sUwaSendRawUciEvt.wait(UWB_CMD_TIMEOUT); } else { JNI_TRACE_E("%s: Failed UWA_SendRawCommand", __func__); return status; } } JNI_TRACE_I("%s: Exit", __func__); return status; } /******************************************************************************* ** ** Function: SetCoreDeviceConfigurations ** ** Description: Set the Core Device Config ** ** ** Returns: If Success UWA_STATUS_OK else UWA_STATUS_FAILED ** *******************************************************************************/ static tUWA_STATUS SetCoreDeviceConfigurations() { uint8_t coreConfigsCount = 1; static const char fn[] = "SetCoreDeviceConfigurations"; UNUSED(fn); tUWA_STATUS status; uint8_t configParam[] = {0x00, 0x00, 0x00}; uint16_t config = 0; JNI_TRACE_I("%s: Enter ", fn); config = UwbConfig::getUnsigned(NAME_UWB_LOW_POWER_MODE, 0x00); JNI_TRACE_I("%s: NAME_UWB_LOW_POWER_MODE value %d ", fn, (uint8_t)config); configParam[0] = (uint8_t)config; { SyncEventGuard guard(sUwaSetConfigEvent); status = UWA_SetCoreConfig(UCI_PARAM_ID_LOW_POWER_MODE, coreConfigsCount, &configParam[0]); if (status == UWA_STATUS_OK) { sUwaSetConfigEvent.wait(UWB_CMD_TIMEOUT); JNI_TRACE_I("%s: low power mode config is success", fn); } else { JNI_TRACE_E("%s: low power mode config is failed", fn); return UWA_STATUS_FAILED; } } JNI_TRACE_I("%s: Exit ", fn); return status; } /******************************************************************************* ** ** Function: clearAllSessionContext ** ** Description: This API is invoked before Init and during DeInit to clear ** All the Session specific context. ** ** Returns: Nothing ** *******************************************************************************/ void clearAllSessionContext() { { std::unique_lock lock(sSessionMutex); sAveragedRangingData.clear(); } clearRfTestContext(); } /******************************************************************************* ** ** Function: UwbDeviceReset ** ** Description: Send Device Reset Command. ** ** Params: resetConfig: Manufacturer/Vendor Specific Reset Data ** Returns: If Success UWA_STATUS_OK else UWA_STATUS_FAILED ** *******************************************************************************/ bool UwbDeviceReset(uint8_t resetConfig) { static const char fn[] = "UwbDeviceReset"; UNUSED(fn); tUWA_STATUS status; JNI_TRACE_I("%s: Enter", fn); sIsDeviceResetDone = false; { SyncEventGuard guard(sUwaDeviceResetEvent); status = UWA_SendDeviceReset((uint8_t)resetConfig); if (status == UWA_STATUS_OK) sUwaDeviceResetEvent.wait(UWB_CMD_TIMEOUT); /* wait for callback */ } if (status == UWA_STATUS_OK) { JNI_TRACE_E("%s: Success UWA_SendDeviceReset", fn); if (sIsDeviceResetDone) { SyncEventGuard guard(sUwadeviceNtfEvent); sUwadeviceNtfEvent.wait(UWB_CMD_TIMEOUT); switch (sDeviceState) { case UWBS_STATUS_READY: { clearAllSessionContext(); JNI_TRACE_I("%s: Device Reset is success %d", fn, sDeviceState); } break; default: { JNI_TRACE_E("%s: Device state is = %d", fn, sDeviceState); } break; } } } else { JNI_TRACE_E("%s: Failed UWA_SendDeviceReset", fn); } JNI_TRACE_I("%s: Exit", fn); return sIsDeviceResetDone ? TRUE : FALSE; } /******************************************************************************* ** ** Function: uwbNativeManager_doInitialize ** ** Description: Turn on UWB. initialize the GKI module and HAL module for *UWB device. ** ** Params: env: JVM environment. ** o: Java object. ** ** Returns: True if UWB device initialization is success. ** *******************************************************************************/ jboolean uwbNativeManager_doInitialize(JNIEnv *env, jobject o) { static const char fn[] = "uwbNativeManager_doInitialize"; UNUSED(fn); tUWA_STATUS status; uint8_t resetConfig = 0; JNI_TRACE_I("%s: enter", fn); if (gIsUwaEnabled) { JNI_TRACE_I("%s: Already Initialized", fn); UwbDeviceReset(resetConfig); return JNI_TRUE; } sDeviceState = UWBS_STATUS_ERROR; UwbAdaptation &theInstance = UwbAdaptation::GetInstance(); theInstance.Initialize(); // start GKI, UCI task, UWB task tHAL_UWB_ENTRY *halFuncEntries = theInstance.GetHalEntryFuncs(); UWA_Init(halFuncEntries); clearAllSessionContext(); { SyncEventGuard guard(sUwaEnableEvent); status = UWA_Enable(uwaDeviceManagementCallback, uwaRfTestDeviceManagementCallback); if (status == UWA_STATUS_OK) sUwaEnableEvent.wait(UWB_CMD_TIMEOUT); } if (status == UWA_STATUS_OK) { if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB Enable failed", fn); goto error; } status = theInstance.CoreInitialization(); JNI_TRACE_I("%s: CoreInitialization status: %d", fn, status); if (status == UWA_STATUS_OK) { #if 1 // WA waiting binding status NTF/ SE comm error NTF #endif { /* Get Device Info */ { SyncEventGuard guard(sUwaGetDeviceInfoEvent); status = UWA_GetDeviceInfo(); if (status == UWA_STATUS_OK) { sUwaGetDeviceInfoEvent.wait(); JNI_TRACE_I("UCI Version : %x.%x", (sUwbDeviceInfo.uciVersion & 0X00FF), (sUwbDeviceInfo.uciVersion >> 8)); } } if (status == UWA_STATUS_OK) { gIsUwaEnabled = true; status = SetCoreDeviceConfigurations(); if (status == UWA_STATUS_OK) { JNI_TRACE_I("%s: SetCoreDeviceConfigurations is SUCCESS %d", fn, status); } else { JNI_TRACE_I("%s: SetCoreDeviceConfigurations is Failed %d", fn, status); goto error; } goto end; } } } } error: JNI_TRACE_E("%s: device status is failed %d", fn, sDeviceState); gIsUwaEnabled = false; status = UWA_Disable(false); /* gracefull exit */ if (status == UWA_STATUS_OK) { JNI_TRACE_I("%s: UWA_Disable(false) SUCCESS %d", fn, status); } else { JNI_TRACE_E("%s: UWA_Disable(false) is failed %d", fn, status); } theInstance.Finalize(false); // disable GKI, UCI task, UWB task end: if (gIsUwaEnabled) { sDeviceState = UWBS_STATUS_READY; } JNI_TRACE_I("%s: exit", fn); return gIsUwaEnabled ? JNI_TRUE : JNI_FALSE; } /******************************************************************************* ** ** Function: uwbNativeManager_doDeinitialize ** ** Description: Turn off UWB. Deinitilize the GKI and HAL module, power ** of the UWB device. ** Params: env: JVM environment. ** o: Java object. ** ** Returns: True if UWB device De-initialization is success. ** *******************************************************************************/ jboolean uwbNativeManager_doDeinitialize(JNIEnv *env, jobject obj) { static const char fn[] = "uwbNativeManager_doDeinitialize"; UNUSED(fn); tUWA_STATUS status; JNI_TRACE_I("%s: Enter", fn); UwbAdaptation &theInstance = UwbAdaptation::GetInstance(); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is already De-initialized", fn); return JNI_TRUE; } SyncEventGuard guard(sUwaDisableEvent); status = UWA_Disable(true); /* gracefull exit */ if (status == UWA_STATUS_OK) { JNI_TRACE_I("%s: wait for de-init completion:", fn); sUwaDisableEvent.wait(); } else { JNI_TRACE_E("%s: De-Init is failed:", fn); } clearAllSessionContext(); gIsUwaEnabled = false; theInstance.Finalize(true); // disable GKI, UCI task, UWB task JNI_TRACE_I("%s: Exit", fn); return JNI_TRUE; } /******************************************************************************* ** ** Function: uwbNativeManager_getDeviceInfo ** ** Description: retrieve the UWB device information etc. ** Params: env: JVM environment. ** o: Java object. ** ** Returns: device info class object or NULL. ** *******************************************************************************/ jobject uwbNativeManager_getDeviceInfo(JNIEnv *env, jobject obj) { static const char fn[] = "uwbNativeManager_getDeviceInfo"; UNUSED(fn); JNI_TRACE_I("%s: Enter", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return NULL; } // TODO need to change this implemenatation based on service. const char *DEVICE_DATA_CLASS_NAME = "com/android/server/uwb/UwbDeviceData"; jclass deviceDataClass = env->FindClass(DEVICE_DATA_CLASS_NAME); jmethodID constructor = env->GetMethodID(deviceDataClass, "", "(IIII)V"); // TODO to be updated based on service if (constructor == JNI_NULL) { JNI_TRACE_E("%s: jni cannot find the method deviceInfoClass", fn); return NULL; } jint uciVersion = sUwbDeviceInfo.uciVersion; jint uciTestVersion = sUwbDeviceInfo.uciTestVersion; jint macVersion = sUwbDeviceInfo.macVersion; jint phyVersion = sUwbDeviceInfo.phyVersion; JNI_TRACE_I("%s: Exit", fn); return env->NewObject(deviceDataClass, constructor, uciVersion, macVersion, phyVersion, uciTestVersion); } /******************************************************************************* ** ** Function: uwbNativeManager_getSpecificationInfo ** ** Description: retrieve the UWB device specific information etc. ** Params: env: JVM environment. ** o: Java object. ** ** Returns: device info class object or NULL. ** *******************************************************************************/ jobject uwbNativeManager_getSpecificationInfo(JNIEnv *env, jobject obj) { static const char fn[] = "uwbNativeManager_getSpecificationInfo"; UNUSED(fn); JNI_TRACE_I("%s: Enter", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return NULL; } const char *DEVICE_DATA_CLASS_NAME = "com/android/server/uwb/info/UwbSpecificationInfo"; jclass deviceDataClass = env->FindClass(DEVICE_DATA_CLASS_NAME); jmethodID constructor = env->GetMethodID(deviceDataClass, "", "(IIIIIIIIIIIIIIII)V"); if (constructor == JNI_NULL) { JNI_TRACE_E("%s: jni cannot find the method deviceInfoClass", fn); return NULL; } jint uciMajor = (sUwbDeviceInfo.uciVersion & MSB_BITMASK); jint uciMaintenance = (sUwbDeviceInfo.uciVersion >> 8) & 0x0F; jint uciMinor = (sUwbDeviceInfo.uciVersion >> 12) & 0x0F; jint macMajor = (sUwbDeviceInfo.macVersion & MSB_BITMASK); jint macMaintenance = (sUwbDeviceInfo.macVersion >> 8) & 0x0F; jint macMinor = (sUwbDeviceInfo.macVersion >> 12) & 0x0F; jint phyMajor = (sUwbDeviceInfo.phyVersion & MSB_BITMASK); jint phyMaintenance = (sUwbDeviceInfo.phyVersion >> 8) & 0x0F; jint phyMinor = (sUwbDeviceInfo.phyVersion >> 12) & 0x0F; jint uciTestMajor = (sUwbDeviceInfo.uciTestVersion) & MSB_BITMASK; jint uciTestMaintenance = (sUwbDeviceInfo.uciTestVersion >> 8) & 0x0F; jint uciTestMinor = (sUwbDeviceInfo.uciTestVersion >> 12) & 0x0F; JNI_TRACE_I("%s: Exit", fn); return env->NewObject(deviceDataClass, constructor, uciMajor, uciMaintenance, uciMinor, macMajor, macMaintenance, macMinor, phyMajor, phyMaintenance, phyMinor, uciTestMajor, uciTestMaintenance, uciTestMinor, 1 /* firaMajorVersion */, 0 /* firaMinorVersion */, 1 /* cccMajorVersion */, 0 /* cccMinorVersion*/); } /******************************************************************************* ** ** Function: uwbNativeManager_getUwbDeviceState ** ** Description: Retrieve the UWB device state.. ** ** Params : env: JVM environment. ** o: Java object. ** ** Returns: device state. ** *******************************************************************************/ jint uwbNativeManager_getUwbDeviceState(JNIEnv *env, jobject obj) { static const char fn[] = "uwbNativeManager_getUwbDeviceState"; UNUSED(fn); eUWBS_DEVICE_STATUS_t sDeviceState = UWBS_STATUS_ERROR; JNI_TRACE_I("%s: Enter", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return sDeviceState; } tUWA_PMID configParam[] = {UCI_PARAM_ID_DEVICE_STATE}; SyncEventGuard guard(sUwaGetConfigEvent); tUWA_STATUS status = UWA_GetCoreConfig(sizeof(configParam), configParam); if (status == UWA_STATUS_OK) { sUwaGetConfigEvent.wait(UWB_CMD_TIMEOUT); if (sGetCoreConfigLen > 0) { if (sGetCoreConfig[0] == UCI_PARAM_ID_DEVICE_STATE) { sDeviceState = (eUWBS_DEVICE_STATUS_t)sGetCoreConfig[2]; } } } JNI_TRACE_I("%s: Exit", fn); return sDeviceState; } /******************************************************************************* ** ** Function: uwbNativeManager_deviceReset ** ** Description: Send Device Reset Command. ** ** Params: env: JVM environment. ** obj: Java object. ** resetConfig: Manufacturer/Vendor Specific Reset Data ** ** Returns: If Success UWA_STATUS_OK else UWA_STATUS_FAILED ** *******************************************************************************/ jbyte uwbNativeManager_deviceReset(JNIEnv *env, jobject obj, jbyte resetConfig) { static const char fn[] = "uwbNativeManager_deviceReset"; UNUSED(fn); bool status; JNI_TRACE_I("%s: Enter", fn); // WA: commented reset functionality as this wiill trigger ESE communication // and Helios will send binding status NTF again // if Helos is turned off without reading response from ESE, then this makes // ESE unresponsive sitiation // Sending reset command as part of MW enable every time to reset both Helios // and SUS applet from ESE status = true; // true always #if 0 if(!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return UWA_STATUS_FAILED; } status = UwbDeviceReset((uint8_t)resetConfig); #endif JNI_TRACE_I("%s: Exit", fn); return status ? UWA_STATUS_OK : UWA_STATUS_FAILED; } /******************************************************************************* ** ** Function: uwbNativeManager_sessionInit ** ** Description: Initialize the session for the particular activity. ** ** Params: env: JVM environment. ** o: Java object. ** ** Returns: If Success UWA_STATUS_OK else UWA_STATUS_FAILED ** *******************************************************************************/ jbyte uwbNativeManager_sessionInit(JNIEnv *env, jobject o, jint sessionId, jbyte sessionType) { static const char fn[] = "uwbNativeManager_sessionInit"; UNUSED(fn); tUWA_STATUS status = UWA_STATUS_FAILED; JNI_TRACE_I("%s: Enter", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return status; } sSessionInitStatus = false; SyncEventGuard guard(sUwaSessionInitEvent); status = UWA_SendSessionInit(sessionId, sessionType); if (UWA_STATUS_OK == status) { sUwaSessionInitEvent.wait(UWB_CMD_TIMEOUT); } else { JNI_TRACE_E("%s: Session Init command is failed", fn); } JNI_TRACE_I("%s: Exit", fn); return (sSessionInitStatus) ? UWA_STATUS_OK : UWA_STATUS_FAILED; } /******************************************************************************* ** ** Function: uwbNativeManager_sessionDeInit ** ** Description: This API is invoked from the application to DeInitialize ** Session Specific context. ** ** Params: env: JVM environment. ** o: Java object. ** ** Returns: If Success UWA_STATUS_OK else UWA_STATUS_FAILED ** *******************************************************************************/ jbyte uwbNativeManager_sessionDeInit(JNIEnv *env, jobject o, jint sessionId) { static const char fn[] = "uwbNativeManager_sessionDeInit"; UNUSED(fn); tUWA_STATUS status = UWA_STATUS_FAILED; JNI_TRACE_I("%s: Enter", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return status; } sSessionDeInitStatus = false; SyncEventGuard guard(sUwaSessionDeInitEvent); status = UWA_SendSessionDeInit(sessionId); if (UWA_STATUS_OK == status) { sUwaSessionDeInitEvent.wait(UWB_CMD_TIMEOUT); } else { JNI_TRACE_E("%s: Session DeInit command is failed", fn); } JNI_TRACE_I("%s: Exit", fn); return (sSessionDeInitStatus) ? UWA_STATUS_OK : UWA_STATUS_FAILED; } /******************************************************************************* ** ** Function: uwbNativeManager_setAppConfigurations() ** ** Description: Invoked this API to set the session specific Application ** Configuration. ** ** Params: env: JVM environment. ** o: Java object. ** sessionId: All APP configurations belonging to this Session *ID ** noOfParams : The number of APP Configuration fields to *follow ** appConfigLen : Length of AppConfigData ** AppConfig : App Configurations for session ** ** Returns: Returns byte array ** *******************************************************************************/ jobject uwbNativeManager_setAppConfigurations(JNIEnv *env, jobject o, jint sessionId, jint noOfParams, jint appConfigLen, jbyteArray AppConfig) { static const char fn[] = "uwbNativeManager_setAppConfigurations"; UNUSED(fn); uint8_t *appConfigData = NULL; tUWA_STATUS status = UWA_STATUS_FAILED; JNI_TRACE_I("%s: Enter", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return NULL; } appConfigData = (uint8_t *)malloc(sizeof(uint8_t) * appConfigLen); if (appConfigData != NULL) { memset(appConfigData, 0, (sizeof(uint8_t) * appConfigLen)); env->GetByteArrayRegion(AppConfig, 0, appConfigLen, (jbyte *)appConfigData); JNI_TRACE_I("%d: appConfigLen", appConfigLen); status = setAppConfiguration(sessionId, noOfParams, appConfigLen, appConfigData); free(appConfigData); if (sSetAppConfigRespStatus) { const char *UWB_CONFIG_STATUS_DATA = "com/android/server/uwb/data/UwbConfigStatusData"; jclass configStatusDataClass = env->FindClass(UWB_CONFIG_STATUS_DATA); jmethodID constructor = env->GetMethodID(configStatusDataClass, "", "(II[B)V"); if (constructor == JNI_NULL) { JNI_TRACE_E("%s: jni cannot find the method for UwbTlvDATA", fn); return NULL; } jbyteArray appConfigArray = env->NewByteArray(sSetAppConfigLen); env->SetByteArrayRegion(appConfigArray, 0, sSetAppConfigLen, (jbyte *)&sSetAppConfig[0]); return env->NewObject(configStatusDataClass, constructor, sSetAppConfigStatus, sNoOfAppConfigIds, appConfigArray); } else { JNI_TRACE_E("%s: Failed setAppConfigurations, Status = %d", fn, sSetAppConfigRespStatus); } } else { JNI_TRACE_E("%s: Unable to Allocate Memory", fn); } JNI_TRACE_I("%s: Exit", fn); return NULL; } /******************************************************************************* ** ** Function: uwbNativeManager_sendRawUci() ** ** Description: Invoked this API to send raw uci cmds ** ** Params: env: JVM environment. ** o: Java object. ** rawUci: Uci data to send to controller ** cmdLen: uci data lentgh ** ** Returns: Returns byte array for raw uci rsp ** *******************************************************************************/ jobject uwbNativeManager_sendRawUci(JNIEnv *env, jobject o, jint gid, jint oid, jbyteArray rawUci) { static const char fn[] = "uwbNativeManager_sendRawUci"; UNUSED(fn); JNI_TRACE_I("%s: enter; ", fn); uint8_t *cmd = NULL; tUWA_STATUS status = UWA_STATUS_FAILED; jint cmdLen = env->GetArrayLength(rawUci); if (cmdLen > UCI_MAX_PAYLOAD_SIZE) { JNI_TRACE_E("%s: CmdLen %d is beyond max allowed range %d", fn, cmdLen, UCI_MAX_PAYLOAD_SIZE); return NULL; } if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return NULL; } cmd = (uint8_t *)malloc(sizeof(uint8_t) * cmdLen); if (cmd == NULL) { JNI_TRACE_E("%s: malloc failure for raw cmd", __func__); return NULL; } memset(cmd, 0, (sizeof(uint8_t) * cmdLen)); env->GetByteArrayRegion(rawUci, 0, cmdLen, (jbyte *)cmd); status = sendRawUci(gid, oid, cmd, cmdLen); free(cmd); const char *UWB_VENDOR_RES_DATA = "com/android/server/uwb/data/UwbVendorUciResponse"; jclass resDataClass = env->FindClass(UWB_VENDOR_RES_DATA); jmethodID constructor = env->GetMethodID(resDataClass, "", "(BII[B)V"); if (constructor == JNI_NULL) { JNI_TRACE_E("%s: jni cannot find the method for UwbTlvDATA", fn); return NULL; } JNI_TRACE_I("%s: exit sendRawUCi= 0x%x", __func__, status); if (status == UWA_STATUS_OK) { jbyteArray rawResArray = env->NewByteArray(sSendRawResLen); env->SetByteArrayRegion(rawResArray, 0, sSendRawResLen, (jbyte *)&sSendRawResData[0]); return env->NewObject(resDataClass, constructor, status, gid, oid, rawResArray); } else { return env->NewObject(resDataClass, constructor, status, gid, oid, NULL); } } /******************************************************************************* ** ** Function: uwbNativeManager_getAppConfigurations ** ** Description: retrieve the session specific App Configs ** ** Params: env: JVM environment. ** o: Java object. ** session id : Session Id for the given set of App params ** noOfParams: Number of Params ** appConfigLen: Total App config Lentgh ** AppConfig: App Config List to retrieve ** ** Returns: Returns byte array ** *******************************************************************************/ jobject uwbNativeManager_getAppConfigurations(JNIEnv *env, jobject o, jint sessionId, jint noOfParams, jint appConfigLen, jbyteArray AppConfig) { static const char fn[] = "uwbNativeManager_getAppConfigurations"; UNUSED(fn); tUWA_STATUS status; uint8_t *appConfigData = NULL; JNI_TRACE_I("%s: Enter", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return NULL; } sGetAppConfigRespStatus = false; appConfigData = (uint8_t *)malloc(sizeof(uint8_t) * appConfigLen); if (appConfigData != NULL) { memset(appConfigData, 0, (sizeof(uint8_t) * appConfigLen)); env->GetByteArrayRegion(AppConfig, 0, appConfigLen, (jbyte *)appConfigData); SyncEventGuard guard(sUwaGetAppConfigEvent); status = UWA_GetAppConfig(sessionId, noOfParams, appConfigLen, appConfigData); free(appConfigData); if (status == UWA_STATUS_OK) { sUwaGetAppConfigEvent.wait(UWB_CMD_TIMEOUT); if (sGetAppConfigRespStatus) { const char *UWB_TLV_DATA = "com/android/server/uwb/data/UwbTlvData"; jclass tlvDataClass = env->FindClass(UWB_TLV_DATA); jmethodID constructor = env->GetMethodID(tlvDataClass, "", "(II[B)V"); if (constructor == JNI_NULL) { JNI_TRACE_E("%s: jni cannot find the method for UwbTlvDATA", fn); return NULL; } jbyteArray appConfigArray = env->NewByteArray(sGetAppConfigLen); env->SetByteArrayRegion(appConfigArray, 0, sGetAppConfigLen, (jbyte *)&sGetAppConfig[0]); return env->NewObject(tlvDataClass, constructor, sGetAppConfigStatus, sNoOfAppConfigIds, appConfigArray); } else { JNI_TRACE_E("%s: Failed getAppConfigurations, Status = %d", fn, sGetAppConfigRespStatus); } } else { JNI_TRACE_E("%s: Failed UWA_GetAppConfig", fn); } } else { JNI_TRACE_E("%s: Unable to Allocate Memory", fn); } JNI_TRACE_I("%s: Exit", fn); return NULL; } /******************************************************************************* ** ** Function: uwbNativeManager_startRanging ** ** Description: start the ranging session with required configs and notify ** the peer device information. ** ** Params: env: JVM environment. ** o: Java object. ** sessionId : Session ID for which ranging shall start ** ** Returns: If Success UWA_STATUS_OK else UWA_STATUS_FAILED ** *******************************************************************************/ jbyte uwbNativeManager_startRanging(JNIEnv *env, jobject obj, jint sessionId) { static const char fn[] = "uwbNativeManager_startRanging"; UNUSED(fn); tUWA_STATUS status = UWA_STATUS_FAILED; JNI_TRACE_I("%s: enter", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not enabled", fn); return status; } sRangeStartStatus = false; SyncEventGuard guard(sUwaRngStartEvent); status = UWA_StartRangingSession(sessionId); if (status == UWA_STATUS_OK) { sUwaRngStartEvent.wait(UWB_CMD_TIMEOUT); } JNI_TRACE_I("%s: exit", fn); return (sRangeStartStatus) ? UWA_STATUS_OK : UWA_STATUS_FAILED; } /******************************************************************************* ** ** Function: uwbNativeManager_stopRanging ** ** Description: stop the ranging session. ** ** Params: env: JVM environment. ** o: Java object. ** sessionId : Session ID for which ranging shall start ** ** Returns: UWA_STATUS_OK if ranging session stop is success. ** *******************************************************************************/ jbyte uwbNativeManager_stopRanging(JNIEnv *env, jobject obj, jint sessionId) { static const char fn[] = "uwbNativeManager_stopRanging"; UNUSED(fn); tUWA_STATUS status = UWA_STATUS_FAILED; JNI_TRACE_I("%s: enter", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not enabled", fn); return status; } sRangeStopStatus = false; SyncEventGuard guard(sUwaRngStopEvent); status = UWA_StopRangingSession(sessionId); if (status == UWA_STATUS_OK) { sUwaRngStopEvent.wait(UWB_CMD_TIMEOUT); } else { JNI_TRACE_E("%s: Stop ranging is failed error:%x:", fn, status); } JNI_TRACE_I("%s: exit", fn); return (sRangeStopStatus) ? UWA_STATUS_OK : UWA_STATUS_FAILED; } /******************************************************************************* ** ** Function: uwbNativeManager_getSessionCount ** ** Description: Get session count. ** ** Params: env: JVM environment. ** o: Java object. ** ** Returns: session count on success ** *******************************************************************************/ jbyte uwbNativeManager_getSessionCount(JNIEnv *env, jobject obj) { static const char fn[] = "uwbNativeManager_getSessionCount"; UNUSED(fn); tUWA_STATUS status; sSessionCount = -1; JNI_TRACE_I("%s: Enter", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return sSessionCount; } SyncEventGuard guard(sUwaGetSessionCountEvent); status = UWA_GetSessionCount(); if (UWA_STATUS_OK == status) { sUwaGetSessionCountEvent.wait(UWB_CMD_TIMEOUT); } else { JNI_TRACE_E("%s: get session count command is failed", fn); } JNI_TRACE_I("%s: Exit", fn); return sSessionCount; } jint uwbNativeManager_getMaxSessionNumber(JNIEnv *env, jobject obj) { static const char fn[] = "uwbNativeManager_getMaxSessionNumber"; UNUSED(fn); return 5; } jbyte uwbNativeManager_resetDevice(JNIEnv *env, jbyte resetConfig) { static const char fn[] = "uwbNativeManager_resetDevice"; UNUSED(fn); return UWA_STATUS_OK; } /******************************************************************************* ** ** Function: uwbNativeManager_getSessionState ** ** Description: get the current session status for the given session id ** ** Params: env: JVM environment. ** o: Java object. ** sessionId : Session ID for which to get the session status ** ** Returns: current session status if UWb_STATUS_OK else returns ** UWA_STATUS_FAILED. ** *******************************************************************************/ jbyte uwbNativeManager_getSessionState(JNIEnv *env, jobject obj, jint sessionId) { static const char fn[] = "uwbNativeManager_getSessionState"; UNUSED(fn); tUWA_STATUS status; JNI_TRACE_I("%s: enter", fn); sSessionState = UWB_UNKNOWN_SESSION; if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not enabled", fn); return sSessionState; } SyncEventGuard guard(sUwaGetSessionStatusEvent); status = UWA_GetSessionStatus(sessionId); if (status == UWA_STATUS_OK) { sUwaGetSessionStatusEvent.wait(UWB_CMD_TIMEOUT); } JNI_TRACE_I("%s: exit", fn); return sSessionState; } /******************************************************************************* ** ** Function: uwbNativeManager_ControllerMulticastListUpdate() ** ** Description: API to set Controller Multicast List Update ** ** Params: env: JVM environment. ** o: Java object. ** sessionId: Session Id to which update the list ** action: Required Action to be taken ** noOfControlees: Number of Responders ** shortAddressList: Short Address list for each responder ** subSessionIdList: Sub session Id list of each responder ** ** Returns: UFA_STATUS_OK on success or UFA_STATUS_FAILED on failure ** *******************************************************************************/ jbyte uwbNativeManager_ControllerMulticastListUpdate( JNIEnv *env, jobject o, jint sessionId, jbyte action, jbyte noOfControlees, jshortArray shortAddressList, jintArray subSessionIdList) { static const char fn[] = "uwbNativeManager_ControllerMulticastListUpdate"; UNUSED(fn); tUWA_STATUS status = UWA_STATUS_FAILED; uint16_t *shortAddressArray = NULL; uint32_t *subSessionIdArray = NULL; JNI_TRACE_E("%s: enter; ", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return status; } if ((shortAddressList == NULL) || (subSessionIdList == NULL)) { JNI_TRACE_E("%s: subSessionIdList or shortAddressList value is NULL", fn); return status; } uint8_t shortAddressLen = env->GetArrayLength(shortAddressList); uint8_t subSessionIdLen = env->GetArrayLength(subSessionIdList); if (noOfControlees > MAX_NUM_CONTROLLEES) { JNI_TRACE_E("%s: no Of Controlees %d exceeded than %d ", fn, shortAddressLen, MAX_NUM_CONTROLLEES); return status; } if ((shortAddressLen > 0) && (subSessionIdLen > 0)) { shortAddressArray = (uint16_t *)malloc(shortAddressLen); if (shortAddressArray == NULL) { JNI_TRACE_E("%s: malloc failure for shortAddressArray", fn); return status; } memset(shortAddressArray, 0, shortAddressLen); env->GetShortArrayRegion(shortAddressList, 0, shortAddressLen, (jshort *)shortAddressArray); subSessionIdArray = (uint32_t *)malloc(SESSION_ID_LEN * subSessionIdLen); if (subSessionIdArray == NULL) { free(shortAddressArray); JNI_TRACE_E("%s: malloc failure for subSessionIdArray", fn); return status; } memset(subSessionIdArray, 0, (SESSION_ID_LEN * subSessionIdLen)); env->GetIntArrayRegion(subSessionIdList, 0, subSessionIdLen, (jint *)subSessionIdArray); sMulticastListUpdateStatus = false; SyncEventGuard guard(sUwaMulticastListUpdateEvent); status = UWA_ControllerMulticastListUpdate( sessionId, action, noOfControlees, shortAddressArray, subSessionIdArray); if (status == UWA_STATUS_OK) { sUwaMulticastListUpdateEvent.wait(UWB_CMD_TIMEOUT); } free(shortAddressArray); free(subSessionIdArray); } else { JNI_TRACE_E("%s: controleeListArray length is not valid", fn); } JNI_TRACE_I("%s: exit", fn); return (sMulticastListUpdateStatus) ? UWA_STATUS_OK : UWA_STATUS_FAILED; } /******************************************************************************* ** ** Function: uwbNativeManager_SetCountryCode() ** ** Description: API to set country code ** ** Params: env: JVM environment. ** o: Java object. ** countryCode: ISO country code ** ** Returns: UFA_STATUS_OK on success or UFA_STATUS_FAILED on failure ** *******************************************************************************/ jbyte uwbNativeManager_SetCountryCode(JNIEnv *env, jobject o, jbyteArray countryCode) { static const char fn[] = "uwbNativeManager_SetCountryCode"; tUWA_STATUS status = UWA_STATUS_FAILED; uint8_t *countryCodeArray = NULL; JNI_TRACE_E("%s: enter; ", fn); if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", fn); return status; } if (countryCode == NULL) { JNI_TRACE_E("%s: country code value is NULL", fn); return status; } uint8_t countryCodeArrayLen = env->GetArrayLength(countryCode); if (countryCodeArrayLen != 2) { JNI_TRACE_E("%s: Malformed country code arraylen %d", fn, countryCodeArrayLen); return status; } countryCodeArray = (uint8_t *)malloc(countryCodeArrayLen); if (countryCodeArray == NULL) { JNI_TRACE_E("%s: malloc failure for countryCodeArray", fn); return status; } memset(countryCodeArray, 0, countryCodeArrayLen); env->GetByteArrayRegion(countryCode, 0, countryCodeArrayLen, (jbyte *)countryCodeArray); sSetCountryCodeStatus = false; SyncEventGuard guard(sUwaSetCountryCodeEvent); status = UWA_ControllerSetCountryCode(countryCodeArray); if (status == UWA_STATUS_OK) { sUwaSetCountryCodeEvent.wait(UWB_CMD_TIMEOUT); } free(countryCodeArray); JNI_TRACE_I("%s: exit", fn); return (sSetCountryCodeStatus) ? UWA_STATUS_OK : UWA_STATUS_FAILED; } /******************************************************************************* ** ** Function: uwbNativeManager_init ** ** Description: Initialize variables. ** ** Params env: JVM environment. ** o: Java object. ** ** Returns: True if ok. ** *******************************************************************************/ jboolean uwbNativeManager_init(JNIEnv *env, jobject o) { uwbEventManager.doLoadSymbols(env, o); return JNI_TRUE; } /******************************************************************************* ** ** Function: uwbNativeManager_enableConformanceTest ** ** Description: Enable or disable MCTT mode of operation. ** ** Params: env: JVM environment. ** o: Java object. ** enable: enable/disable MCTT mode ** ********************************************************************************/ jbyte uwbNativeManager_enableConformanceTest(JNIEnv *env, jobject o, jboolean enable) { static const char fn[] = "uwbNativeManager_enableConformanceTest"; UNUSED(fn); JNI_TRACE_I("%s: enter", fn); tUWA_STATUS status = UWA_STATUS_FAILED; if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not enabled", fn); return status; } UWB_EnableConformanceTest(enable); JNI_TRACE_I("%s: exit", fn); return UWA_STATUS_OK; } /******************************************************************************* ** ** Function: uwbNativeManager_GetDeviceCapebilityParams() ** ** Description: Invoked this API to get the device capability information. ** ** Params: env: JVM environment. ** o: Java object. ** ** Returns: Returns byte array ** *******************************************************************************/ jobject uwbNativeManager_GetDeviceCapebilityParams(JNIEnv* env, jobject o) { JNI_TRACE_I("%s: Entry", __func__); tUWA_STATUS status; if (!gIsUwaEnabled) { JNI_TRACE_E("%s: UWB device is not initialized", __func__); return NULL; } sGetDeviceCapsRespStatus = false; SyncEventGuard guard(sUwaGetDeviceCapsEvent); status = UWA_GetCoreGetDeviceCapability(); if (status == UWA_STATUS_OK) { JNI_TRACE_D("%s: Success UWA_GetCoreGetDeviceCapability", __func__); sUwaGetDeviceCapsEvent.wait(UWB_CMD_TIMEOUT); } else { JNI_TRACE_E("%s: Failed UWA_GetCoreGetDeviceCapability", __func__); return NULL; } if (!sGetDeviceCapsRespStatus) { JNI_TRACE_E("%s: Failed getDeviceCapabilityInfo, Status = %d", __func__, sGetDeviceCapsRespStatus); return NULL; } const char *UWB_TLV_DATA = "com/android/server/uwb/data/UwbTlvData"; jclass tlvDataClass = env->FindClass(UWB_TLV_DATA); jmethodID constructor = env->GetMethodID(tlvDataClass, "", "(II[B)V"); if (constructor == JNI_NULL) { JNI_TRACE_E("%s: jni cannot find the method for UwbTlvDATA", __func__); return NULL; } //remove vendor ext parameters uint8_t sUwbDeviceCapaInfos[UCI_MAX_PKT_SIZE]; uint16_t capLen = 0; for( uint16_t index= 0;index< sDevCapInfoLen;) { if (sUwbDeviceCapability[index] == 0xE0 ) { //Ext id switch (sUwbDeviceCapability[index+1]) { //Ext sub id case 0x00: case 0x01: case 0x02: int lenofParam = sUwbDeviceCapability[index+2]; //Get the length of Ext paramaeter index = index + (lenofParam+3); // increament index by (Ext id+ Ext sub id + length of ext param + velue of param) sDevCapInfoIds--; break; } } else { sUwbDeviceCapaInfos[capLen++] = sUwbDeviceCapability[index]; index++; } } jbyteArray deviceCapabilityInfo = env->NewByteArray(capLen); env->SetByteArrayRegion(deviceCapabilityInfo, 0, capLen, (jbyte*)&sUwbDeviceCapaInfos[0]); JNI_TRACE_I("%s: Exit", __func__); return env->NewObject(tlvDataClass, constructor, status, sDevCapInfoIds, deviceCapabilityInfo); } /***************************************************************************** ** ** JNI functions for android ** UWB service layer has to invoke these APIs to get required functionality ** *****************************************************************************/ static JNINativeMethod gMethods[] = { {"nativeInit", "()Z", (void *)uwbNativeManager_init}, {"nativeDoInitialize", "()Z", (void *)uwbNativeManager_doInitialize}, {"nativeDoDeinitialize", "()Z", (void *)uwbNativeManager_doDeinitialize}, {"nativeSessionInit", "(IB)B", (void *)uwbNativeManager_sessionInit}, {"nativeSessionDeInit", "(I)B", (void *)uwbNativeManager_sessionDeInit}, {"nativeSetAppConfigurations", "(III[B)Lcom/android/server/uwb/data/UwbConfigStatusData;", (void *)uwbNativeManager_setAppConfigurations}, {"nativeGetAppConfigurations", "(III[B)Lcom/android/server/uwb/data/UwbTlvData;", (void *)uwbNativeManager_getAppConfigurations}, {"nativeRangingStart", "(I)B", (void *)uwbNativeManager_startRanging}, {"nativeRangingStop", "(I)B", (void *)uwbNativeManager_stopRanging}, {"nativeGetSessionCount", "()B", (void *)uwbNativeManager_getSessionCount}, {"nativeGetSessionState", "(I)B", (void *)uwbNativeManager_getSessionState}, {"nativeControllerMulticastListUpdate", "(IBB[S[I)B", (void *)uwbNativeManager_ControllerMulticastListUpdate}, {"nativeSetCountryCode", "([B)B", (void *)uwbNativeManager_SetCountryCode}, {"nativeSendRawVendorCmd", "(II[B)Lcom/android/server/uwb/data/UwbVendorUciResponse;", (void*)uwbNativeManager_sendRawUci}, {"nativeEnableConformanceTest", "(Z)B", (void*)uwbNativeManager_enableConformanceTest}, {"nativeGetMaxSessionNumber", "()I", (void *)uwbNativeManager_getMaxSessionNumber}, {"nativeResetDevice", "(B)B", (void *)uwbNativeManager_resetDevice}, {"nativeGetSpecificationInfo", "()Lcom/android/server/uwb/info/UwbSpecificationInfo;", (void *)uwbNativeManager_getSpecificationInfo}, {"nativeGetCapsInfo", "()Lcom/android/server/uwb/data/UwbTlvData;", (void*)uwbNativeManager_GetDeviceCapebilityParams} }; /******************************************************************************* ** ** Function: register_UwbNativeManager ** ** Description: Regisgter JNI functions of UwbEventManager class with Java *Virtual Machine. ** ** Params: env: Environment of JVM. ** ** Returns: Status of registration (JNI version). ** *******************************************************************************/ int register_com_android_uwb_dhimpl_UwbNativeManager(JNIEnv *env) { static const char fn[] = "register_com_android_uwb_dhimpl_UwbNativeManager"; UNUSED(fn); JNI_TRACE_I("%s: enter", fn); return jniRegisterNativeMethods(env, UWB_NATIVE_MANAGER_CLASS_NAME, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); } } // namespace android