interfejs HAL czujników 1.0,

Interfejs Sensors HAL, zadeklarowany w pliku sensors.h, stanowi interfejs między frameworkem Androida a oprogramowaniem dla konkretnego sprzętu. Implementacja HAL musi zdefiniować każdą funkcję zadeklarowaną w pliku sensors.h. Główne funkcje to:

  • get_sensors_list – zwraca listę wszystkich czujników.
  • activate – uruchamia lub zatrzymuje czujnik.
  • batch – ustawia parametry czujnika, takie jak częstotliwość próbkowania i maksymalne opóźnienie raportowania.
  • setDelay – używany tylko w wersji 1.0 interfejsu HAL. Ustawia częstotliwość próbkowania dla danego czujnika.
  • flush – opróżnia kolejkę FIFO określonego czujnika i zgłasza zdarzenie zakończenia opróżniania, gdy to się stanie.
  • poll – zwraca dostępne zdarzenia czujnika.

Implementacja musi być bezpieczna w wielu wątkach i umożliwiać wywoływanie tych funkcji z różnych wątków.

Interfejs definiuje też kilka typów używanych przez te funkcje. Główne typy to:

  • sensors_module_t
  • sensors_poll_device_t
  • sensor_t
  • sensors_event_t

Więcej informacji o tych typach znajdziesz w pliku sensors.h, a nie w sekcjach poniżej.

get_sensors_list(list)

int (*get_sensors_list)(struct sensors_module_t* module, struct sensor_t
  const** list);

Zawiera listę czujników zaimplementowanych przez HAL. Szczegółowe informacje o definiowaniu czujników znajdziesz w sekcji sensor_t.

Kolejność, w jakiej czujniki są widoczne na liście, to kolejność, w jakiej będą one raportowane aplikacjom. Zwykle najpierw pojawiają się czujniki podstawowe, a potem czujniki złożone.

Jeśli kilka czujników ma ten sam typ i właściwość aktywacji, pierwszy na liście jest nazywany „domyślnym” czujnikiem. Jest to wartość zwrócona przez getDefaultSensor(int sensorType, bool wakeUp).

Ta funkcja zwraca liczbę czujników na liście.

activate(sensor, true/false)

int (*activate)(struct sensors_poll_device_t *dev, int sensor_handle, int
  enabled);

Aktywuje lub dezaktywuje czujnik.

sensor_handle to uchwyt czujnika do aktywacji/dezaktywacji. Uchwyt czujnika jest zdefiniowany przez pole handle w strukturze sensor_t.

Wartość 1 włącza czujnik, a 0 – wyłącza.enabled

Jednorazowe czujniki wyłączają się automatycznie po otrzymaniu zdarzenia. Aby je wyłączyć, należy je wywołać za pomocą funkcji activate(..., enabled=0).

Czujniki niewybudzające nigdy nie uniemożliwiają SoC przejścia w tryb zawieszenia. Oznacza to, że HAL nie może blokować częściowego wybudzania w imieniu aplikacji.

Ciągłe wysyłanie zdarzeń przez czujniki aktywujące może uniemożliwić SoC przejście w tryb zawieszenia, ale jeśli nie trzeba wysyłać żadnych zdarzeń, należy zwolnić blokadę częściowego budzenia.

Jeśli enabled = 1, a czujnik jest już aktywny, ta funkcja nie wykonuje żadnej operacji i kończy się sukcesem.

Jeśli enabled = 0 i czujnik jest już dezaktywowany, ta funkcja nie wykonuje żadnej operacji i kończy się sukcesem.

Ta funkcja zwraca 0 w przypadku powodzenia i ujemną liczbę błędu w przeciwnym przypadku.

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);

Ustawia parametry czujnika, w tym częstotliwość próbkowaniamaksymalną latencję raportu. Funkcję tę można wywołać, gdy czujnik jest włączony. W tym przypadku nie może ona spowodować utraty pomiarów czujnika: przejście z jednego współczynnika próbkowania na inny nie może spowodować utraty zdarzeń, podobnie jak przejście z wysokiej maksymalnej latencji raportu na niską maksymalną latencję raportu.

sensor_handle to uchwyt czujnika, który ma być skonfigurowany.

flags nie jest obecnie używany.

sampling_period_ns to okres próbkowania, w którym ma działać czujnik (w nanosekundach). Więcej informacji znajdziesz w kolumnie sampling_period_ns.

max_report_latency_ns to maksymalny czas opóźnienia zdarzeń przed ich zgłoszeniem przez HAL (w nanosekundach). Więcej informacji znajdziesz w akapicie max_report_latency_ns.

