Sensors HAL 1.0

ממשק ה-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.