blob: bff5b858a9db3713991ae264d7b5e8e6067ba67b [file] [log] [blame]
//! jni for uwb native stack
use jni::JNIEnv;
use jni::objects::{JObject, JValue};
use jni::sys::{jboolean, jbyte, jbyteArray, jint, jintArray, jlong, jobject};
use log::{error, info, warn};
use uwb_uci_rust::event_manager::EventManager;
use uwb_uci_rust::error::UwbErr;
use uwb_uci_rust::uci::{BlockingJNICommand, Dispatcher, JNICommand, uci_hrcv::UciResponse};
use uwb_uci_packets::StatusCode;
const STATUS_OK: i8 = 0;
const STATUS_FAILED: i8 = 2;
/// Initialize UWB
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeInit(_env: JNIEnv, _obj: JObject) -> jboolean {
logger::init(
logger::Config::default().with_tag_on_device("uwb").with_min_level(log::Level::Trace),
);
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeInit: enter");
true as jboolean
}
/// Get max session number
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeGetMaxSessionNumber(_env: JNIEnv, _obj: JObject) -> jint {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeGetMaxSessionNumber: enter");
5
}
/// Turn on UWB. initialize the GKI module and HAL module for UWB device.
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeDoInitialize(env: JNIEnv, obj: JObject) -> jboolean {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeDoInitialize: enter");
boolean_result_helper(do_initialize(env, obj), "DoInitialize")
}
/// Turn off UWB. Deinitilize the GKI and HAL module, power of the UWB device.
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeDoDeinitialize(env: JNIEnv, obj: JObject) -> jboolean {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeDoDeinitialize: enter");
boolean_result_helper(do_deinitialize(env, obj), "DoDeinitialize")
}
/// get nanos
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos(_env: JNIEnv, _obj: JObject) -> jlong {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos: enter");
0
}
/// retrieve the UWB device specific information etc.
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeGetSpecificationInfo(env: JNIEnv, _obj: JObject) -> jobject {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeGetSpecificationInfo: enter");
// TODO: implement this function
let uwb_specification_info_class = env.find_class("com/android/uwb/info/UwbSpecificationInfo").unwrap();
let specification_info = env.new_object(uwb_specification_info_class, "(IIIIIIIIIIII)V", &[JValue::Int(1); 12]).unwrap();
*specification_info
}
/// reset the device
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeResetDevice(_env: JNIEnv, _obj: JObject, _reset_config: jbyte) -> jbyte {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeResetDevice: enter");
// TODO: implement this function
0
}
/// init the session
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeSessionInit(env: JNIEnv, obj: JObject, session_id: jint, session_type: jbyte) -> jbyte {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeSessionInit: enter");
byte_result_helper(session_init(env, obj, session_id as u32, session_type as u8), "SessionInit")
}
/// deinit the session
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeSessionDeInit(env: JNIEnv, obj: JObject, session_id: jint) -> jbyte {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeSessionDeInit: enter");
byte_result_helper(session_deinit(env, obj, session_id as u32), "SessionDeInit")
}
/// get session count
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeGetSessionCount(env: JNIEnv, obj: JObject) -> jbyte {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeGetSessionCount: enter");
byte_result_helper(get_session_count(env, obj), "GetSessionCount")
}
/// start the ranging
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeRangingStart(env: JNIEnv, obj: JObject, session_id: jint) -> jbyte {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeRangingStart: enter");
byte_result_helper(ranging_start(env, obj, session_id as u32), "RangingStart")
}
/// stop the ranging
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeRangingStop(env: JNIEnv, obj: JObject, session_id: jint) -> jbyte {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeRangingStop: enter");
byte_result_helper(ranging_stop(env, obj, session_id as u32), "RangingStop")
}
/// get the session state
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeGetSessionState(env: JNIEnv, obj: JObject, session_id: jint) -> jbyte {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeGetSessionState: enter");
byte_result_helper(get_session_state(env, obj, session_id as u32), "GetSessionState")
}
/// set app configurations
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeSetAppConfigurations(env: JNIEnv, _obj: JObject, _session_id: jint, _no_of_params: jint, _app_config_param_len: jint, _app_config_params: jbyteArray) -> jbyteArray {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeSetAppConfigurations: enter");
// TODO: implement this function
let buf = [1; 10];
env.byte_array_from_slice(&buf).unwrap()
}
/// get app configurations
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeGetAppConfigurations(env: JNIEnv, _obj: JObject, _session_id: jint, _no_of_params: jint, _app_config_param_len: jint, _app_config_params: jbyteArray) -> jbyteArray {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeGetAppConfigurations: enter");
// TODO: implement this function
let buf = [1; 10];
env.byte_array_from_slice(&buf).unwrap()
}
/// update multicast list
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate(env: JNIEnv, obj: JObject, session_id: jint, action: jbyte, no_of_controlee: jbyte, address: jbyteArray, sub_session_id: jintArray) -> jbyte {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate: enter");
byte_result_helper(multicast_list_update(env, obj, session_id as u32, action as u8, no_of_controlee as u8, address, &sub_session_id), "ControllerMulticastListUpdate")
}
/// set country code
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeSetCountryCode(env: JNIEnv, obj: JObject, country_code: jbyteArray) -> jbyte {
info!("Java_com_android_uwb_jni_NativeUwbManager_nativeSetCountryCode: enter");
byte_result_helper(set_country_code(env, obj, country_code), "SetCountryCode")
}
fn boolean_result_helper(result: Result<(), UwbErr>, function_name: &str) -> jboolean {
match result {
Ok(()) => true as jboolean,
Err(err) => {
error!("{} failed with: {:?}", function_name, err);
false as jboolean
}
}
}
fn byte_result_helper(result: Result<(), UwbErr>, function_name: &str) -> jbyte {
match result {
Ok(()) => STATUS_OK,
Err(err) => {
error!("{} failed with: {:?}", function_name, err);
STATUS_FAILED
}
}
}
fn do_initialize(env: JNIEnv, obj: JObject) -> Result<(), UwbErr> {
dispatch_command(env, obj, JNICommand::UwaEnable)?;
uwa_init(); // todo: implement this
clear_all_session_context(); // todo: implement this
uwa_enable()?; // todo: implement this, and add a lock here
match uwa_get_device_info(env, obj) {
Ok(device_info) => info!("Get the device info: {:?}", device_info),
Err(e) => {
warn!("Failed to get device info with: {:?}", e);
return Err(UwbErr::failed());
},
}
match set_core_device_configurations() {
Ok(()) => {
info!("set_core_device_configurations is success");
return Ok(());
},
_ => info!("set_core_device_configurations is failed"),
};
match uwa_disable(false) {
Ok(()) => info!("UWA_disable(false) success."),
_ => warn!("UWA_disable(false) is failed."),
};
Err(UwbErr::failed())
}
fn do_deinitialize(env: JNIEnv, obj: JObject) -> Result<(), UwbErr> {
let dispatcher = get_dispatcher(env, obj)?;
dispatcher.send_jni_command(JNICommand::UwaDisable(true))?;
dispatcher.send_jni_command(JNICommand::Exit)?;
Ok(())
}
fn session_init(env: JNIEnv, obj: JObject, session_id: u32, session_type: u8) -> Result<(), UwbErr> {
let dispatcher = get_dispatcher(env, obj)?;
let res = match dispatcher.block_on_jni_command(BlockingJNICommand::UwaSessionInit(session_id, session_type))? {
UciResponse::SessionInitRsp(data) => data,
_ => return Err(UwbErr::failed()),
};
info!("session_init_response: {:?}", res);
match res.status {
StatusCode::UciStatusOk => Ok(()),
_ => Err(UwbErr::failed()),
}
}
fn session_deinit(env: JNIEnv, obj: JObject, session_id: u32) -> Result<(), UwbErr> {
dispatch_command(env, obj, JNICommand::UwaSessionDeinit(session_id))
}
fn get_session_count(env: JNIEnv, obj: JObject) -> Result<(), UwbErr> {
dispatch_command(env, obj, JNICommand::UwaSessionGetCount)
}
fn ranging_start(env: JNIEnv, obj: JObject, session_id: u32) -> Result<(), UwbErr> {
dispatch_command(env, obj, JNICommand::UwaStartRange(session_id))
}
fn ranging_stop(env: JNIEnv, obj: JObject, session_id: u32) -> Result<(), UwbErr> {
dispatch_command(env, obj, JNICommand::UwaStopRange(session_id))
}
fn get_session_state(env: JNIEnv, obj: JObject, session_id: u32) -> Result<(), UwbErr> {
dispatch_command(env, obj, JNICommand::UwaGetSessionState(session_id))
}
fn multicast_list_update(env: JNIEnv, obj: JObject, session_id: u32, action: u8, no_of_controlee: u8, address: jbyteArray, sub_session_id: &jintArray) -> Result<(), UwbErr> {
let address_list = env.convert_byte_array(address)?;
let sub_session_id_list: &mut [i32] = &mut [];
env.get_int_array_region(*sub_session_id, 0, sub_session_id_list)?;
dispatch_command(env, obj, JNICommand::UwaSessionUpdateMulticastList{session_id, action, no_of_controlee, address_list, sub_session_id_list: sub_session_id_list.to_vec()})
}
fn set_country_code(env: JNIEnv, obj: JObject, country_code: jbyteArray) -> Result<(), UwbErr> {
let code = env.convert_byte_array(country_code)?;
dispatch_command(env, obj, JNICommand::UwaSetCountryCode{code})
}
fn dispatch_command(env: JNIEnv, obj: JObject, command: JNICommand) -> Result<(), UwbErr> {
let dispatcher = get_dispatcher(env, obj)?;
dispatcher.send_jni_command(command)?;
Ok(())
}
fn get_dispatcher<'a>(env: JNIEnv, obj: JObject) -> Result<&'a mut Dispatcher, UwbErr> {
let dispatcher_ptr_value = env.get_field(obj, "mDispatcherPointer", "J")?;
let dispatcher_ptr = dispatcher_ptr_value.j()?;
if dispatcher_ptr == 0i64 {
warn!("The dispatcher is not initialized.");
return Err(UwbErr::NoneDispatcher);
}
// Safety: dispatcher pointer must not be a null pointer and it must point to a valid dispatcher object.
// This can be ensured because the dispatcher is created in an earlier stage and
// won't be deleted before calling doDeinitialize.
unsafe { Ok(&mut *(dispatcher_ptr as *mut Dispatcher)) }
}
/// create a dispatcher instance
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeDispatcherNew(env: JNIEnv, obj: JObject) -> jlong {
let eventmanager = EventManager::new(env, obj).expect("Failed to create event manager");
let dispatcher = match Dispatcher::new(eventmanager) {
Ok(dispatcher) => dispatcher,
Err(_err) => panic!("Fail to create dispatcher"),
};
Box::into_raw(Box::new(dispatcher)) as jlong
}
/// destroy the dispatcher instance
#[no_mangle]
pub extern "system" fn Java_com_android_uwb_jni_NativeUwbManager_nativeDispatcherDestroy(env: JNIEnv, obj: JObject) {
let dispatcher_ptr_value = match env.get_field(obj, "mDispatcherPointer", "J") {
Ok(value) => value,
Err(err) => {
error!("Failed to get the pointer with: {:?}", err);
return;
}
};
let dispatcher_ptr = dispatcher_ptr_value.j().expect("Failed to get the pointer!");
// Safety: dispatcher pointer must not be a null pointer and must point to a valid dispatcher object.
// This can be ensured because the dispatcher is created in an earlier stage and
// won't be deleted before calling this destroy function.
// This function will early return if the instance is already destroyed.
let _boxed_dispatcher = unsafe { Box::from_raw(dispatcher_ptr as *mut Dispatcher) };
info!("The dispatcher successfully destroyed.");
}
// TODO: Implement these functions
fn uwa_init() {
}
fn uwa_get_device_info(env: JNIEnv, obj: JObject) -> Result<UciResponse, UwbErr> {
let dispatcher = get_dispatcher(env, obj)?;
let res = dispatcher.block_on_jni_command(BlockingJNICommand::GetDeviceInfo)?;
Ok(res)
}
fn uwa_enable() -> Result<(), UwbErr> {
Ok(())
}
fn clear_all_session_context() {
}
fn uwa_disable(_para: bool) -> Result<(), UwbErr> {
Err(UwbErr::refused())
}
fn set_core_device_configurations() -> Result<(), UwbErr> {
Ok(())
}