Ta funkcja zwraca 0 w przypadku powodzenia i ujemną liczbę błędu w przeciwnym przypadku.

setDelay(sensor, sampling period)

int (*setDelay)(
     struct sensors_poll_device_t *dev,
     int sensor_handle,
     int64_t sampling_period_ns);

Po wersji HAL 1.0 ta funkcja została wycofana i nigdy nie jest wywoływana. Zamiast tego do ustawienia parametru sampling_period_ns wywoływana jest funkcja batch.

W wersji HAL 1.0 do ustawienia parametru sampling_period_ns używana była funkcja setDelay zamiast batch.

flush(sensor)

int (*flush)(struct sensors_poll_device_1* dev, int sensor_handle);

Dodaj zgłoszenie całkowitego opróżnienia FIFO na końcu FIFO sprzętowego dla określonego czujnika i opróżnij FIFO. Te zdarzenia są dostarczane jak zwykle (czyli tak, jakby maksymalny czas oczekiwania na raportowanie minął) i usuwane z FIFO.

Wyczyszczenie odbywa się asynchronicznie (czyli funkcja musi zwrócić wynik natychmiast). Jeśli implementacja używa jednego kolejki FIFO dla kilku czujników, ta kolej jest opróżniana, a zdarzenie o ukończeniu opróżniania jest dodawane tylko dla określonego czujnika.

Jeśli wskazany czujnik nie ma kolejki FIFO (nie można przeprowadzić buforowania) lub jeśli kolejka FIFO była pusta w momencie wywołania, flush musi zakończyć się sukcesem i wysłać zdarzenie flush complete dla tego czujnika. Dotyczy to wszystkich czujników oprócz jednorazowych.

Gdy wywołana zostanie funkcja flush, nawet jeśli zdarzenie czyszczenia znajduje się już w FIFO dla danego czujnika, należy utworzyć dodatkowe zdarzenie i dodać je na końcu FIFO, a także opróżnić FIFO. Liczba wywołań flush musi być równa liczbie utworzonych zdarzeń FlushComplete.

flush nie dotyczy czujników jednorazowych. Jeśli sensor_handle odnosi się do czujnika jednorazowego, flush musi zwracać -EINVAL i nie generować żadnego zdarzenia flush complete metadata.

Ta funkcja zwraca 0 w przypadku powodzenia, -EINVAL, jeśli podany czujnik jest jednorazowy lub nie został włączony, a w przeciwnym razie zwraca liczbę błędu.

poll()

int (*poll)(struct sensors_poll_device_t *dev, sensors_event_t* data, int
  count);

Zwraca tablicę danych z czujnika, wypełniając argument data. Ta funkcja musi blokować do czasu, gdy wydarzenia będą dostępne. W przypadku powodzenia zwraca liczbę odczytanych zdarzeń, a w przypadku błędu – ujemną liczbę błędu.

Liczba zdarzeń zwracanych w parametrize data musi być mniejsza lub równa argumentowi count. Ta funkcja nigdy nie powinna zwracać 0 (brak zdarzenia).

Kolejność wywołań

Podczas uruchamiania urządzenia wywoływana jest funkcja get_sensors_list.

Gdy czujnik zostanie aktywowany, zostanie wywołana funkcja batch z wymaganymi parametrami, a następnie activate(..., enable=1).

W wersji HAL 1_0 kolejność była odwrotna: najpierw wywoływana była funkcja activate, a potem set_delay.

Gdy podczas aktywacji żądane właściwości czujnika ulegają zmianie, wywoływana jest funkcja batch.

flush może być wywoływany w dowolnym momencie, nawet w przypadku nieaktywnych czujników (w takim przypadku musi zwracać -EINVAL).

Gdy czujnik zostanie dezaktywowany, zostanie wywołana metoda activate(..., enable=0).

Równolegle z tymi wywołaniami funkcja poll będzie wielokrotnie wywoływana w celu żądania danych. poll może być wywoływany nawet wtedy, gdy nie ma aktywnych czujników.

sensors_module_t

sensors_module_t to typ używany do tworzenia modułu sprzętowego Androida dla czujników. Implementacja HAL musi zdefiniować obiekt HAL_MODULE_INFO_SYM tego typu, aby udostępnić funkcję get_sensors_list. Więcej informacji znajdziesz w definicji sensors_module_t w pliku sensors.h oraz w definicji hw_module_t.

sensors_poll_device_t / sensors_poll_device_1_t

sensors_poll_device_1_t zawiera pozostałe zdefiniowane powyżej metody: activate, batch, flush i poll. Jego pole common (z typem hw_device_t) określa numer wersji interfejsu HAL.

sensor_t

sensor_t odpowiada czujnikowi Androida. Oto kilka ważnych pól:

