Komunikasi ultra-wideband (UWB)

Komunikasi ultra-wideband adalah teknologi radio yang berfokus pada rentang presisi (mengukur lokasi hingga akurasi 10 cm) antarperangkat. Teknologi radio ini dapat menggunakan kepadatan energi rendah untuk pengukuran jarak pendek dan melakukan sinyal bandwidth tinggi melalui sebagian besar spektrum radio. Bandwidth UWB lebih besar dari 500 MHz (atau melebihi bandwidth pecahan 20%).

Pengontrol/Inisiator vs. Pengendali/Responden

Komunikasi UWB terjadi antara dua perangkat, dengan salah satunya sebagai Pengontrol dan yang lainnya sebagai Controlee. Pengontrol menentukan saluran kompleks (UwbComplexChannel) yang akan dibagikan oleh kedua perangkat dan merupakan inisiator, sedangkan Controlee adalah responden.

Pengontrol dapat menangani beberapa Kontrol, tetapi satu Pengontrol hanya dapat berlangganan ke satu Pengontrol. Konfigurasi Pengontrol/Inisiator dan Controlee/Responder didukung.

Parameter rentang

Pengontrol dan Controlee perlu mengidentifikasi satu sama lain dan mengomunikasikan parameter rentang untuk memulai ranging. Pertukaran ini diserahkan ke aplikasi untuk diimplementasikan menggunakan mekanisme out-of-band (OOB) yang aman pilihan mereka, seperti Bluetooth Hemat Energi (BLE).

Parameter rentang mencakup alamat lokal, saluran kompleks, dan kunci sesi. Perhatikan bahwa parameter ini dapat dirotasi atau berubah setelah sesi ranging berakhir dan perlu dikomunikasikan kembali untuk memulai ulang ranging.

Langkah

Untuk menggunakan UWB API, ikuti langkah-langkah berikut:

  1. Pastikan perangkat Android berjalan di Android 12 atau yang lebih baru dan mendukung UWB menggunakan PackageManager#hasSystemFeature("android.hardware.uwb").
  2. Jika berkisar pada perangkat IoT, pastikan perangkat tersebut mematuhi FiRa MAC 1.3.
  3. Temukan perangkat pembanding berkemampuan UWB menggunakan mekanisme OOB pilihan Anda, seperti BluetoothLeScanner.
  4. Menukar parameter rentang menggunakan mekanisme OOB yang aman pilihan Anda, seperti BluetoothGatt.
  5. Jika pengguna ingin menghentikan sesi, batalkan cakupan sesi.

Batasan penggunaan

Pembatasan berikut berlaku untuk penggunaan UWB API:

  1. Aplikasi yang memulai sesi rentang UWB baru harus berupa aplikasi/layanan latar depan.
  2. Saat aplikasi berpindah ke latar belakang (saat sesi sedang berlangsung), aplikasi mungkin tidak lagi menerima laporan rentang. Namun, sesi UWB akan terus dipertahankan di lapisan yang lebih rendah. Saat aplikasi kembali ke latar depan, laporan ranging akan dilanjutkan.

Contoh kode

Aplikasi contoh

Untuk contoh menyeluruh tentang cara menggunakan library Jetpack UWB, lihat aplikasi contoh kami di GitHub. Aplikasi contoh ini mencakup validasi kompatibilitas UWB pada perangkat Android, memungkinkan proses penemuan menggunakan mekanisme OOB, dan menyiapkan rentang UWB di antara dua perangkat berkemampuan UWB. Contoh ini juga mencakup kasus penggunaan kontrol perangkat dan berbagi media.

Rentang UWB

Contoh kode ini memulai dan menghentikan rentang UWB untuk Controlee:

// The coroutineScope responsible for handling uwb ranging.
// This will be initialized when startRanging is called.
var job: Job?

