חיישנים 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 אם הפעולה בוצעה בהצלחה, ומספר שגיאה שלילי אחרת.

אצווה(חיישן, דגלים, תקופת דגימה, זמן אחזור מקסימלי של דוח)

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(חיישן, תקופת דגימה)

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, גם אם אירוע שטיפה כבר נמצא ב-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.

חיישנים_poll_device_t / חיישנים_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 לא מכויל', 'BMP280 Wake-up Barometer', 'MPU6515 Game Rotation Vector'

כינוי: המספר השלם שמשמש להתייחס לחיישן כשנרשמים אליו או יוצרים אירועים ממנו.

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.

fifoReserveEventCount: מספר האירועים ששמורים לחיישן הזה ב-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 ומדווחים באמצעות פונקציית הסקר הם מתוך 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, Reserve, חותמת זמן: חייבת להיות 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.