name: widoczny dla użytkownika ciąg znaków reprezentujący czujnik. Ten ciąg tekstowy często zawiera nazwę części czujnika, typ czujnika oraz informację, czy jest to czujnik aktywujący. Przykłady: „LIS2HH12 Accelerometer”, „MAX21000 Uncalibrated Gyroscope”, „BMP280 Wake-up Barometer”, „MPU6515 Game Rotation Vector”.

handle: liczba całkowita używana do odwoływania się do czujnika podczas rejestrowania go lub generowania zdarzeń.

type: typ czujnika. Więcej informacji o rodzaju czujnika znajdziesz w artykule Czym są czujniki Androida?, a o oficjalnych typach czujników – w artykule Typy czujników. W przypadku nieoficjalnych typów czujników type musi zaczynać się od SENSOR_TYPE_DEVICE_PRIVATE_BASE

stringType: typ czujnika jako ciąg znaków. Jeśli czujnik ma oficjalny typ, ustaw wartość SENSOR_STRING_TYPE_*. Jeśli czujnik ma typ określony przez producenta, stringType musi zaczynać się od nazwy domeny odwrotnej producenta. Na przykład czujnik (np. detektor jednorożców) zdefiniowany przez zespół Cool-product w firmie Fictional-Company może używać stringType=”com.fictional_company.cool_product.unicorn_detector”. Wartość stringType służy do jednoznacznej identyfikacji nieoficjalnych typów czujników. Więcej informacji o typach i typach ciągów znajdziesz w pliku sensors.h.

requiredPermission: ciąg znaków reprezentujący uprawnienie, które aplikacje muszą mieć, aby widzieć czujnik, zarejestrować go i otrzymywać z niego dane. Pusty ciąg znaków oznacza, że aplikacje nie wymagają żadnych uprawnień do dostępu do tego czujnika. Niektóre typy czujników, np. monitor tętna, mają obowiązkowe requiredPermission. Wszystkie czujniki dostarczające informacje o użytkowniku o charakterze wrażliwym (takie jak tętno) muszą być chronione przez uprawnienia.

flagi: flagi tego czujnika określające tryb raportowania i to, czy jest to czujnik aktywujący. Na przykład czujnik pojedynczego pobudzenia będzie miał wartość flags = SENSOR_FLAG_ONE_SHOT_MODE | SENSOR_FLAG_WAKE_UP. Bity flagi, które nie są używane w bieżącej wersji HAL, muszą być równe 0.

maxRange: maksymalna wartość, jaką może podać czujnik, w tych samych jednostkach co wartości zgłaszane. Sensor musi być w stanie raportować wartości bez nasycenia w zakresie [-maxRange; maxRange]. Oznacza to, że całkowity zakres czujnika w ogólnym znaczeniu to 2*maxRange. Gdy czujnik podaje wartości na kilku osiach, zakres dotyczy każdej z nich. Na przykład akcelerometr „+/- 2g” podaje wartość maxRange = 2*9.81 = 2g.

resolution: najmniejsza różnica w wartości, jaką może mierzyć czujnik. Zwykle obliczana na podstawie maxRange i liczby bitów w pomiarach.

power: koszt energii potrzebny do włączenia czujnika w miliampach. Jest to prawie zawsze więcej niż zużycie energii podane w arkuszu danych czujnika. Więcej informacji znajdziesz w artykule Base sensors != physical sensors, a szczegóły dotyczące pomiaru poboru mocy przez czujnik znajdziesz w artykule Proces pomiaru poboru mocy. Jeśli zużycie energii przez czujnik zależy od tego, czy urządzenie się porusza, zużycie energii podczas ruchu jest podawane w polu power

minDelay: w przypadku ciągłych czujników okres próbkowania w mikrosekundach odpowiadający najszybszej częstotliwości obsługiwanej przez czujnik. Szczegółowe informacje o użyciu tej wartości znajdziesz w sekcji sampling_period_ns. Pamiętaj, że minDelay jest wyrażona w mikrosekundach, a sampling_period_ns – w nanosekundach. W przypadku czujników w trybie raportowania zmian i trybie specjalnym (chyba że określono inaczej) wartość minDelay musi wynosić 0. W przypadku czujników jednorazowych musi ona mieć wartość -1.

maxDelay: w przypadku ciągłych i zmiennych czujników okres próbkowania w mikrosekundach odpowiadający najwolniejszej częstotliwości obsługiwanej przez czujnik. Szczegółowe informacje o użyciu tej wartości znajdziesz w sekcji sampling_period_ns. Pamiętaj, że maxDelay jest wyrażona w mikrosekundach, a sampling_period_ns – w nanosekundach. W przypadku czujników specjalnych i jednorazowych wartość maxDelay musi wynosić 0.

