שכבת ההפשטה של החומרה (HAL) של החיישנים היא הממשק בין מסגרת החיישנים של Android לבין החיישנים של המכשיר, כמו מד תאוצה או ג'ירוסקופ. ה-HAL של החיישנים מגדיר את הפונקציות שצריך להטמיע כדי לאפשר למסגרת לשלוט בחיישנים.
Sensors HAL 2.0 זמין ב-Android מגרסה 10 ואילך במכשירים חדשים ובמכשירים ששודרגו. Sensors HAL 2.0 מבוסס על Sensors HAL 1.0, אבל יש כמה הבדלים חשובים שמונעים תאימות לאחור. Sensors HAL 2.0 משתמש בתורים מהירים של הודעות (FMQ) כדי לשלוח אירועי חיישן מ-HAL למסגרת החיישן של Android.
Sensors HAL 2.1 זמין ב-Android מגרסה 11 ואילך במכשירים חדשים ובמכשירים משודרגים. Sensors HAL 2.1 הוא איטרציה של Sensors HAL 2.0 שחושפת את סוג החיישן HINGE_ANGLE ומעדכנת שיטות שונות כדי לקבל את הסוג HINGE_ANGLE.
ממשק HAL 2.1
המקור העיקרי לתיעוד של Sensors HAL 2.1 נמצא בהגדרת ה-HAL בכתובת hardware/interfaces/sensors/2.1/ISensors.hal.
במקרה של סתירה בין הדרישות בדף הזה לבין הדרישות בISensors.hal, הדרישות בISensors.hal הן הקובעות.
ממשק HAL 2.0
המקור העיקרי לתיעוד של Sensors HAL 2.0 נמצא בהגדרת ה-HAL בכתובת hardware/interfaces/sensors/2.0/ISensors.hal.
במקרה של סתירה בין הדרישות בדף הזה לבין הדרישות בISensors.hal, הדרישות בISensors.hal הן הקובעות.
הטמעה של Sensors HAL 2.0 ו-HAL 2.1
כדי להטמיע את Sensors HAL 2.0 או 2.1, אובייקט צריך להרחיב את הממשק ISensors ולהטמיע את כל הפונקציות שמוגדרות ב-2.0/ISensors.hal או ב-2.1/ISensors.hal.
אתחול ה-HAL
לפני שניתן להשתמש ב-HAL של החיישנים, צריך לאתחל אותו באמצעות מסגרת החיישנים של Android. המסגרת קוראת לפונקציה initialize() עבור HAL 2.0 ולפונקציה initialize_2_1() עבור HAL 2.1 כדי לספק שלושה פרמטרים ל-Sensors HAL: שני מתארים של FMQ ומצביע אחד לאובייקט ISensorsCallback.
שכבת ה-HAL משתמשת בתיאור הראשון כדי ליצור את ה-FMQ של האירוע שמשמש לכתיבת אירועי חיישן למסגרת. ה-HAL משתמש בתיאור השני כדי ליצור את ה-FMQ של Wake Lock שמשמש לסנכרון כשה-HAL משחרר את ה-Wake Lock שלו עבור WAKE_UPאירועי חיישן. שכבת ה-HAL צריכה לשמור מצביע לאובייקט ISensorsCallback כדי שאפשר יהיה להפעיל את פונקציות ההתקשרות חזרה הנדרשות.
הפונקציה initialize() או initialize_2_1() חייבת להיות הפונקציה הראשונה שמופעלת כשמאתחלים את Sensors HAL.
חשיפה של חיישנים זמינים
כדי לקבל רשימה של כל החיישנים הסטטיים שזמינים במכשיר, משתמשים בפונקציה getSensorsList() ב-HAL 2.0 ובפונקציה getSensorsList_2_1() ב-HAL 2.1. הפונקציה מחזירה רשימה של חיישנים, שכל אחד מהם מזוהה באופן ייחודי על ידי נקודת האחיזה שלו. הכינוי של חיישן מסוים לא יכול להשתנות כשמפעילים מחדש את התהליך שמארח את Sensors HAL. יכול להיות שהכינויים ישתנו אחרי הפעלה מחדש של המכשיר, וגם אחרי הפעלה מחדש של שרת המערכת.
אם כמה חיישנים חולקים את אותו סוג חיישן ואת אותה תכונת התעוררות, החיישן הראשון ברשימה נקרא חיישן ברירת המחדל והוא מוחזר לאפליקציות שמשתמשות בפונקציה getDefaultSensor(int sensorType, bool wakeUp).
יציבות של רשימת החיישנים
אחרי הפעלה מחדש של Sensors HAL, אם הנתונים שמוחזרים על ידי getSensorsList() או getSensorsList_2_1() מצביעים על שינוי משמעותי בהשוואה לרשימת החיישנים שאוחזרה לפני ההפעלה מחדש, המסגרת מפעילה מחדש את זמן הריצה של Android. שינויים משמעותיים ברשימת החיישנים כוללים מקרים שבהם חסר חיישן עם נקודת אחיזה נתונה או שהמאפיינים שלו השתנו, או מקרים שבהם נוספו חיישנים חדשים. למרות שהפעלה מחדש של זמן הריצה של Android עלולה לשבש את חוויית המשתמש, היא נדרשת כי מסגרת Android לא יכולה יותר לעמוד בחוזה של Android API, שלפיו חיישנים סטטיים (לא דינמיים) לא משתנים במהלך משך החיים של האפליקציה. יכול להיות שהפעולה הזו גם תמנע ממסגרת Android להקים מחדש בקשות פעילות של חיישנים שבוצעו על ידי אפליקציות. לכן, מומלץ לספקי HAL למנוע שינויים ברשימת החיישנים שאפשר להימנע מהם.
כדי להבטיח טיפול יציב בחיישנים, שכבת HAL צריכה למפות באופן דטרמיניסטי חיישן פיזי נתון במכשיר לנקודת האחיזה שלו. ממשק Sensors HAL לא מחייב הטמעה ספציפית, אבל למפתחים יש כמה אפשרויות כדי לעמוד בדרישה הזו.
לדוגמה, אפשר למיין את רשימת החיישנים באמצעות שילוב של מאפיינים קבועים של כל חיישן, כמו ספק, דגם וסוג חיישן. אפשרות נוספת מתבססת על העובדה שקבוצת החיישנים הסטטיים של המכשיר קבועה בחומרה, ולכן שכבת HAL צריכה לדעת מתי כל החיישנים הצפויים סיימו את האתחול לפני שהיא מחזירה נתונים מ-getSensorsList() או מ-getSensorsList_2_1(). אפשר לקמפל את רשימת החיישנים הצפויים לתוך קובץ ה-HAL הבינארי או לאחסן אותה בקובץ הגדרות במערכת הקבצים. אפשר להשתמש בסדר ההופעה כדי להפיק נקודות אחיזה יציבות. הפתרון הטוב ביותר תלוי בפרטי ההטמעה הספציפיים של HAL, אבל הדרישה העיקרית היא שמזהי החיישנים לא ישתנו במהלך הפעלה מחדש של HAL.
הגדרת חיישנים
לפני שמפעילים חיישן, צריך להגדיר אותו באמצעות הפונקציה batch(), כולל תקופת דגימה וחביון מקסימלי של דיווח.
חייבת להיות אפשרות להגדיר מחדש את החיישן בכל שלב באמצעות batch() בלי לאבד את נתוני החיישן.
תקופת הדגימה
לפרק הזמן של הדגימה יש משמעות שונה בהתאם לסוג החיישן שמגדירים:
- רציף: אירועי החיישן נוצרים בקצב רציף.
- בשינוי: האירועים נוצרים בקצב שלא עולה על קצב תקופת הדגימה, ויכול להיות שהם ייווצרו בקצב איטי יותר אם הערך שנמדד לא משתנה.
- חד-פעמי: המערכת מתעלמת מתקופת הדגימה.
- מיוחד: פרטים נוספים זמינים במאמר בנושא סוגי חיישנים.
כדי לקבל מידע על האינטראקציה בין תקופת דגימה לבין מצבי הדיווח של חיישן, אפשר לעיין במאמר בנושא מצבי דיווח.
זמן ההמתנה המקסימלי לדיווח
החביון המקסימלי של הדיווח מגדיר את הזמן המקסימלי בננו-שניות שבו אפשר לעכב אירועים ולאחסן אותם ב-FIFO של החומרה לפני שהם נכתבים ל-FMQ של האירועים דרך ה-HAL בזמן שה-SoC פעיל.
ערך של אפס מציין שצריך לדווח על האירועים ברגע שהם נמדדים, או לדלג על ה-FIFO לחלוטין, או לרוקן את ה-FIFO ברגע שאירוע אחד מהחיישן נמצא ב-FIFO.
לדוגמה, מד תאוצה שמופעל בתדר של 50 Hz עם חביון דיווח מקסימלי של אפס מפעיל הפרעות 50 פעמים בשנייה כשה-SoC פעיל.
אם זמן האחזור המקסימלי של הדיווח גדול מאפס, אין צורך לדווח על אירועים של חיישנים ברגע שהם מזוהים. אפשר לאחסן אירועים באופן זמני ב-FIFO של החומרה ולדווח עליהם בקבוצות, כל עוד אף אירוע לא מתעכב מעבר לזמן האחזור המקסימלי של הדיווח. כל האירועים מאז הקבוצה הקודמת מתועדים ומוחזרים בבת אחת. כך מצמצמים את מספר ההפסקות שנשלחות ל-SoC ומאפשרים ל-SoC לעבור למצב צריכת חשמל נמוכה יותר בזמן שהחיישן אוסף נתונים ומקבץ אותם.
לכל אירוע משויכת חותמת זמן. העיכוב של השעה שבה מדווח על אירוע לא יכול להשפיע על חותמת הזמן של האירוע. חותמת הזמן צריכה להיות מדויקת ולשקף את הזמן שבו האירוע התרחש בפועל, ולא את הזמן שבו הוא דווח.
מידע נוסף על הדרישות לדיווח על אירועים של חיישנים עם זמן חביון מקסימלי לדיווח שאינו אפס זמין במאמר בנושא אצווה.
הפעלת חיישנים
המסגרת מפעילה ומשביתה חיישנים באמצעות הפונקציה activate().
לפני שמפעילים חיישן, המסגרת צריכה להגדיר את החיישן באמצעות batch().
אחרי שחיישן מושבת, אירועים נוספים של החיישן הזה לא יכולים להיכתב ל-FMQ של האירועים.
חיישני הדחה
אם חיישן מוגדר לאגור נתוני חיישנים, אפשר להשתמש ב-flush() כדי לאלץ את המסגרת לנקות את המאגר של אירועי החיישנים באופן מיידי. הפעולה הזו גורמת לכך שאירועי החיישן באצווה עבור נקודת האחיזה של החיישן שצוינה ייכתבו באופן מיידי ל-Event FMQ. מודול ה-HAL של החיישנים צריך לצרף אירוע של השלמת הניקוי לסוף אירועי החיישנים שנכתבים כתוצאה מקריאה ל-flush().
הפעולה מתבצעת באופן אסינכרוני (כלומר, הפונקציה הזו צריכה להחזיר ערך באופן מיידי). אם ההטמעה משתמשת ב-FIFO יחיד לכמה חיישנים, ה-FIFO הזה מתרוקן והאירוע של השלמת הריקון מתווסף רק לחיישן שצוין.
אם לחיישן שצוין אין FIFO (אי אפשר לבצע אחסון זמני), או אם ה-FIFO היה ריק בזמן הקריאה, הפונקציה flush() עדיין צריכה להצליח ולשלוח אירוע של השלמת ניקוי החיישן. הדרישה הזו חלה על כל החיישנים למעט חיישנים חד-פעמיים.
אם קוראים ל-flush() עבור חיישן חד-פעמי, הפונקציה flush() חייבת להחזיר BAD_VALUE ולא ליצור אירוע של סיום הניקוי.
כתיבת אירועי חיישן ל-FMQ
ה-FMQ של האירועים משמש את ה-HAL של החיישנים כדי לדחוף אירועים של חיישנים למסגרת החיישנים של Android.
תור ה-FMQ של האירועים הוא תור FMQ מסונכרן, כלומר כל ניסיון לכתוב יותר אירועים בתור ה-FMQ ממה שהמקום הפנוי מאפשר יגרום לכתיבה להיכשל. במקרה כזה, שכבת ה-HAL צריכה לקבוע אם לכתוב את קבוצת האירועים הנוכחית כשתי קבוצות קטנות יותר של אירועים, או לכתוב את כל האירועים יחד כשיש מספיק מקום.
אחרי ש-Sensors HAL כותב את מספר אירועי החיישן הרצוי ל-Event FMQ, הוא צריך להודיע למסגרת שהאירועים מוכנים. כדי לעשות זאת, הוא כותב את הביט EventQueueFlagBits::READ_AND_PROCESS לפונקציה EventFlag::wake של Event FMQ. אפשר ליצור את EventFlag מ-Event FMQ באמצעות EventFlag::createEventFlag והפונקציה getEventFlagWord() של Event FMQ.
Sensors HAL 2.0/2.1 תומך גם ב-write וגם ב-writeBlocking ב-Event FMQ.
ההטמעה שמוגדרת כברירת מחדל מספקת הפניה לשימוש ב-write. אם משתמשים בפונקציה writeBlocking, צריך להגדיר את הדגל readNotification לערך EventQueueFlagBits::EVENTS_READ, שמוגדר על ידי ה-Framework כשהוא קורא אירועים מ-Event FMQ. דגל ההתראה על כתיבה צריך להיות מוגדר לערך EventQueueFlagBits::READ_AND_PROCESS, שמציין למסגרת שאירועים נכתבו ל-FMQ של האירועים.
אירועי WAKE_UP
אירועים מסוג WAKE_UP הם אירועים של חיישנים שגורמים למעבד האפליקציות (AP) להתעורר ולטפל באירוע באופן מיידי. בכל פעם שאירוע WAKE_UP נכתב ל-Event FMQ, Sensors HAL חייב להבטיח שהמערכת תישאר פעילה עד שהמסגרת תוכל לטפל באירוע. כשמתקבל אירוע WAKE_UP, המסגרת מאבטחת את חסימת מצב השינה שלה, וכך מאפשרת ל-HAL של החיישנים לשחרר את חסימת מצב השינה שלו. כדי לסנכרן כשה-HAL של החיישנים משחרר את חסימת מצב השינה שלו, משתמשים ב-FMQ של חסימת מצב השינה.
שכבת HAL של חיישנים צריכה לקרוא את FMQ של Wake Lock כדי לקבוע את מספר WAKE_UP
האירועים שהמסגרת טיפלה בהם. שכבת ה-HAL צריכה לשחרר את חסימת מצב השינה שלה לאירועי WAKE_UP רק אם המספר הכולל של אירועי WAKE_UP שלא טופלו הוא אפס.
אחרי הטיפול באירועים של חיישנים, המסגרת סופרת את מספר האירועים שמסומנים כאירועי WAKE_UP וכותבת את המספר הזה בחזרה ל-FMQ של Wake Lock.
המסגרת מגדירה את WakeLockQueueFlagBits::DATA_WRITTEN write
notification ב-Wake Lock FMQ בכל פעם שהיא כותבת נתונים ב-Wake Lock FMQ.
חיישנים דינמיים
חיישנים דינמיים הם חיישנים שלא מהווים חלק פיזי מהמכשיר, אבל אפשר להשתמש בהם כקלט למכשיר, כמו גיימפד עם מד תאוצה.
כשחיישן דינמי מחובר, צריך להפעיל את הפונקציה onDynamicSensorConnected ב-ISensorsCallback מ-Sensors HAL. הפעולה הזו מודיעה למסגרת על החיישן הדינמי החדש, ומאפשרת לשלוט בחיישן דרך המסגרת ולצרוך את האירועים של החיישן על ידי לקוחות.
באופן דומה, כשחיישן דינמי מנותק, צריך לקרוא לפונקציה onDynamicSensorDisconnected ב-ISensorsCallback כדי שהמסגרת תוכל להסיר חיישן שכבר לא זמין.
ערוץ ישיר
ערוץ ישיר הוא שיטת פעולה שבה אירועי חיישנים נכתבים לזיכרון ספציפי במקום ל-Event FMQ, תוך עקיפת Android Sensors Framework. לקוח שרושם ערוץ ישיר חייב לקרוא את אירועי החיישן ישירות מהזיכרון ששימש ליצירת הערוץ הישיר, ולא יקבל את אירועי החיישן דרך המסגרת. הפונקציה configDirectReport()
דומה לפונקציה batch() בפעולה רגילה ומגדירה את ערוץ הדוחות הישירים.
הפונקציות registerDirectChannel() ו-unregisterDirectChannel() יוצרות או משמידות ערוץ ישיר חדש.
מצבי פעולה
הפונקציה setOperationMode() מאפשרת למסגרת להגדיר חיישן כדי שהמסגרת תוכל להחדיר נתוני חיישן לתוך החיישן. האפשרות הזו שימושית לבדיקות, במיוחד לאלגוריתמים שקיימים מתחת למסגרת.
הפונקציה injectSensorData() ב-HAL 2.0 והפונקציה injectSensorsData_2_1()
ב-HAL 2.0 משמשות בדרך כלל להעברת פרמטרים תפעוליים אל Sensors HAL. אפשר להשתמש בפונקציה גם כדי להחדיר אירועים של חיישנים לחיישן ספציפי.
אימות
כדי לאמת את ההטמעה של Sensors HAL, מריצים את בדיקות ה-CTS וה-VTS של החיישן.
בדיקות CTS
בדיקות CTS של חיישנים קיימות גם בבדיקות CTS אוטומטיות וגם באפליקציית CTS Verifier הידנית.
הבדיקות האוטומטיות נמצאות בתיקייה cts/tests/sensor/src/android/hardware/cts. בבדיקות האלה מאמתים את הפונקציונליות הרגילה של החיישנים, כמו הפעלה של חיישנים, עיבוד באצווה ושיעורי אירועים של חיישנים.
הבדיקות של CTS Verifier נמצאות בנתיב cts/apps/CtsVerifier/src/com/android/cts/verifier/sensors. הבדיקות האלה דורשות הזנה ידנית ממפעיל הבדיקה, והן מבטיחות שהחיישנים ידווחו על ערכים מדויקים.
הצלחה בבדיקות CTS היא קריטית כדי לוודא שהמכשיר שנבדק עומד בכל הדרישות של CDD.
בדיקות VTS
בדיקות VTS עבור Sensors HAL 2.0 ממוקמות ב-hardware/interfaces/sensors/2.0/vts.
בדיקות VTS עבור Sensors HAL 2.1 ממוקמות ב-hardware/interfaces/sensors/2.1/vts.
הבדיקות האלה מוודאות שה-HAL של החיישנים מוטמע בצורה תקינה ושהדרישות ב-ISensors.hal וב-ISensorsCallback.hal מתקיימות בצורה תקינה.
שדרוג ל-Sensors HAL 2.1 מגרסה 2.0
כשמשדרגים ל-Sensors HAL 2.1 מגרסה 2.0, הטמעת ה-HAL צריכה לכלול את השיטות initialize_2_1(), getSensorsList_2_1() ו-injectSensorsData_2_1(), יחד עם הסוגים של HAL 2.1. השיטות האלה צריכות לעמוד באותן דרישות שצוינו למעלה לגבי HAL 2.0.
ממשקי HAL בגרסאות משניות חייבים לתמוך בכל הפונקציות מממשקי HAL קודמים, ולכן ממשקי HAL בגרסה 2.1 חייבים לתמוך באתחול כממשקי HAL בגרסה 2.0. כדי להימנע מהמורכבות של תמיכה בשתי גרסאות HAL, מומלץ מאוד להשתמש ב-Multi-HAL 2.1.
דוגמה להטמעה של Sensors 2.1 HAL זמינה בכתובת Sensors.h.
שדרוג מ-Sensors HAL 1.0 ל-2.0
כשמשדרגים ל-Sensors HAL 2.0 מגרסה 1.0, צריך לוודא שההטמעה של HAL עומדת בדרישות הבאות.
אתחול ה-HAL
כדי ליצור תורי הודעות מהירים בין המסגרת לבין HAL, צריך לתמוך בפונקציה initialize().
חשיפה של חיישנים זמינים
ב-Sensors HAL 2.0, הפונקציה getSensorsList() חייבת להחזיר את אותו ערך במהלך אתחול יחיד של המכשיר, גם אם מתבצע אתחול מחדש של Sensors HAL. דרישה חדשה של הפונקציה getSensorsList() היא שהיא צריכה להחזיר את אותו ערך במהלך אתחול יחיד של המכשיר, גם אם מתבצעת הפעלה מחדש של Sensors HAL. כך, אם השרת של המערכת מופעל מחדש, המסגרת יכולה לנסות ליצור מחדש את החיבורים לחיישנים. הערך שמוחזר על ידי getSensorsList() יכול להשתנות אחרי שהמכשיר מופעל מחדש.
כתיבת אירועי חיישן ל-FMQ
במקום לחכות לקריאה של poll(), ב-Sensors HAL 2.0, Sensors HAL צריך לכתוב באופן יזום אירועי חיישן ל-Event FMQ בכל פעם שאירועי חיישן זמינים. ה-HAL אחראי גם לכתיבת הביטים הנכונים ל-EventFlag כדי לגרום לקריאת FMQ במסגרת.
אירועי WAKE_UP
ב-HAL 1.0 של חיישנים, ה-HAL יכול היה לשחרר את חסימת מצב השינה שלו לכל WAKE_UPאירוע בכל קריאה עוקבת ל-poll() אחרי ש-WAKE_UP פורסם ב-poll(), כי זה הצביע על כך שהמסגרת עיבדה את כל אירועי החיישן וקיבלה חסימת מצב שינה, אם היה צורך בכך. ב-Sensors HAL 2.0, HAL כבר לא יודע מתי המסגרת עיבדה אירועים שנכתבו ל-FMQ, ולכן ה-FMQ של Wake Lock מאפשר למסגרת לתקשר עם HAL כשהיא מטפלת באירועים של WAKE_UP.
ב-Sensors HAL 2.0, חסימת מצב השינה שמאובטחת על ידי Sensors HAL עבור אירועים WAKE_UPחייבת להתחיל ב-SensorsHAL_WAKEUP.
חיישנים דינמיים
חיישנים דינמיים הוחזרו באמצעות הפונקציה poll() ב-Sensors HAL 1.0.
ב-Sensors HAL 2.0, צריך לקרוא ל-onDynamicSensorsConnected ול-onDynamicSensorsDisconnected ב-ISensorsCallback בכל פעם שמשתנים חיבורים של חיישנים דינמיים. הקריאות החוזרות האלה זמינות כחלק מהמצביע ISensorsCallback שמסופק דרך הפונקציה initialize().
מצבי פעולה
חייבת להיות תמיכה במצב DATA_INJECTION של חיישני WAKE_UP ב-Sensors HAL
2.0.
תמיכה ב-Multi-HAL
Sensors HAL 2.0 ו-2.1 תומכים ב-multi-HAL באמצעות המסגרת Sensors Multi-HAL. פרטים על ההטמעה זמינים במאמר העברה מ-Sensors HAL 1.0.