Czujniki HAL 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 HAL 1.0. Ustawia częstotliwość próbkowania dla danego czujnika.
  • flush – opróżnia kolejkę FIFO określonego czujnika i zgłasza zdarzenie flush complete, gdy to zrobi.
  • poll – zwraca dostępne zdarzenia czujnika.

Implementacja musi być bezpieczna w wątku 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(lista)

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. Zazwyczaj jako pierwsze pojawiają się czujniki podstawowe, a potem te 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ść enabled 1 włącza czujnik, a 0 – wyłącza.

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 interfejs HAL nie może blokować częściowego wybudzania w imieniu aplikacji.

Czujniki wybudzania podczas ciągłego dostarczania zdarzeń mogą zapobiec przechodzeniu układu SOC w tryb zawieszenia, ale jeśli nie jest potrzebne żadne zdarzenie, częściowa blokada wybudzania musi być wyłączona.

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 do skonfigurowania.

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 kolejki FIFO sprzętowej dla określonego czujnika i opróżnij FIFO. Te zdarzenia są dostarczane jak zwykle (czyli tak, jakby upłynął maksymalny czas oczekiwania na raportowanie) 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 w przypadku 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, funkcja flush musi się zakończyć sukcesem i wysłać zdarzenie flush complete dla tego czujnika. Dotyczy to wszystkich czujników oprócz czujników jednego ujęcia.

Po wywołaniu funkcji flush nawet wtedy, gdy w ustawieniach FIFO tego czujnika znajduje się już zdarzenie flush, należy utworzyć i dodać kolejne zdarzenie na końcu obiektu FIFO, a obiekt FIFO musi zostać opróżniony. Liczba wywołań flush musi być równa liczbie utworzonych zdarzeń Flush Complete.

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 wartości data musi być mniejsza lub równa argumentowi count. Ta funkcja nigdy nie zwraca 0 (brak zdarzenia).

Kolejność wywołań

Gdy urządzenie się uruchamia, wywoływana jest funkcja get_sensors_list.

Po aktywowaniu czujnika funkcja batch zostanie wywołana z żądanymi parametrami, po których następuje wywołanie 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 czujnika zmieniają się żądane cechy czujnika, wywoływana jest funkcja batch.

Funkcja flush może zostać wywołana w dowolnym momencie, nawet w przypadku nieaktywowanych czujników (w takim przypadku musi zwrócić wartość -EINVAL)

Gdy czujnik zostanie dezaktywowany, zostanie wywołana funkcja 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 są aktywne żadne czujniki.

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 w Androidzie. 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 typach czujników 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 specyficzny dla producenta, atrybut stringType musi zaczynać się od odwrotnej nazwy domeny 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”. 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 uprawnienia, 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łoszone. Sensor musi być w stanie raportować wartości bez nasycenia w zakresie [-maxRange; maxRange]. Pamiętaj, że oznacza to, że całkowity zakres czujnika w ogólnym sensie wynosi 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 niemal zawsze większe niż zużycie energii podawane w arkuszu danych czujnika źródłowego. Więcej informacji znajdziesz w sekcji Czujniki podstawowe != czujniki fizyczne. Szczegółowe informacje na temat pomiaru zużycia energii przez czujnik znajdziesz w artykule Proces pomiaru 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żony w mikrosekundach, a sampling_period_ns w nanosekundach. O ile nie określono inaczej, w przypadku czujników przy zmianie i specjalnych trybów raportowania, minDelay musi mieć wartość 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żony w mikrosekundach, a sampling_period_ns w nanosekundach. W przypadku czujników specjalnych i jednorazowych pole maxDelay musi mieć wartość 0.

fifoReserveEventCount: liczba zdarzeń zarezerwowanych dla tego czujnika w sprzętowej funkcji FIFO. Jeśli dla tego czujnika istnieje dedykowana kolejka FIFO, fifoReservedEventCount to jej rozmiar. Jeśli FIFO jest udostępniany innym czujnikom, fifoReservedEventCount to rozmiar części FIFO zarezerwowanej dla tego czujnika. W większości systemów współdzielonych FIFO oraz w systemach bez sprzętowego FIFO ta wartość wynosi 0.

fifoMaxEventCount: maksymalna liczba zdarzeń, które mogą być zapisane w FIFO dla tego czujnika. Zawsze jest równa lub większa od wartości fifoReservedEventCount. Ta wartość służy do oszacowania, jak szybko FIFO zapełni się po zarejestrowaniu w czujniku z określoną szybkością, o ile żadne inne czujniki nie zostaną aktywowane. W systemach, które nie mają sprzętowego FIFO, fifoMaxEventCount ma wartość 0. Więcej informacji znajdziesz w sekcji Grupowanie wsadowe.

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

sensors_event_t

Zdarzenia z czujników generowane przez czujniki Androida i zgłaszane za pomocą funkcji ankiety mają wartość type sensors_event_t. Oto kilka ważnych pól sensors_event_t:

version: musi być 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, zdefiniowany przez 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. Funkcja timestamp musi być zsynchronizowana z zegarem elapsedRealtimeNano, a w przypadku czujników ciągłych zakłócenia muszą być niewielkie. Filtrowanie sygnatur czasowych jest czasami konieczne, aby spełnić wymagania dotyczące CDD, ponieważ użycie tylko czasu przerwania SoC do ustawienia sygnatur czasowych powoduje zbyt duży jitter, a użycie tylko czasu z układu scalonego czujnika do ustawienia sygnatur 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 zakończenia usuwania metadanych

Zdarzenia metadanych mają ten sam typ co zwykłe zdarzenia z 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:

wersja: wymagana to 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 wywołanie flush jest wywoływane w przypadku czujnika. Więcej informacji znajdziesz w sekcji poświęconej funkcji flush.