fifoReservedEventCount: liczba zdarzeń zarezerwowanych dla tego czujnika w FIFO sprzętowym. Jeśli dla tego czujnika istnieje dedykowany stos FIFO, fifoReservedEventCount to rozmiar tego dedykowanego stosu FIFO. Jeśli kolejka FIFO jest współdzielona z innymi czujnikami, fifoReservedEventCount to rozmiar części kolejki FIFO zarezerwowanej dla danego czujnika. W przypadku większości systemów z wspólnym FIFO oraz systemów bez FIFO sprzętowego ta wartość wynosi 0.

fifoMaxEventCount: maksymalna liczba zdarzeń, które mogą być przechowywane w FIFO dla tego czujnika. Jest ona zawsze równa lub większa od wartości fifoReservedEventCount. Ta wartość służy do oszacowania, jak szybko FIFO zostanie wypełniona po zarejestrowaniu w czujniku z określoną szybkością, przy założeniu, że nie są aktywne żadne inne czujniki. W systemach, które nie mają FIFO sprzętowego, fifoMaxEventCount ma wartość 0. Więcej informacji znajdziesz w sekcji przetwarzanie zbiorcze.

W przypadku czujników z oficjalnym typem niektóre pola są zastępowane przez platformę. Na przykład czujniki przyspieszenia muszą mieć tryb ciągłego raportowania, a monitory tętna muszą być chronione przez uprawnienie SENSOR_PERMISSION_BODY_SENSORS.

sensors_event_t

Zdarzenia czujnika generowane przez czujniki Androida i zgłaszane za pomocą funkcji poll mają typ type sensors_event_t. Oto kilka ważnych pól w sensors_event_t:

version: musi mieć wartość sizeof(struct sensors_event_t)

sensor: uchwyt czujnika, który wygenerował zdarzenie, zgodnie z definicją w sensor_t.handle.

type: typ czujnika, który wygenerował zdarzenie, zgodnie z definicją w sensor_t.type.

timestamp: sygnatura czasowa zdarzenia w nanosekundach. Jest to czas wystąpienia zdarzenia (krok lub pomiar przyspieszenia), a nie czas zgłoszenia zdarzenia. timestamp musi być zsynchronizowany z zegarkiem elapsedRealtimeNano, a w przypadku ciągłych czujników jitter musi być mały. Filtrowanie sygnałów czasowych jest czasami konieczne, aby spełnić wymagania dotyczące CDD, ponieważ użycie tylko czasu przerwania SoC do ustawienia sygnałów czasowych powoduje zbyt duży jitter, a użycie tylko czasu z układu scalonego czujnika do ustawienia sygnałów czasowych może spowodować brak synchronizacji z zegarem elapsedRealtimeNano, ponieważ zegar czujnika może się przesuwać.

pola danych i pola nakładające się: wartości zmierzone przez czujnik. Ich znaczenie i jednostki zależą od typu czujnika. Opis pól danych znajdziesz w pliku sensors.h oraz w definicji różnych typów czujników. W przypadku niektórych czujników dokładność odczytów jest również raportowana jako część danych w polu status. To pole jest przekazywane tylko w przypadku wybranych typów czujników i wyświetlane na poziomie SDK jako wartość dokładności. W przypadku tych czujników fakt, że pole stanu musi być ustawione, jest wspomniany w definicji typu czujnika.

Zdarzenia dotyczące pełnego wyczyszczania metadanych

Zdarzenia metadanych mają ten sam typ co zwykłe zdarzenia czujnika: sensors_event_meta_data_t = sensors_event_t. Zdarzenia te są zwracane razem z innymi zdarzeniami czujnika za pomocą metody poll(). Zawierają one te pola:

version: musi mieć wartość META_DATA_VERSION

type: musi być SENSOR_TYPE_META_DATA

sensor, reserved, and timestamp: muszą mieć wartość 0.

meta_data.what: zawiera typ metadanych tego zdarzenia. Obecnie dostępny jest tylko 1 prawidłowy typ metadanych: META_DATA_FLUSH_COMPLETE.

Zdarzenia META_DATA_FLUSH_COMPLETE wskazują na zakończenie czyszczenia kolejki FIFO czujnika. Gdy meta_data.what=META_DATA_FLUSH_COMPLETE, meta_data.sensor musi być ustawiony na uchwyt czujnika, który został wyczyszczony. Są one generowane tylko wtedy, gdy funkcja flush zostanie wywołana w przypadku czujnika. Więcej informacji znajdziesz w sekcji poświęconej funkcji flush.