תקשורת Ultra Wideband (UWB)

תקשורת Ultra Wideband (UWB) היא טכנולוגיית רדיו שמתמקדת בטווח מדויק (מדידת המיקום ברמת דיוק של 10 ס"מ) בין מכשירים. טכנולוגיית הרדיו הזו יכולה להשתמש בצפיפות אנרגיה נמוכה למדידות של טווח קצר ומבצעים אותות ברוחב פס גבוה על פני חלק גדול מספקטרום הרדיו. רוחב הפס של UWB גדול מ-500MHz (או גדול מ-20% שהוא חלקי רוחב פס).

נאמני מידע/יוזם לעומת מבוקר/משיב

תקשורת UWB מתרחשת בין שני מכשירים, שאחד מהם הוא שלט רחוק, אחר הוא בעל שליטה. נאמן המידע קובע את הערוץ המורכב (UwbComplexChannel) ש שני המכשירים ישתפו והוא יוזם, ואילו בעל השליטה הוא מגיב.

נאמני מידע יכולים לטפל במספר בעלי הרשאות, אבל משתמש שמוגדר כנאמן מידע יכול להירשם רק לערוץ לנאמן מידע יחיד. גם נאמני מידע/יוזם נתונים וגם מבוקר/ת או משיב/ה ההגדרות האישיות.

פרמטרים של טווח

נאמן המידע ונאמן המידע צריכים לזהות זה את זה ולתקשר בטווח של פרמטרים כדי להתחיל בטווח. ההחלפה הזו נשארת לאפליקציות כדי להטמיע באמצעות מנגנון מאובטח מחוץ למסגרת (OOB) לבחירתם, כמו Bluetooth Low Energy (BLE).

הפרמטרים של הטווח כוללים כתובת מקומית, ערוץ מורכב, מפתח סשן ועוד. הערה שהפרמטרים האלה עשויים להשתנות או להשתנות בדרך אחרת לאחר הסשן של הטווח מסתיים וצריך לתקשר אותו מחדש כדי להפעיל מחדש את הטווח.

טווח הרקע

אפליקציה שפועלת ברקע יכולה להתחיל סשן בטווח UWB אם המכשיר תומך בכך. כדי לבדוק את יכולות המכשיר: RangingCapabilities.

האפליקציה לא מקבלת מגוון דוחות כשהיא פועלת ברקע; האפליקציה מקבל מגוון דוחות כשהוא עובר לחזית.

הגדרות STS

האפליקציה או השירות מקצים מפתח סשן לכל סשן באמצעות מפתח מעורבל. רצף חותמות זמן (STS). תשתית STS שהוקצתה מאובטחת יותר מ-STS סטטי הגדרה אישית. STS מוקצה נתמך בכל המכשירים שתומכים ב-UWB פועלים Android מגרסה 14 ואילך.

קטגוריית האיום STS סטטי STS בפיקוח
אוויר: צופה פסיבי תכונות שננקטו לגביהן צמצום תכונות שננקטו לגביהן צמצום
אוויר: הגברת אותות תכונות שננקטו לגביהן צמצום תכונות שננקטו לגביהן צמצום
Air: מתקפת שידור/ממסר חשופים תכונות שננקטו לגביהן צמצום

עבור STS שהוקצו:

  1. שימוש ב-uwbConfigType ב-RangingParameters שתומך ב-STS שהוקצו.

  2. מזינים את המפתח בגודל 16 בייטים בשדה sessionKeyInfo.

עבור STS סטטי:

  1. שימוש במאפיין uwbConfigType ב-RangingParameters שתומך ב-STS סטטיות.

  2. מזינים את המפתח בן 8 הבייטים בשדה sessionKeyInfo.

צעדים

כדי להשתמש ב-UWB API, פועלים לפי השלבים הבאים:

  1. חשוב לוודא שמכשירי Android עובדים עם Android מגרסה 12 ואילך ושהם תמיכה ב-UWB באמצעות PackageManager#hasSystemFeature("android.hardware.uwb")
  2. אם הטווח הוא למכשירי IoT, יש לוודא שהם FiRa MAC 1.3 תואם למדיניות.
  3. תוכלו לגלות מכשירים עמיתים עם יכולות UWB באמצעות מנגנון OOB לבחירתכם, כמו BluetoothLeScanner
  4. החלפת פרמטרים בטווח באמצעות מנגנון OOB מאובטח לבחירתכם, כמו BluetoothGatt.
  5. אם המשתמש רוצה להפסיק את הסשן, צריך לבטל את היקף הסשן.

הגבלות שימוש

ההגבלות הבאות חלות על השימוש ב-UWB API:

  1. האפליקציה שמתחילה סשנים חדשים של טווח UWB חייבת להיות בחזית אפליקציה או שירות, אלא אם טווח הרקע נתמך כפי שמתואר באיור מוקדם יותר.
  2. כשהאפליקציה עוברת לרקע (בזמן שהסשן פעיל), עשויים להפסיק לקבל דוחות שונים. עם זאת, סשן UWB ימשיכו להישמר בשכבות הנמוכות יותר. כשהאפליקציה חוזרת בחזית, מגוון הדוחות ימשיך לפעול.

דוגמאות קוד

אפליקציה לדוגמה

כדי לראות דוגמה מקצה לקצה לאופן השימוש בספריית UWB Jetpack, אפשר לעיין באפליקציה לדוגמה ב-GitHub. האפליקציה לדוגמה הזו מכסה אימות תאימות של UWB במכשיר Android, הפעלת תהליך הגילוי באמצעות מנגנון OOB והגדרה של UWB בין שני מכשירים עם יכולות UWB. הדוגמה כוללת גם תרחישים לדוגמה של שליטה במכשיר ושיתוף מדיה.

טווח UWB

דוגמת הקוד הזו יוזמת ומסיימת טווח UWB של מקבל בקרה:

// 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()
    }
}

