ממשק ה-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 של החיישן מוגדר על ידי השדה handle
במבנה sensor_t.
הערך של enabled
הוא 1 כדי להפעיל את החיישן או 0 כדי להשבית אותו.
חיישנים חד-פעמיים מושבתים אוטומטית אחרי קבלת אירוע,
ועדיין צריך לאשר את ההשבתה שלהם באמצעות קריאה ל-activate(...,
enabled=0)
.
חיישנים שלא מעוררים את המערכת אף פעם לא מונעים את המעבר של ה-SoC למצב השהיה. כלומר, שכבת ה-HAL לא יכולה להחזיק נעילת השכמה חלקית בשם האפליקציות.
חיישני התעוררות, כשמספקים אירועים באופן רציף, יכולים למנוע את המעבר של ה-SoC למצב השהיה, אבל אם אין צורך לספק אירוע, צריך לשחרר את נעילת ההתעוררות החלקית.
אם הערך של enabled
הוא 1 והחיישן כבר הופעל, הפונקציה הזו לא מבצעת פעולה ומצליחה.
אם הערך של enabled
הוא 0 והחיישן כבר מושבת, הפונקציה הזו לא מבצעת פעולה ומצליחה.
הפונקציה הזו מחזירה 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
הוא ה-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
.
בגרסה 1.0 של HAL, נעשה שימוש ב-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
, גם אם אירוע flush כבר נמצא ב-FIFO של החיישן, צריך ליצור אירוע נוסף ולהוסיף אותו לסוף ה-FIFO, ולבצע flush ל-FIFO. מספר הקריאות flush
חייב להיות שווה למספר האירועים של סיום השמירה שנוצרו.
flush
לא חל על חיישנים חד-פעמיים. אם sensor_handle
מתייחס לחיישן חד-פעמי, 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
מכיל את שאר ה-methods שמוגדרים למעלה:
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: ה-handle של החיישן שיצר את האירוע, כפי שמוגדר ב-sensor_t.handle
.
type: סוג החיישן שיצר את האירוע, כפי שמוגדר ב-sensor_t.type
.
timestamp: חותמת הזמן של האירוע בננו-שניות. זהו הזמן שבו האירוע קרה (בוצע שלב או בוצעה מדידה של מד התאוצה), ולא הזמן שבו האירוע דווח. השעון timestamp
צריך להיות מסונכרן עם השעון elapsedRealtimeNano
, ובמקרה של חיישנים רציפים, ה-jitter צריך להיות קטן. לפעמים צריך לסנן את חותמות הזמן כדי לעמוד בדרישות של CDD, כי שימוש רק בזמן ההפסקה של SoC כדי להגדיר את חותמות הזמן גורם לשינויים גדולים מדי בזמן ההשהיה, ושימוש רק בזמן של שבב החיישן כדי להגדיר את חותמות הזמן עלול לגרום לביטול הסנכרון מהשעון של elapsedRealtimeNano
, כי השעון של החיישן סוטה.
נתונים ושדות חופפים: הערכים שנמדדים על ידי החיישן. המשמעות והיחידות של השדות האלה הן ספציפיות לכל סוג של חיישן. בקטע sensors.h ובקטע ההגדרה של סוגי החיישנים יש תיאור של שדות הנתונים. בחלק מהחיישנים, גם רמת הדיוק של הקריאות מדווחת כחלק מהנתונים, דרך שדה status
. השדה הזה מועבר רק עבור סוגי החיישנים הנבחרים האלה, ומופיע בשכבת ה-SDK כערך דיוק. העובדה שצריך להגדיר את שדה הסטטוס בחיישנים האלה מצוינת בהגדרה של סוג החיישן.
אירועים של השלמת העברת מטא-נתונים
הסוג של אירועי מטא-נתונים זהה לסוג של אירועים רגילים של חיישנים:
sensors_event_meta_data_t = sensors_event_t
. הם מוחזרים יחד עם אירועים אחרים של חיישנים באמצעות סקר. הם כוללים את השדות הבאים:
version: (גרסה): הערך חייב להיות META_DATA_VERSION
type: הערך חייב להיות SENSOR_TYPE_META_DATA
sensor, reserved, and timestamp: הערך חייב להיות 0
meta_data.what: מכיל את סוג המטא-נתונים של האירוע הזה. נכון לעכשיו, יש רק סוג אחד של מטא-נתונים תקינים: META_DATA_FLUSH_COMPLETE
.
אירועים מסוג META_DATA_FLUSH_COMPLETE
מייצגים את השלמת הריקון של FIFO של חיישן. כשמגדירים את meta_data.what=META_DATA_FLUSH_COMPLETE
, meta_data.sensor
צריך להגדיר את המאחז של החיישן שבוצע בו ניקוי. הם נוצרים רק כשקוראים ל-flush
בחיישן. מידע נוסף זמין בקטע בנושא הפונקציה flush.