ממשק ה-HAL של חיישנים, שמוצהר ב-sensors.h, מייצג את הממשק בין המסגרת של Android לבין התוכנה הספציפית לחומרה. הטמעת HAL חייבת להגדיר כל פונקציה שהוצהרה ב-sensors.h. הפונקציות העיקריות הן:
get_sensors_list
– הפונקציה מחזירה את הרשימה של כל החיישנים.activate
– הפעלה או השבתה של חיישן.batch
– הגדרת הפרמטרים של חיישן, כמו תדירות הדגימה וזמן האחזור המקסימלי לדיווח.setDelay
– משמש רק ב-HAL בגרסה 1.0. הגדרת תדירות הדגימה של חיישן נתון.flush
– שטיפה של ה-FIFO של החיישן שצוין, ודיווחה על אירוע של סיום השטיפה בסיום התהליך.poll
– הפונקציה מחזירה את אירועי החיישן הזמינים.
ההטמעה צריכה להיות בטוחה לשרשור ולאפשר להפעיל את הפונקציות האלה משרשוריים שונים.
הממשק מגדיר גם כמה סוגים שבהם נעשה שימוש בפונקציות האלה. הסוגים העיקריים הם:
sensors_module_t
sensors_poll_device_t
sensor_t
sensors_event_t
בנוסף לקטעים הבאים, מידע נוסף על הסוגים האלה זמין בקובץ sensors.h.
get_sensors_list(list)
int (*get_sensors_list)(struct sensors_module_t* module, struct sensor_t const** list);
רשימת החיישנים שהוטמעו על ידי HAL. פרטים על אופן ההגדרה של החיישנים זמינים במאמר sensor_t.
הסדר שבו החיישנים מופיעים ברשימה הוא הסדר שבו הם ידווחו לאפליקציות. בדרך כלל החיישנים הבסיסיים מופיעים קודם, ואחריהם החיישנים המשולבים.
אם כמה חיישנים משתפים את אותו סוג חיישן ואת אותו מאפיין התעוררות, החיישן הראשון ברשימה נקרא 'חיישן ברירת המחדל'. זהו הערך שמוחזר על ידי getDefaultSensor(int sensorType, bool wakeUp)
.
הפונקציה הזו מחזירה את מספר החיישנים ברשימה.
activate(sensor, true/false)
int (*activate)(struct sensors_poll_device_t *dev, int sensor_handle, int enabled);
הפעלה או השבתה של חיישן.
sensor_handle
הוא הכינוי של החיישן שרוצים להפעיל/להשבית. הידית של חיישן מוגדרת לפי השדה handle
במבנה sensor_t שלו.
כדי להפעיל את החיישן, מגדירים את enabled
לערך 1. כדי להשבית אותו, מגדירים את הערך 0.
חיישנים מסוג 'קליק אחד' משביתים את עצמם באופן אוטומטי כשהם מקבלים אירוע, אבל עדיין צריך לאשר את השבתתם באמצעות קריאה ל-activate(...,
enabled=0)
.
חיישנים ללא התעוררות לעולם לא מונעים מה-SoC לעבור למצב השהיה. כלומר, ה-HAL לא ישמור על נעילת התעוררות חלקית בשם האפליקציות.
חיישני התעוררות, כשהם שולחים אירועים באופן רציף, יכולים למנוע מה-SoC לעבור למצב השהיה, אבל אם אין צורך לשלוח אירוע, צריך לשחרר את נעילת ההתעוררות החלקית.
אם הערך של enabled
הוא 1 והחיישן כבר מופעל, הפונקציה הזו לא מבצעת פעולה כלשהי ומצליחה.
אם הערך של enabled
הוא 0 והחיישן כבר מושבת, הפונקציה הזו היא פעולה ללא תוצאה (no-op) והיא מסתיימת בהצלחה.
הפונקציה הזו מחזירה 0 אם הפעולה בוצעה בהצלחה, ומספר שגיאה שלילי אחרת.
batch(sensor, flags, sampling period, maximum report latency)
int (*batch)( struct sensors_poll_device_1* dev, int sensor_handle, int flags, int64_t sampling_period_ns, int64_t max_report_latency_ns);
הגדרת הפרמטרים של חיישן, כולל תדירות הדגימה וזמן האחזור המקסימלי של הדוח. אפשר להפעיל את הפונקציה הזו בזמן שהחיישן מופעל, אבל היא לא יכולה לגרום לאובדן מדידות של החיישן: המעבר משיעור דגימה אחד לשני לא יכול לגרום לאובדן אירועים, וגם המעבר מעיכוב דיווח מקסימלי גבוה לעיכוב דיווח מקסימלי נמוך לא יכול לגרום לכך.
sensor_handle
הוא הכינוי של החיישן שרוצים להגדיר.
flags
לא בשימוש כרגע.
sampling_period_ns
היא תקופת הדגימה שבה החיישן צריך לפעול, בננו-שניות. פרטים נוספים זמינים במאמר בנושא sampling_period_ns.
max_report_latency_ns
הוא הזמן המקסימלי שאפשר לעכב אירועים לפני שמדווחים עליהם דרך ה-HAL, בננו-שניות. פרטים נוספים זמינים בקטע max_report_latency_ns.
הפונקציה הזו מחזירה 0 אם הפעולה בוצעה בהצלחה, ומספר שגיאה שלילי אחרת.
setDelay(sensor, sampling period)
int (*setDelay)( struct sensors_poll_device_t *dev, int sensor_handle, int64_t sampling_period_ns);
אחרי HAL גרסה 1.0, הפונקציה הזו הוצאה משימוש ואף פעם לא נקראת.
במקום זאת, הפונקציה batch
נקראת כדי להגדיר את הפרמטר sampling_period_ns
.
ב-HAL בגרסה 1.0, השתמשו ב-setDelay במקום ב-batch כדי להגדיר את sampling_period_ns.
flush(sensor)
int (*flush)(struct sensors_poll_device_1* dev, int sensor_handle);
מוסיפים אירוע של סיום שטיפה לסוף ה-FIFO של החומרה עבור החיישן שצוין ומנקים את ה-FIFO. האירועים האלה נשלחים כרגיל (כלומר, כאילו פג תוקף זמן האחזור המקסימלי לדיווח) ומוסרים מה-FIFO.
השטיפה מתבצעת באופן אסינכרוני (כלומר, הפונקציה הזו חייבת לחזור מיד). אם ההטמעה משתמשת ב-FIFO יחיד למספר חיישנים, ה-FIFO הזה יתרוקן והאירוע 'סיום הריקון' יתווסף רק לחיישן שצוין.
אם לחיישן שצוין אין FIFO (לא ניתן לבצע אגירת נתונים), או אם ה-FIFO היה ריק בזמן הקריאה, הפונקציה flush
עדיין חייבת להצליח ולשלוח אירוע flush complete לחיישן הזה. הכלל הזה חל על כל החיישנים מלבד חיישנים מסוג 'צילום אחד'.
כשפונים ל-flush
, גם אם אירוע שטיפה כבר נמצא ב-FIFO של החיישן הזה, צריך ליצור אירוע נוסף ולהוסיף אותו לסוף ה-FIFO, וגם צריך לבצע שטיפה של ה-FIFO. מספר הקריאות ל-flush
חייב להיות שווה למספר האירועים של סיום השליפה שנוצרו.
flush
לא רלוונטי לחיישנים מסוג one-shot. אם sensor_handle
מתייחס לחיישן מסוג one-shot, flush
חייב להחזיר את הערך -EINVAL
ולא ליצור אירוע של שטיפה מלאה של המטא-נתונים.
הפונקציה הזו מחזירה 0 אם הפעולה בוצעה בהצלחה, -EINVAL
אם החיישן שצוין הוא חיישן חד-פעמי או לא הופעל, ומספר שגיאה שלילי במקרים אחרים.
poll()
int (*poll)(struct sensors_poll_device_t *dev, sensors_event_t* data, int
count);
הפונקציה מחזירה מערך של נתוני חיישנים על ידי מילוי הארגומנט data
. הפונקציה הזו חייבת לחסום עד שהאירועים יהיו זמינים. הפונקציה תחזיר את מספר האירועים שקרא בהצלחה, או מספר שגיאה שלילי במקרה של שגיאה.
מספר האירועים שמוחזרים ב-data
חייב להיות קטן מ-count
או שווה לו. הפונקציה הזו אף פעם לא תחזיר את הערך 0 (ללא אירוע).
רצף השיחות
כשהמכשיר מופעל, מתבצעת קריאה ל-get_sensors_list
.
כשחיישן מופעל, הפונקציה batch
תופעל עם הפרמטרים המבוקשים, ואחריה activate(..., enable=1)
.
שימו לב שבגרסה 1_0 של HAL, הסדר היה הפוך: activate
הופעל קודם, ואחריו set_delay
.
כשהמאפיינים המבוקשים של חיישן משתנים בזמן שהוא מופעל, מתבצעת קריאה לפונקציה batch
.
אפשר להפעיל את flush
בכל שלב, גם בחיישנידים לא מופעלים (במקרה כזה, הפונקציה חייבת להחזיר את הערך -EINVAL
).
כשחיישן מושבת, מתבצעת קריאה ל-activate(..., enable=0)
.
במקביל לקריאות האלה, הפונקציה poll
תופעל שוב ושוב כדי לבקש נתונים. אפשר להפעיל את poll
גם אם אין חיישנים מופעלים.
sensors_module_t
sensors_module_t
הוא הסוג שמשמש ליצירת מודול החומרה של Android לחיישנים. ההטמעה של ה-HAL חייבת להגדיר אובייקט HAL_MODULE_INFO_SYM
מהסוג הזה כדי לחשוף את הפונקציה get_sensors_list. מידע נוסף זמין בהגדרה של sensors_module_t
בקובץ sensors.h ובהגדרה של hw_module_t
.
sensors_poll_device_t / sensors_poll_device_1_t
sensors_poll_device_1_t
מכיל את שאר השיטות שהוגדרו למעלה:
activate
, batch
, flush
וגם
poll
. השדה common
(מסוג hw_device_t) מגדיר את מספר הגרסה של ה-HAL.
sensor_t
sensor_t
מייצג חיישן Android. אלה כמה מהשדות החשובים שלו:
name: מחרוזת שגלויה למשתמש ומייצגת את החיישן. המחרוזת הזו מכילה לרוב את שם החלק של החיישן הבסיסי, את סוג החיישן ואת העובדה שהוא חיישן התעוררות. לדוגמה, 'LIS2HH12 Accelerometer', 'MAX21000 Uncalibrated Gyroscope', 'BMP280 Wake-up Barometer', 'MPU6515 Game Rotation Vector'
handle: המספר השלם שמשמש להפניה לחיישן בזמן ההרשמה אליו או בזמן יצירת אירועים ממנו.
type: סוג החיישן. למידע נוסף, אפשר לעיין בהסבר על סוג החיישן במאמר מהם חיישני Android?. בסוגי חיישנים מפורטים סוגי החיישנים הרשמיים. בסוגים לא רשמיים של חיישנים, השדה type
חייב להתחיל ב-SENSOR_TYPE_DEVICE_PRIVATE_BASE
stringType: סוג החיישן כמחרוזת. אם לסוג החיישן יש סוג רשמי, מגדירים אותו כ-SENSOR_STRING_TYPE_*
. כשלחיישן יש סוג ספציפי ליצרן, השדה stringType
חייב להתחיל בשם הדומיין ההפוך של היצרן. לדוגמה, חיישן (למשל, גלאי חד-קרן) שהוגדר על ידי הצוות Cool-product בחברת Fictional-Company יכול להשתמש ב-stringType=”com.fictional_company.cool_product.unicorn_detector”
.
השדה stringType
משמש לזיהוי ייחודי של סוגים של חיישנים לא רשמיים. למידע נוסף על סוגי מחרוזות וסוגים אחרים, אפשר לעיין בקובץ sensors.h.
requiredPermission: מחרוזת שמייצגת את ההרשאה שצריכה להיות לאפליקציות כדי לראות את החיישן, להירשם אליו ולקבל את הנתונים שלו. אם המחרוזת ריקה, לאפליקציות לא נדרשת הרשאה כלשהי כדי לגשת לחיישן הזה. לחלק מסוגי החיישנים, כמו מכשיר למדידת קצב הלב, יש requiredPermission
חובה. כל החיישנים שמספקים מידע אישי רגיש (כמו קצב הלב) חייבים להיות מוגנים באמצעות הרשאה.
flags: דגלים של החיישן הזה, שמגדירים את מצב הדיווח של החיישן ואת העובדה שהוא חיישן התעוררות או לא. לדוגמה, לחיישן התעוררות חד-פעמי יהיה flags = SENSOR_FLAG_ONE_SHOT_MODE | SENSOR_FLAG_WAKE_UP
. צריך להשאיר את הביטים של הדגל שלא בשימוש בגרסה הנוכחית של HAL שווים ל-0.
maxRange: הערך המקסימלי שהחיישן יכול לדווח, באותה יחידה שבה מדווחים הערכים. חיישן צריך להיות מסוגל לדווח על ערכים בלי שתהיה לו רוויה תוך [-maxRange; maxRange]
. שימו לב: המשמעות היא שהטווח הכולל של החיישן במובן הכללי הוא 2*maxRange
. כשהחיישן מדווח על ערכים בכמה צירים, הטווח חל על כל ציר. לדוגמה, מד תאוצה עם טווח תנודות של +/- 2g ידווח על maxRange = 2*9.81 = 2g
.
רזולוציה: ההבדל הקטן ביותר בערך שהחיישן יכול למדוד.
בדרך כלל מחושב על סמך maxRange
ומספר הביטים במדידה.
power: עלות האנרגיה להפעלת החיישן, במיליאמפר.
הערך הזה תמיד גבוה יותר מצריכת החשמל שמדווחת בגיליון הנתונים של החיישן הבסיסי. פרטים נוספים זמינים במאמר חיישנים בסיסיים הם לא חיישנים פיזיים, ובמאמר תהליך מדידת צריכת החשמל מוסבר איך מודדים את צריכת החשמל של חיישן.
אם צריכת החשמל של החיישן תלויה בתנועה של המכשיר, צריכת החשמל בזמן התנועה היא זו שמדווחת בשדה power
.
minDelay: בחיישנים רצופיים, תקופת הדגימה, במיקרו-שניות, שמתאימה לשיעור המהיר ביותר שהחיישן תומך בו. פרטים על אופן השימוש בערך הזה מופיעים בקטע sampling_period_ns. חשוב לזכור ש-minDelay
מופיע ביחידות מיקרו-שנייה, ואילו sampling_period_ns
מופיע ביחידות ננו-שנייה. בחיישנים של דיווח בזמן שינוי ובמצב דיווח מיוחד, אלא אם צוין אחרת, הערך של minDelay
חייב להיות 0. בחיישנים מסוג 'קליק אחד', הערך חייב להיות -1.
maxDelay: בחיישנים רצויים בחיישנים שמתעדכנים בזמן אמת, תקופת הדגימה, במיקרו-שניות, שתואמת לשיעור האיטי ביותר שהחיישן תומך בו. פרטים על אופן השימוש בערך הזה מופיעים בקטע sampling_period_ns. חשוב לזכור ש-maxDelay
מופיע ביחידות מיקרו-שנייה, ואילו sampling_period_ns
מופיע ביחידות ננו-שנייה. לחיישנים מיוחדים ולחיישנים מסוג 'קליק אחד', הערך של maxDelay
חייב להיות 0.
fifoReservedEventCount: מספר האירועים ששמורים לחיישן הזה ב-FIFO של החומרה. אם יש FIFO ייעודי לחיישן הזה, הערך של fifoReservedEventCount
הוא הגודל של ה-FIFO הייעודי הזה. אם ה-FIFO משותף עם חיישנים אחרים, הערך של fifoReservedEventCount
הוא הגודל של החלק ב-FIFO ששמור לאותו חיישן. ברוב המערכות המשותפות של FIFO, ובמערכות שאין בהן FIFO בחומרה, הערך הזה הוא 0.
fifoMaxEventCount: המספר המקסימלי של אירועים שאפשר לאחסן במאגרי ה-FIFO של החיישן הזה. הערך הזה תמיד גדול מ-fifoReservedEventCount
או שווה לו. הערך הזה משמש להערכת המהירות שבה ה-FIFO יאוכלס כשרושמים לחיישן בקצב ספציפי, בהנחה שאין חיישנים אחרים שפועלים. במערכות ללא FIFO בחומרה, הערך של fifoMaxEventCount
הוא 0. פרטים נוספים זמינים במאמר אוסף בקשות.
בחיישני סוג רשמי, חלק מהשדות נכתבים מחדש על ידי המסגרת. לדוגמה, חיישנים של מד תאוצה חייבים לפעול במצב דיווח רציף, ומוניטורים של קצב הלב חייבים להיות מוגנים באמצעות ההרשאה SENSOR_PERMISSION_BODY_SENSORS
.
sensors_event_t
אירועי חיישנים שנוצרו על ידי חיישני Android ודווחו באמצעות הפונקציה poll הם מסוג type sensors_event_t
. אלה כמה שדות חשובים של sensors_event_t
:
version: חייבת להיות sizeof(struct sensors_event_t)
sensor: הכינוי של החיישן שיצר את האירוע, כפי שמוגדר ב-sensor_t.handle
.
type: סוג החיישן של החיישן שיצר את האירוע, כפי שמוגדר ב-sensor_t.type
.
timestamp: חותמת הזמן של האירוע בננו-שניות. זו השעה שבה האירוע התרחש (צעד שנעשה או מדידה של תאוצה), ולא השעה שבה האירוע דווח. timestamp
חייב להיות מסונכרן עם השעון elapsedRealtimeNano
, ובמקרה של חיישנים רצויים, התנודות חייבות להיות קטנות. לפעמים צריך לסנן את חותמות הזמן כדי לעמוד בדרישות של CDD, כי שימוש רק בזמן ההפרעה של SoC כדי להגדיר את חותמות הזמן גורם לתנודות גבוהות מדי, ושימוש רק בזמן של צ'יפ החיישן כדי להגדיר את חותמות הזמן עלול לגרום לניתוק מסנכרון עם השעון elapsedRealtimeNano
, כי שעון החיישן נע.
data ושדות חופפים: הערכים שנמדדים על ידי החיישן. המשמעות והיחידות של השדות האלה ספציפיות לכל סוג חיישן. תיאור של שדות הנתונים מופיע בקובץ sensors.h ובהגדרה של סוגי החיישנים השונים. בחלק מהחיישנים, הדיוק של הקריאות מדווח גם כחלק מהנתונים, באמצעות השדה status
. השדה הזה מועבר רק לסוגי החיישנים שנבחרו, ומופיע בשכבת ה-SDK כערך של הדיוק. לגבי החיישנים האלה, העובדה שצריך להגדיר את שדה הסטטוס מופיעה בהגדרה של סוג החיישן.
אירועים של סיום שטיפה של מטא-נתונים
סוג האירועים של המטא-נתונים זהה לסוג של אירועי חיישנים רגילים:
sensors_event_meta_data_t = sensors_event_t
. הם מוחזרים יחד עם אירועי חיישנים אחרים באמצעות סקרים. הם מכילים את השדות הבאים:
version: חייבת להיות META_DATA_VERSION
type: חייב להיות SENSOR_TYPE_META_DATA
sensor, reserved ו-timestamp: חייבים להיות 0
meta_data.what: מכיל את סוג המטא-נתונים של האירוע הזה. נכון לעכשיו יש סוג מטא-נתונים תקין אחד: META_DATA_FLUSH_COMPLETE
.
אירועי META_DATA_FLUSH_COMPLETE
מייצגים את השלמת השטיפה של FIFO של חיישן. כשהערך של meta_data.what=META_DATA_FLUSH_COMPLETE
הוא 1, צריך להגדיר את הערך של meta_data.sensor
כ-handle של החיישן שעבר שטיפה. הם נוצרים רק כשמתבצעת קריאה ל-flush
באחד מהחיישנים. מידע נוסף זמין בקטע flush.