תקשורת Ultra-Wideband היא טכנולוגיית רדיו שמתמקדת בטווח מדויק (מדידת המיקום בדיוק של 10 ס"מ) בין מכשירים. טכנולוגיית הרדיו הזו יכולה להשתמש בצפיפות אנרגיה נמוכה למדידות לטווח קצר, ולבצע איתות ברוחב פס גבוה בחלק גדול מתחום התדרים של הרדיו. רוחב הפס של UWB גדול מ-500 MHz (או חורג מ-20% רוחב פס חלקי).
גורם בקרה/גורם מפעיל לעומת גורם מבוקר/גורם מגיב
תקשורת UWB מתרחשת בין שני מכשירים, כאשר אחד מהם הוא מכשיר בקרה והשני הוא מכשיר מבוקר. הגורם המבקר קובע את הערוץ המורכב (UwbComplexChannel
) ששני המכשירים ישתפו, והוא זה שמתחיל את התהליך, בעוד שהגורם המבוקר הוא זה שמגיב.
אמצעי בקרה יכול לטפל בכמה פריטים שנשלטים, אבל פריט שנשלט יכול להירשם רק לאמצעי בקרה אחד. השירות תומך בתצורות של בקר/יזם ושל מושפע/משיב.
פרמטרים של מדידת טווח
כדי להתחיל את תהליך הטווח, ה-Controller וה-Controllee צריכים לזהות זה את זה ולתקשר את הפרמטרים של הטווח. האפליקציות צריכות להטמיע את החלפת המפתחות באמצעות מנגנון מאובטח מחוץ לערוץ (OOB) לבחירתן, כמו Bluetooth עם צריכת אנרגיה נמוכה (BLE).
פרמטרים של טווח כוללים, בין היתר, כתובת מקומית, ערוץ מורכב ומפתח סשן. חשוב לזכור שהפרמטרים האלה עשויים להשתנות או להסתובב לאחר סיום סשן הטווח, ויש להעביר אותם מחדש כדי להפעיל מחדש את הטווח.
מדידת מרחק ברקע
אפליקציה שפועלת ברקע יכולה להתחיל סשן למדידת מרחק באמצעות UWB אם המכשיר תומך בכך. כדי לבדוק את יכולות המכשיר, אפשר לעיין במאמר RangingCapabilities
.
האפליקציה לא מקבלת דוחות טווח כשהיא פועלת ברקע, אלא רק כשהיא עוברת לחזית.
הגדרות STS
האפליקציה או השירות מקצים מפתח סשן לכל סשן באמצעות רצף חותמות זמן מוצפנות (STS). STS מוקצה מאובטח יותר מתצורת STS סטטית. אפשר להשתמש ב-STS מוגדר מראש בכל המכשירים שתומכים ב-UWB עם Android מגרסה 14 ואילך.
קטגוריית האיום | Static STS | STS שהוקצה |
---|---|---|
אוויר: משקיף פסיבי | ננקטו תנאים מיוחדים לצמצום סיכונים | ננקטו תנאים מיוחדים לצמצום סיכונים |
באוויר: הגברה של האות | ננקטו תנאים מיוחדים לצמצום סיכונים | ננקטו תנאים מיוחדים לצמצום סיכונים |
אוויר: מתקפת שליחה מחדש/שליחה חוזרת | חשוף | ננקטו תנאים מיוחדים לצמצום סיכונים |
ל-STS שהוקצה:
משתמשים ב-
uwbConfigType
ב-RangingParameters
שתומך ב-STS שהוקצה.מזינים את המפתח בן 16 הבתים בשדה
sessionKeyInfo
.
ל-STS סטטי:
משתמשים ב-
uwbConfigType
ב-RangingParameters
שתומך ב-STS סטטי.מזינים את המפתח בן 8 הבתים בשדה
sessionKeyInfo
.
צעדים
כדי להשתמש ב-UWB API:
- מוודאים שמכשירי Android פועלים עם Android 12 ואילך ושהם תומכים ב-UWB באמצעות
PackageManager#hasSystemFeature("android.hardware.uwb")
. - אם מבצעים מדידה של טווח מול מכשירי IoT, צריך לוודא שהם תואמים ל-FiRa MAC 1.3.
- מאתרים מכשירים עמיתים עם תמיכה ב-UWB באמצעות מנגנון OOB לבחירתכם, כמו
BluetoothLeScanner
. - מחליפים את הפרמטרים של הטווח באמצעות מנגנון מאובטח מחוץ ל-IP לבחירתכם, כמו
BluetoothGatt
. - אם המשתמש רוצה להפסיק את הסשן, צריך לבטל את היקף הסשן.
הגבלות שימוש
ההגבלות הבאות חלות על השימוש ב-UWB API:
- האפליקציה שמפעילה סשנים חדשים למדידת מרחק באמצעות UWB חייבת להיות אפליקציה או שירות שפועלים בחזית, אלא אם יש תמיכה במדידת מרחק ברקע כפי שמתואר למעלה.
- כשהאפליקציה מועברת לרקע (בזמן שהסשן נמשך), יכול להיות שהיא לא תקבל יותר דוחות טווח. עם זאת, הסשן של 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. הספרייה הזו מספקת דרך לקבל תוצאות סריקה כזרם של Observable או Flowable, ולשלוף את UwbClientSessionScope כאובייקט Single.
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
החל מינואר 2025, המכשירים הבאים תומכים בספריית Jetpack של Android UWB:
ספק | דגם המכשיר |
---|---|
Pixel Pro (6 Pro ודגמים חדשים יותר), Fold, Tablet | |
Motorola | Edge 50 Ultra |
Samsung | Galaxy Note 20, Galaxy Plus ו-Ultra (S21 ודגמים חדשים יותר), Galaxy Z Fold (Fold2 ודגמים חדשים יותר) |
הערה: יש תמיכה במדידת המרחק ברקע באמצעות UWB בכל המכשירים, מלבד במכשירים הבאים:
- Pixel 6 Pro ו-Pixel 7 Pro.
- טלפונים של Samsung עם Android מגרסה 13 ומטה.
- טלפונים של Samsung בסין עם Android מגרסה 14 ומטה.
ערכות SDK של צד שלישי
החל מאפריל 2023, פתרונות השותפים האלה תואמים לספריית Jetpack הנוכחית.
- ערכת פיתוח UWB של Estimote.
- MK UWB Kit Mobile Edition 2.0 של Mobile Knowledge.
בעיה ידועה: סדר הבייטים הפוך בשדות של כתובת ה-MAC ומזהה הספק הסטטי של STS
ב-Android מגרסה 13 ומטה, סטאק UWB של Android הופך בטעות את סדר הבייטים בשדות הבאים:
- כתובת MAC של המכשיר
- כתובת MAC של יעד
- מזהה ספק סטטי של STS
היפוך סדר הבייטים מתרחש כי סטאק Android מתייחס לשדות האלה כערכים, ולא כמערכי נתונים. אנחנו עובדים עם FiRa כדי לעדכן את מפרט UCI (CR-1112) כך שיציין במפורש שצריך להתייחס לשדות האלה כמערכי נתונים.
הבעיה הזו תטופל באמצעות עדכון GMS Core במהדורה 2320XXXX
.
כדי לעמוד בדרישות של מכשירי Android החל מהנקודה הזו, ספקי ה-IoT צריכים לשנות את ההטמעה כדי למנוע היפוך של סדר הבייטים בשדות האלה.