תמיכה ב-RxJava3

עכשיו יש תמיכה ב-Rxjava3 כדי לאפשר יכולת פעולה הדדית עם Java הלקוחות שלנו. הספרייה הזו מספקת דרך לקבל מגוון תוצאות כ'ניתן לצפייה' או זרם זורם, ולאחזר את UwbClientSessionScope כאובייקט יחיד.

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();

תמיכה בסביבה העסקית

אלו המכשירים הנתמכים וערכות ה-SDK של צדדים שלישיים.

מכשירים ניידים עם תמיכה ב-UWB

החל ממרץ 2024, במכשירים הבאים יש תמיכה בספריית Android UWB Jetpack:

ספק דגם המכשיר
Google Pixel 6 Pro, Pixel 7 Pro, 8 Pro, Pixel Fold, טאבלט
Samsung Galaxy Note 20, S21+, S22+, S23+, S24+ Z Fold 2, 3, 4, 5

ערכות SDK של צד שלישי

החל מאפריל 2023, הפתרונות האלה לשותפים תואמים הספרייה הנוכחית של Jetpack.

בעיה ידועה: סדר הבייטים בוטל בשדות של כתובת MAC ומזהה ספק STS סטטי

ב-Android מגרסה 13 ומטה, מחסנית Android UWB הופכת את הבייט בטעות לפי הסדר בשדות הבאים:

  • כתובת MAC של המכשיר
  • כתובת MAC של יעד
  • מזהה ספק STS סטטי

היפוך הסדר של הבייטים מתרחשת כי מחסנית Android מתייחסת לשדות האלה כערכים, לא כמערכים. אנחנו עובדים עם FiRa כדי לעדכן את המפרט של UCI (CR-1112) כדי לקבוע במפורש שיש להתייחס לשדות האלה כמערכים.

הבעיה הזו תיפתר דרך עדכון הליבה של GMS בגרסה 2320XXXX. כדי לעמוד בדרישות למכשירי Android מאותו רגע ואילך, ספקי IOT צריכים לשנות את ההטמעה כדי למנוע היפוך של סדר הבייטים בשדות האלה.