שכבת ההפשטה של חומרת החיישנים (HAL) היא הממשק בין מסגרת החיישנים של Android לבין חיישני המכשיר, כמו מד תאוצה או ג'ירוסקופ. ב-HAL של החיישנים מוגדרות הפונקציות שצריך להטמיע כדי לאפשר למסגרת לשלוט בחיישנים.
ה-HAL של Sensors AIDL זמין ב-Android מגרסה 13 ואילך במכשירים חדשים ובמכשירים משודרגים. Sensors AIDL HAL, שמבוסס על Sensors HAL 2.1, משתמש בממשק AIDL HAL ומציג את סוגי חיישני ה-IMU למעקב אחר תנועות הראש וסוגי חיישני ה-IMU עם צירים מוגבלים.
ממשק AIDL HAL
מקור המסמכים העיקרי של HAL של Sensors AIDL נמצא בהגדרת ה-HAL בקובץ hardware/interfaces/sensors/aidl/android/hardware/sensors/ISensors.aidl.
הטמעת HAL של Sensors AIDL
כדי להטמיע את HAL של Sensors AIDL, אובייקט צריך להרחיב את הממשק ISensors
ולהטמיע את כל הפונקציות שמוגדרות ב-hardware/interfaces/sensors/aidl/android/hardware/sensors/ISensors.aidl.
אתחול ה-HAL
כדי שאפשר יהיה להשתמש ב-HAL של החיישנים, מסגרת החיישנים של Android צריכה לאתחל אותו. המסגרת קוראת לפונקציה initialize()
כדי לספק שלושה פרמטרים ל-HAL של החיישנים: שני מתארי FMQ ו-pointer אחד לאובייקט ISensorsCallback
.
ה-HAL משתמש בתיאור הראשון כדי ליצור את ה-Event FMQ שמשמש לכתיבת אירועי חיישנים למסגרת. ה-HAL משתמש במתאר השני כדי ליצור את ה-FMQ של Wake Lock, שמשמשים לסנכרון כשה-HAL משחרר את נעילת ההתעוררות שלו לאירועי חיישן WAKE_UP
. ה-HAL חייב לשמור מצביע לאובייקט ISensorsCallback
כדי שאפשר יהיה להפעיל את כל פונקציות ההתקשרות החוזרת הנדרשות.
הפונקציה initialize()
חייבת להיות הפונקציה הראשונה שנקראת במהלך האיפוס של Sensors HAL.
חשיפת החיישנים הזמינים
כדי לקבל רשימה של כל החיישנים הסטטיים הזמינים במכשיר, משתמשים בפונקציה getSensorsList()
. הפונקציה הזו מחזירה רשימה של חיישנים, וכל אחד מהם מזוהה באופן ייחודי לפי הכינוי שלו. ה-handle של חיישן נתון לא יכול להשתנות כשהתהליך שמארח את Sensors HAL מתחיל מחדש. הכינוי עשוי להשתנות אחרי הפעלה מחדש של המכשיר או אחרי הפעלה מחדש של שרת המערכת.
אם כמה חיישנים חולקים את אותו סוג חיישן ואת אותה מאפיין התעוררות, החיישן הראשון ברשימה נקרא חיישן ברירת המחדל והוא מוחזר לאפליקציות שמשתמשות בפונקציה getDefaultSensor(int sensorType, bool wakeUp)
.
יציבות רשימת החיישנים
אחרי הפעלה מחדש של Sensors HAL, אם הנתונים שמוחזרים על ידי getSensorsList()
מצביעים על שינוי משמעותי בהשוואה לרשימת החיישנים שאוחזרה לפני ההפעלה מחדש, המסגרת מפעילה הפעלה מחדש של סביבת זמן הריצה של Android. שינויים משמעותיים ברשימת החיישנים כוללים מקרים שבהם חיישן עם כינוי נתון חסר או שהמאפיינים שלו השתנו, או מקרים שבהם נוספו חיישנים חדשים. הפעלה מחדש של סביבת זמן הריצה של Android מפריעה למשתמש, אבל היא נדרשת כי מסגרת Android כבר לא יכולה לעמוד בתנאי החוזה של Android API, שלפיו חיישני סטטיים (לא דינמיים) לא משתנים במהלך מחזור החיים של אפליקציה. כתוצאה מכך, יכול להיות שהמסגרת לא תוכל ליצור מחדש בקשות חיישנים פעילות שנשלחות על ידי אפליקציות. לכן, מומלץ לספקים של HAL למנוע שינויים ברשימת החיישנים שאפשר להימנע מהם.
כדי להבטיח שמזהי החיישנים יהיו יציבים, ה-HAL צריך למפות באופן דטרמיניסטי חיישן פיזי נתון במכשיר למזהה שלו. ממשק ה-HAL של חיישנים לא מחייב הטמעה ספציפית, אבל למפתחים יש כמה אפשרויות שעומדות בדרישות האלה.
לדוגמה, אפשר למיין את רשימת החיישנים לפי שילוב של המאפיינים הקבועים של כל חיישן, כמו ספק, דגם וסוג חיישן. אפשרות אחרת מבוססת על העובדה שקבוצת החיישנים הסטטיים של המכשיר קבועה בחומרה, ולכן ה-HAL צריך לדעת מתי כל החיישנים הצפויים השלימו את האיפוס לפני שהוא חוזר מ-getSensorsList()
. אפשר לקמפל את הרשימה הזו של חיישנים צפויים לקובץ הבינארי של 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.
ה-HAL של Sensors AIDL תומך גם ב-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 של החיישנים. אפשר גם להשתמש בפונקציה כדי להחדיר אירועי חיישן לחיישן ספציפי.
אימות
כדי לאמת את ההטמעה של 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 של HAL של Sensors AIDL נמצאות ב-hardware/interfaces/sensors/aidl/vts/.
הבדיקות האלה מבטיחות שה-HAL של החיישנים מוטמע כראוי ושכל הדרישות ב-ISensors.aidl
וב-ISensorsCallback.aidl
מתקיימות.
אתחול ה-HAL
צריכה להיות תמיכה בפונקציה initialize()
כדי ליצור FMQs בין המסגרת ל-HAL.
חשיפת החיישנים הזמינים
ב-HAL של Sensors AIDL, הפונקציה getSensorsList()
חייבת להחזיר את אותו ערך במהלך הפעלה אחת של המכשיר, גם במהלך הפעלות מחדש של HAL של Sensors. דרישה חדשה לפונקציה getSensorsList()
היא שהיא חייבת להחזיר את אותו ערך במהלך הפעלה של מכשיר יחיד, גם במהלך הפעלות מחדש של Sensors HAL. כך המערכת תוכל לנסות ליצור מחדש את החיבורים לחיישנים אם שרת המערכת יופעל מחדש. הערך שמוחזר על ידי getSensorsList()
יכול להשתנות אחרי שהמכשיר מופעל מחדש.
כתיבת אירועי חיישנים ב-FMQ
במקום להמתין לקריאה ל-poll()
, ב-HAL של Sensors AIDL, ה-HAL של Sensors חייב לכתוב באופן יזום אירועי חיישנים ל-FMQ של האירועים בכל פעם שאירועי חיישנים זמינים. ה-HAL אחראי גם לכתוב את הביטים הנכונים ל-EventFlag
כדי לגרום לקריאה של FMQ במסגרת.
אירועי WAKE_UP
ב-Sensors HAL 1.0, ה-HAL יכול היה לשחרר את נעילת ההתעוררות שלו לכל אירוע WAKE_UP
בכל קריאה חוזרת ל-poll()
אחרי ש-WAKE_UP
פורסם ב-poll()
, כי הדבר סימן שהמסגרת עיבד את כל אירועי החיישן וקיבל נעילת התעוררות, אם היה צורך. מכיוון שב-HAL של Sensors AIDL, ה-HAL כבר לא מקבל התראה כשהמסגרת מעבדת אירועים שנכתבו ב-FMQ, ה-FMQ של Wake Lock מאפשר למסגרת לתקשר עם ה-HAL כשהיא מטפלת באירועי WAKE_UP
.
ב-HAL של Sensors AIDL, נעילת ההתעוררות שמאובטחת על ידי ה-HAL של Sensors לאירועים מסוג WAKE_UP
חייבת להתחיל ב-SensorsHAL_WAKEUP
.
חיישנים דינמיים
חיישנים דינמיים הוחזרו באמצעות הפונקציה poll()
ב-Sensors HAL 1.0.
ב-Sensors AIDL HAL נדרש לקרוא ל-onDynamicSensorsConnected
ול-onDynamicSensorsDisconnected
ב-ISensorsCallback
בכל פעם שמשתנים החיבורים הדינמיים לחיישנים. פונקציות הקריאה החוזרת האלה זמינות כחלק מהצבען ISensorsCallback
שסופק באמצעות הפונקציה initialize()
.
מצבי הפעולה
חייבת להיות תמיכה במצב DATA_INJECTION
לחיישנים מסוג WAKE_UP
.
תמיכה במספר ממשקי HAL
ה-HAL של Sensors AIDL תומך ב-HAL מרובה באמצעות המסגרת של Sensors Multi-HAL. פרטי ההטמעה מפורטים במאמר העברה מ-Sensors HAL 2.1.