// A code snippet that initiates uwb ranging for a Controlee.
suspend fun startRanging() {

    // Get the ranging parameter of a partnering Controller using an OOB mechanism of choice.
    val partnerAddress : Pair<UwbAddress, UwbComplexChannel> = listenForPartnersAddress()

    // Create the ranging parameters.
    val partnerParameters = RangingParameters(
        uwbConfigType = UwbRangingParameters.UWB_CONFIG_ID_1,
        // SessionKeyInfo is used to encrypt the ranging session.
        sessionKeyInfo = null,
        complexChannel = partnerAddress.second,
        peerDevices = listOf(UwbDevice.createForAddress(partnerAddress.first)),
        updateRateType = UwbRangingParameters.RANGING_UPDATE_RATE_AUTOMATIC
    )

    // Initiate a session that will be valid for a single ranging session.
    val clientSession = uwbManager.clientSessionScope()

    // Share the localAddress of the current session to the partner device.
    broadcastMyParameters(clientSession.localAddress)

    val sessionFlow = clientSession.prepareSession(partnerParameters)

    // Start a coroutine scope that initiates ranging.
    CoroutineScope(Dispatchers.Main.immediate).launch {
        sessionFlow.collect {
            when(it) {
                is RangingResultPosition -> doSomethingWithPosition(it.position)
                is RangingResultPeerDisconnected -> peerDisconnected(it)
            }
        }
    }
}

// A code snippet that cancels uwb ranging.
fun cancelRanging() {

    // Canceling the CoroutineScope will stop the ranging.
    job?.let {
        it.cancel()
    }
}

Dukungan RxJava3

Dukungan Rxjava3 kini tersedia untuk membantu mencapai interoperabilitas dengan klien Java. Library ini menyediakan cara untuk mendapatkan hasil rentang sebagai aliran Observable atau Flowable, dan untuk mengambil UwbClientSessionScope sebagai objek Tunggal.

private final UwbManager uwbManager;

// Retrieve uwbManager.clientSessionScope as a Single object
Single<UwbClientSessionScope> clientSessionScopeSingle =
                UwbManagerRx.clientSessionScopeSingle(uwbManager);
UwbClientSessionScope uwbClientSessionScope = clientSessionScopeSingle.blockingGet();

// Retrieve uwbClientSessionScope.prepareSession Flow as an Observable object
Observable<RangingResult> rangingResultObservable =
                UwbClientSessionScopeRx.rangingResultsObservable(clientSessionScope,
                        rangingParameters);

// Consume ranging results from Observable
rangingResultObservable.subscribe(
   rangingResult -> doSomethingWithRangingResult(result), // onNext
   (error) -> doSomethingWithError(error), // onError
   () -> doSomethingOnResultEventsCompleted(), //onCompleted
);
// Unsubscribe
rangingResultObservable.unsubscribe();
   

// Retrieve uwbClientSessionScope.prepareSession Flow as a Flowable object
Flowable<RangingResult> rangingResultFlowable =
                UwbClientSessionScopeRx.rangingResultsFlowable(clientSessionScope,
                        rangingParameters);

// Consume ranging results from Flowable using Disposable
Disposable disposable = rangingResultFlowable
   .delay(1, TimeUnit.SECONDS)
   .subscribeWith(new DisposableSubscriber<RangingResult> () {
      @Override public void onStart() {
          request(1);
      }
      
      @Override public void onNext(RangingResult rangingResult) {
             doSomethingWithRangingResult(rangingResult);
             request(1);
      }


      @Override public void onError(Throwable t) {
             t.printStackTrace();
      }


         @Override public void onComplete() {
            doSomethingOnEventsCompleted();
         }
   });

// Stop subscription
disposable.dispose();

Dukungan ekosistem

Berikut adalah perangkat partner dan SDK pihak ketiga yang didukung.

Perangkat seluler yang mendukung UWB

Mulai April 2023, perangkat berikut mendukung library Jetpack Android UWB:

Vendor Model Perangkat
Google Pixel 6 Pro, Pixel 7 Pro
Samsung Galaxy Note 20, S21+, S22+, Z Fold 2, 3, 4

SDK pihak ketiga

Mulai April 2023, solusi partner ini kompatibel dengan library Jetpack saat ini.

Masalah umum: urutan byte dibalik untuk kolom alamat MAC dan ID vendor STS statis

Di Android 13 dan yang lebih lama, stack UWB Android salah membalik urutan byte untuk kolom berikut:

  • Alamat MAC perangkat
  • Alamat MAC tujuan
  • ID vendor STS statis

Pembalikan urutan byte terjadi karena stack Android memperlakukan kolom ini sebagai nilai, bukan array. Kami bekerja sama dengan FiRa untuk memperbarui spesifikasi UCI (CR-1112) agar secara eksplisit menyatakan bahwa kolom ini harus diperlakukan sebagai array.

Masalah ini akan diperbaiki melalui update GMS Core dalam rilis 2320XXXX. Agar mematuhi perangkat Android sejak saat itu, vendor IOT perlu mengubah implementasi Anda untuk menghindari membalikkan urutan byte kolom ini.