שכבת ההפשטה של חומרת החיישנים (HAL) היא הממשק בין מסגרת החיישנים של Android לבין חיישני המכשיר, כמו מד תאוצה או ג'ירוסקופ. ב-HAL של החיישנים מוגדרות הפונקציות שצריך להטמיע כדי לאפשר למסגרת לשלוט בחיישנים.
Sensors HAL 2.0 זמין ב-Android 10 ואילך במכשירים חדשים ומשודרגים. Sensors HAL 2.0 מבוסס על Sensors HAL 1.0, אבל יש כמה הבדלים עיקריים שמונעים ממנו להיות תואם לאחור. ב-Sensors HAL 2.0 נעשה שימוש בQueues Message Fast (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 כדי לספק שלושה פרמטרים ל-HAL של החיישנים: שני מתארי FMQ ו-pointer אחד לאובייקט ISensorsCallback
.
ה-HAL משתמש בתיאור הראשון כדי ליצור את ה-Event FMQ שמשמש לכתיבת אירועי חיישנים למסגרת. ה-HAL משתמש במתאר השני כדי ליצור את ה-FMQ של Wake Lock, שמשמשים לסנכרון כשה-HAL משחרר את נעילת ההתעוררות שלו לאירועי חיישן WAKE_UP
. ה-HAL חייב לשמור מצביע לאובייקט ISensorsCallback
כדי שאפשר יהיה להפעיל את כל פונקציות ההתקשרות החוזרת הנדרשות.
הפונקציה initialize()
או initialize_2_1()
חייבת להיות הפונקציה הראשונה שנקראת במהלך האיפוס של Sensors HAL.
חשיפת החיישנים הזמינים
כדי לקבל רשימה של כל החיישנים הסטטיים הזמינים במכשיר, משתמשים בפונקציה getSensorsList()
ב-HAL 2.0 ובפונקציה getSensorsList_2_1()
ב-HAL 2.1. הפונקציה הזו מחזירה רשימה של חיישנים, וכל אחד מהם מזוהה באופן ייחודי לפי הכינוי שלו. ה-handle של חיישן נתון לא יכול להשתנות כשהתהליך שמארח את Sensors HAL מופעל מחדש. הכינויים עשויים להשתנות לאחר הפעלה מחדש של המכשיר, וגם לאחר הפעלה מחדש של שרת המערכת.
אם כמה חיישנים חולקים את אותו סוג חיישן ואת אותה מאפיין התעוררות, החיישן הראשון ברשימה נקרא חיישן ברירת המחדל והוא מוחזר לאפליקציות שמשתמשות בפונקציה getDefaultSensor(int sensorType, bool wakeUp)
.
יציבות רשימת החיישנים
אחרי הפעלה מחדש של Sensors HAL, אם הנתונים שמוחזרים על ידי getSensorsList()
או getSensorsList_2_1()
מצביעים על שינוי משמעותי בהשוואה לרשימת החיישנים שאוחזרה לפני ההפעלה מחדש, המסגרת מפעילה הפעלה מחדש של סביבת זמן הריצה של Android. שינויים משמעותיים ברשימת החיישנים כוללים מקרים שבהם חיישן עם כינוי נתון חסר או שהמאפיינים שלו השתנו, או מקרים שבהם נוספו חיישנים חדשים. הפעלה מחדש של סביבת זמן הריצה של Android מפריעה למשתמש, אבל היא נדרשת כי מסגרת Android כבר לא יכולה לעמוד בתנאי החוזה של Android API, שלפיו חיישני סטטיים (לא דינמיים) לא משתנים במהלך מחזור החיים של אפליקציה. כתוצאה מכך, יכול להיות שהמסגרת לא תוכל ליצור מחדש בקשות חיישנים פעילות שנשלחות על ידי אפליקציות. לכן, מומלץ לספקים של HAL למנוע שינויים ברשימת החיישנים שאפשר להימנע מהם.
כדי להבטיח שמזהי החיישנים יהיו יציבים, ה-HAL צריך למפות באופן דטרמיניסטי חיישן פיזי נתון במכשיר למזהה שלו. ממשק ה-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()
.
אחרי שהחיישן יושבת, אסור לכתוב אירועי חיישן נוספים מהחיישן הזה ל-Event FMQ.
חיישני שטיפה
אם חיישן מוגדר לאסוף נתונים בקבוצות, אפשר להפעיל את flush()
כדי לאלץ את המסגרת לבצע שטיפה מיידית של אירועי חיישנים שנאספו בקבוצות. כתוצאה מכך, אירועי החיישן שנצברו בקבוצה עבור ה-handle של החיישן שצוין נכתבים באופן מיידי ב-Event FMQ. HAL של החיישנים חייב לצרף אירוע של סיום שטיפה לסוף אירועי החיישנים שנכתבים כתוצאה מהקריאה ל-flush()
.
השטיפה מתבצעת באופן אסינכרוני (כלומר, הפונקציה הזו חייבת לחזור מיד). אם ההטמעה משתמשת ב-FIFO יחיד למספר חיישנים, ה-FIFO הזה יתרוקן והאירוע 'סיום הריקון' יתווסף רק לחיישן שצוין.
אם לחיישן שצוין אין FIFO (לא ניתן לבצע אגירת נתונים), או אם ה-FIFO היה ריק בזמן הקריאה, הפונקציה flush()
עדיין חייבת להצליח ולשלוח אירוע flush complete לחיישן הזה. הכלל הזה חל על כל החיישנים מלבד חיישנים מסוג 'צילום אחד'.
אם flush()
נקרא לחיישן של זריקה אחת, הפונקציה flush()
חייבת להחזיר את הערך BAD_VALUE
ולא ליצור אירוע של סיום שטיפה.
כתיבת אירועי חיישנים ב-FMQ
Sensors HAL משתמש ב-Event FMQ כדי לדחוף אירועי חיישנים למסגרת החיישנים של 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
. הדגל הזה מוגדר על ידי המסגרת כשהיא קוראת אירועים מ-Event FMQ. צריך להגדיר את הדגל של התראת הכתיבה לערך EventQueueFlagBits::READ_AND_PROCESS
, כדי להודיע למסגרת שהאירועים נכתבו ב-Event FMQ.
אירועי WAKE_UP
אירועי WAKE_UP
הם אירועי חיישן שגורמים למעבד האפליקציות (AP) להתעורר ולטפל באירוע באופן מיידי. בכל פעם שאירוע WAKE_UP
נכתב ב-Event FMQ, HAL של החיישנים צריך לאבטח את נעילת ההתעוררות כדי לוודא שהמערכת תישאר במצב פעיל עד שהמסגרת תוכל לטפל באירוע. כשמתקבל אירוע WAKE_UP
, המסגרת מאבטחת את נעילת ההתעוררות שלה, ומאפשרת ל-HAL של החיישנים לשחרר את נעילת ההתעוררות שלו. כדי לסנכרן את האירוע שבו ה-HAL של החיישנים משחרר את נעילת ההתעוררות, משתמשים ב-Wake Lock FMQ.
HAL של החיישנים צריך לקרוא את FMQ של Wake Lock כדי לקבוע את מספר האירועים מסוג WAKE_UP
שהמסגרת טיפלה בהם. ה-HAL צריך לשחרר את נעילת ההתעוררות שלו רק לאירועי WAKE_UP
אם המספר הכולל של אירועי WAKE_UP
שלא טופלו הוא אפס.
אחרי הטיפול באירועי חיישנים, המסגרת סופרת את מספר האירועים שמסומנים כאירועי WAKE_UP
ומזינה את המספר הזה בחזרה ל-FMQ של Wake Lock.
המסגרת מגדירה את ההתראה WakeLockQueueFlagBits::DATA_WRITTEN
על הכתיבה ב-Wake Lock FMQ בכל פעם שהיא כותבת נתונים ב-Wake Lock FMQ.
חיישנים דינמיים
חיישנים דינמיים הם חיישנים שלא נכללים פיזית במכשיר, אבל אפשר להשתמש בהם כקלט למכשיר, כמו גיימפאד עם מד תאוצה.
כשחיישן דינמי מחובר, צריך לקרוא לפונקציה onDynamicSensorConnected
ב-ISensorsCallback
מ-HAL של החיישנים. כך המערכת תודיע למסגרת על החיישן הדינמי החדש, ותאפשר לשלוט בחיישן דרך המסגרת ולאפשר ללקוחות לצרוך את האירועים של החיישן.
באופן דומה, כשחיישן דינמי מנותק, צריך להפעיל את הפונקציה onDynamicSensorDisconnected
ב-ISensorsCallback
כדי שהמסגרת תוכל להסיר כל חיישן שלא זמין יותר.
ערוץ ישיר
ערוץ ישיר הוא שיטת הפעלה שבה אירועי חיישנים נכתבים בזיכרון ספציפי במקום ב-Event FMQ, ועוקפים את Android Sensors Framework. לקוח שמירשם ערוץ ישיר צריך לקרוא את אירועי החיישן ישירות מהזיכרון ששימש ליצירת הערוץ הישיר, ולא יקבל את אירועי החיישן דרך המסגרת. הפונקציה configDirectReport()
דומה לפונקציה batch()
במצב עבודה רגיל, והיא קובעת את ערוץ הדיווח הישיר.
הפונקציות registerDirectChannel()
ו-unregisterDirectChannel()
יוצרות או משמידות שיחה ישירה חדשה.
מצבי הפעולה
הפונקציה setOperationMode()
מאפשרת למסגרת להגדיר חיישן כדי שהיא תוכל להחדיר נתוני חיישן לתוך החיישן. האפשרות הזו שימושית לבדיקה, במיוחד של אלגוריתמים שנמצאים מתחת למסגרת.
בדרך כלל משתמשים בפונקציה injectSensorData()
ב-HAL 2.0 ובפונקציה injectSensorsData_2_1()
ב-HAL 2.0 כדי לדחוף פרמטרים תפעוליים ל-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.0 ל-2.1
כשמשדרגים מ-HAL 2.0 ל-HAL 2.1 של חיישנים, הטמעת ה-HAL צריכה לכלול את השיטות initialize_2_1()
, getSensorsList_2_1()
ו-injectSensorsData_2_1()
, יחד עם הסוגים של HAL 2.1. השיטות האלה צריכות לעמוד באותן הדרישות שמפורטות למעלה לגבי HAL 2.0.
מאחר ש-HAL בגרסה משנית חייב לתמוך בכל הפונקציות מ-HALs קודמים, HAL בגרסה 2.1 חייב לתמוך בהפעלה כ-HAL בגרסה 2.0. כדי להימנע מהמורכבות של תמיכה בשתי הגרסאות של HAL, מומלץ מאוד להשתמש ב-Multi-HAL 2.1.
דוגמה להטמעת HAL של Sensors 2.1 משלכם מופיעה בקובץ Sensors.h.
שדרוג מ-Sensors HAL 1.0 ל-2.0
כשמשדרגים מ-Sensors HAL 1.0 ל-2.0, חשוב לוודא שההטמעה של HAL עומדת בדרישות הבאות.
אתחול ה-HAL
צריכה להיות תמיכה בפונקציה initialize()
כדי ליצור FMQs בין המסגרת ל-HAL.
חשיפת החיישנים הזמינים
ב-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
ב-Sensors HAL 1.0, ה-HAL יכול היה לשחרר את נעילת ההתעוררות שלו לכל אירוע WAKE_UP
בכל קריאה חוזרת ל-poll()
אחרי ש-WAKE_UP
פורסם ב-poll()
, כי הדבר סימן שהמסגרת עיבד את כל אירועי החיישן וקיבל נעילת התעוררות, אם היה צורך. מכיוון שב-Sensors HAL 2.0, ה-HAL כבר לא יודע מתי המסגרת עיבד אירועים שנכתבו ב-FMQ, ה-Wake Lock FMQ מאפשר למסגרת לתקשר עם ה-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.
תמיכה במספר ממשקי HAL
ב-Sensors HAL 2.0 ו-2.1 יש תמיכה במספר ממשקי HAL באמצעות המסגרת של Sensors Multi-HAL. פרטי ההטמעה מפורטים במאמר העברה מ-Sensors HAL 1.0.