11.5. חיבורים¶
ברגע שהתקן מרכזי (central) בוחר התקן היקפי (peripheral) מתוך זרם הפרסום ושולח אליו connect request, שני הצדדים יוצאים ממצב פרסום / סריקה ונכנסים ל-connection. כעת מתזמן הרדיו את פעילותו על ערוצי הנתונים של שכבת הקישור (link layer), תוך דילוג פסבדו-אקראי ביניהם לפי הרצף שהוסכם בזמן יצירת החיבור. כל מה שמעל שכבת הקישור – GATT, אבטחה, L2CAP – רץ מעל החיבור שנוצר כאן.
11.5.1. אירוע החיבור¶
שני התקנים בחיבור BLE אינם משדרים ברצף. הם מסכימים על connection interval, ובכל מרווח שני הצדדים מעירים את הרדיו, מחליפים את החבילות שבתור, מאשרים את מה שקיבלו וחוזרים לישון. כל אחת מההחלפות הללו נקראת connection event.
הרדיו בכל צד ער רק במהלך אירועי החיבור הקצרים, וכל השאר ישן. ההתקן ההיקפי רשאי לדלג על אירועים תחת peripheral latency.¶
המספרים השולטים בכך נסגרים במשא ומתן בזמן יצירת החיבור, ושכבת הקישור אוכפת אותם. הם גלויים ליישום הן כידיות בצד הבקשה והן כערכים המתקבלים המדווחים בחזרה.
Connection interval. מ-7.5 ms עד 4 s, בצעדים של 1.25 ms. ההתקן המרכזי בוחר את הערך שההתקן ההיקפי מבקש, אלא אם הבקשה בלתי סבירה. מרווחים קצרים יותר מספקים נתונים בהשהיה נמוכה יותר במחיר של פעילות רדיו רבה יותר; מרווחים ארוכים יותר חוסכים אנרגיה אך הופכים כל סבב הלוך-ושוב לאיטי יותר.
Peripheral latency. מספר שלם אי-שלילי N. ההתקן ההיקפי רשאי לדלג על עד N אירועי חיבור כשאין לו מה לשלוח, וחוזר לישון במקום להעיר את הרדיו עבור החלפה ריקה. שימושי עבור חיישנים שמתעוררים לדווח פעם בשנייה אך רוצים connection interval קצר ותגובתי עבור ההודעה המיידית הנדירה.
Supervision timeout. מ-100 ms עד 32 s. אם אחד הצדדים אינו שומע דבר מהצד השני למשך פרק זמן זה, הקישור מוכרז כאבוד ושני הצדדים חוזרים לפרסום / סריקה. ה-timeout חייב להיות ארוך מ-
connection_interval * (1 + peripheral_latency)– שכבת הקישור דוחה ערכים המפרים זאת.
aioble.Device.connect() מקבלת min_conn_interval_us ו-max_conn_interval_us כך שההתקן המרכזי יכול לבקש טווח מסוים; את הערך בפועל שעליו התייצב הרדיו אפשר לקרוא בחזרה דרך הגדרת שכבת הקישור לאחר שהחיבור פעיל.
11.5.2. מה המשמעות של ”central“ ו-”peripheral“ בתוך חיבור¶
התפקידים שנקבעו בזמן הפרסום נשמרים לאחר שהחיבור עולה:
ה-central מנהל את התזמון – הוא הבעלים של צד ה-master של רצף הדילוג ושל אירועי החיבור.
ה-peripheral תגובתי. הוא יכול לבקש שינוי בפרמטרי החיבור (מרווח איטי יותר כדי לחסוך אנרגיה, למשל) אך ההתקן המרכזי הוא שמחליט אם לקבל.
התפקידים בלתי תלויים בשאלה מי מארח את מסד הנתונים של GATT, שהוא ציר נפרד. על פי המוסכמה ההתקן ההיקפי הוא גם ה-server של GATT וההתקן המרכזי הוא ה-client של GATT, אך BLE מאפשר לכל צד לארח שירותי GATT. מצלמות כמעט תמיד הולכות לפי המוסכמה: peripheral + server עבור יישומי ”המצלמה מפרסמת נתונים“, central + client עבור יישומי ”המצלמה קוראת מחיישן“.
11.5.3. יחידת השידור המרבית (MTU)¶
שכבת הקישור נושאת חבילות קצרות כברירת מחדל – 27 בייטים של מטען, מתוכם רק 23 זמינים ל-GATT. זה מספיק לקריאה קטנה או לפקודה קצרה אך זעיר ביחס לכל דבר מרובה-בייטים. שני הצדדים יכולים לנהל משא ומתן להעלאת ערך זה, עד הגבול שקושחת הרדיו תומכת בו (בדרך כלל כמה מאות בייטים בבקרים מודרניים).
ה-API של aioble מנהל את המשא ומתן דרך aioble.DeviceConnection.exchange_mtu() והתוצאה הופכת זמינה דרך התכונה mtu. ערכי MTU גדולים יותר משמעם פחות סבבי הלוך-ושוב עבור כל ערך גדול מ-~20 בייטים, במחיר קטן של זיכרון חוצץ (buffer).
11.5.4. אורך חיים¶
חיבור נמשך עד שאחד מאלה קורה:
אחד הצדדים קורא ל-
disconnect(),ה-supervision timeout מופעל (מחוץ לטווח, רדיו כבוי, התקן עמית קרס), או
כשל מפורש בשכבת הקישור (אי-התאמת הצפנה, דחיית pairing).
כאשר החיבור נופל, כל פעולת GATT בתור או בטיסה עליו מעלה aioble.DeviceDisconnectedError, וכל בלוק async with connection שהיישום נמצא בו יוצא באופן נקי. התקן היקפי בדרך כלל מגיב בכך שהוא חוזר ל-aioble.advertise() וממתין להתקן המרכזי הבא; התקן מרכזי מגיב בכך שהוא סורק שוב או חושף את הניתוק ליישום.
אורך החיים הוא אחת הסיבות לכך ש-aioble שימושי. API סינכרוני של BLE היה צריך לחשוף פונקציות callback של ניתוק ומסכות אירועים; גרסת ה-asyncio הופכת ניתוקים לחריגות בתוך ה-coroutine שהמתינה לפעולה, וזה בדיוק מה שניקוי async with בנוי עבורו.