英特爾整合感測器 Hub (ISH)¶
感測器 Hub 能夠將感測器輪詢和演算法處理解除安裝到專用的低功耗協處理器。 這使得核心處理器能夠更頻繁地進入低功耗模式,從而延長電池續航時間。
有許多供應商提供符合 HID 感測器使用表的外部感測器 Hub。 這些裝置可以在平板電腦、二合一可轉換筆記型電腦和嵌入式產品中找到。 Linux 自 Linux 3.9 以來就支援這一點。
Intel® 推出了整合感測器 Hub,作為從 Cherry Trail 開始的 SoC 的一部分,現在在多代 CPU 封裝上都得到了支援。 許多商業裝置已經配備了整合感測器 Hub (ISH)。 這些 ISH 也符合 HID 感測器規範,但不同之處在於用於通訊的傳輸協議。 目前的外部感測器 Hub 主要使用 HID over I2C 或 USB。 但是 ISH 不使用 I2C 或 USB。
概述¶
如果與 usbhid 實現進行類比,ISH 遵循類似的模型,以實現非常高速的通訊
----------------- ----------------------
| USB HID | --> | ISH HID |
----------------- ----------------------
----------------- ----------------------
| USB protocol | --> | ISH Transport |
----------------- ----------------------
----------------- ----------------------
| EHCI/XHCI | --> | ISH IPC |
----------------- ----------------------
PCI PCI
----------------- ----------------------
|Host controller| --> | ISH processor |
----------------- ----------------------
USB Link
----------------- ----------------------
| USB End points| --> | ISH Clients |
----------------- ----------------------
與 USB 協議提供裝置列舉、連結管理和使用者資料封裝的方法一樣,ISH 也提供類似的服務。 但它非常輕量級,專門用於管理和與韌體中實現的 ISH 客戶端應用程式進行通訊。
ISH 允許在韌體中執行多個感測器管理應用程式。 就像 USB 端點一樣,訊息可以是傳送到/來自客戶端的。 作為列舉過程的一部分,這些客戶端會被識別。 這些客戶端可以是簡單的 HID 感測器應用程式、感測器校準應用程式或感測器韌體更新應用程式。
實現模型類似,就像 USB 匯流排一樣,ISH 傳輸也被實現為匯流排。 每個在 ISH 處理器中執行的客戶端應用程式都會註冊為該總線上的裝置。 繫結每個裝置(ISH HID 驅動程式)的驅動程式會識別裝置型別並註冊到 HID 核心。
ISH 實現:框圖¶
---------------------------
| User Space Applications |
---------------------------
----------------IIO ABI----------------
--------------------------
| IIO Sensor Drivers |
--------------------------
--------------------------
| IIO core |
--------------------------
--------------------------
| HID Sensor Hub MFD |
--------------------------
--------------------------
| HID Core |
--------------------------
--------------------------
| HID over ISH Client |
--------------------------
--------------------------
| ISH Transport (ISHTP) |
--------------------------
--------------------------
| IPC Drivers |
--------------------------
OS
---------------- PCI -----------------
Hardware + Firmware
----------------------------
| ISH Hardware/Firmware(FW) |
----------------------------
以上模組中的高階處理¶
硬體介面¶
ISH 作為“非 VGA 未分類 PCI 裝置”暴露給主機。 PCI 產品和供應商 ID 會隨著不同代的處理器而改變。 因此,列舉驅動程式的原始碼需要代代更新。
處理器間通訊 (IPC) 驅動程式¶
位置:drivers/hid/intel-ish-hid/ipc
IPC 訊息使用記憶體對映 I/O。 暫存器在 hw-ish-regs.h 中定義。
IPC/FW 訊息型別¶
有兩種型別的訊息,一種用於連結管理,另一種用於傳送到/來自傳輸層的訊息。
傳輸訊息的 TX 和 RX¶
一組記憶體對映暫存器提供了對多位元組訊息 TX 和 RX 的支援(例如,IPC_REG_ISH2HOST_MSG、IPC_REG_HOST2ISH_MSG)。 IPC 層維護內部佇列以對訊息進行排序,並按順序將其傳送到韌體。 或者,呼叫者可以註冊處理程式以獲取完成通知。 訊息傳遞中使用門鈴機制來觸發主機和客戶端韌體端的處理。 當呼叫 ISH 中斷處理程式時,主機驅動程式使用 ISH2HOST 門鈴暫存器來確定中斷是否用於 ISH。
每一側都有 32 個 32 位訊息暫存器和一個 32 位門鈴。 門鈴暫存器具有以下格式
Bits 0..6: fragment length (7 bits are used)
Bits 10..13: encapsulated protocol
Bits 16..19: management command (for IPC management protocol)
Bit 31: doorbell trigger (signal H/W interrupt to the other side)
Other bits are reserved, should be 0.
傳輸層介面¶
為了抽象 HW 級別的 IPC 通訊,註冊了一組回撥。 傳輸層使用它們來發送和接收訊息。 請參閱結構 ishtp_hw_ops 以獲取回撥。
ISH 傳輸層¶
位置:drivers/hid/intel-ish-hid/ishtp/
通用傳輸層¶
傳輸層是雙向協議,它定義: - 用於啟動、停止、連線、斷開連線和流量控制的一組命令(有關詳細資訊,請參閱 ishtp/hbm.h) - 一種避免緩衝區溢位的流量控制機制
此協議類似於以下文件中描述的匯流排訊息: http://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/dcmi-hi-1-0-spec.pdf “第 7 章:匯流排訊息層”
連線和流量控制機制¶
每個 FW 客戶端和協議都由 UUID 標識。 為了與 FW 客戶端通訊,必須使用連線請求和響應匯流排訊息建立連線。 如果成功,一對(host_client_id 和 fw_client_id)將標識該連線。
建立連線後,對等方會彼此獨立地傳送流量控制匯流排訊息。 只有在之前收到流量控制信用時,每個對等方才能傳送訊息。 一旦傳送了一條訊息,在收到下一個流量控制信用之前,它就不能傳送另一條訊息。 任何一方都可以傳送斷開連線請求匯流排訊息以結束通訊。 如果發生重大 FW 重置,連結也會被丟棄。
對等資料傳輸¶
對等資料傳輸可以在使用或不使用 DMA 的情況下發生。 根據感測器頻寬要求,可以透過在 intel_ishtp 下使用模組引數 ishtp_use_dma 來啟用 DMA。
每一側(主機和 FW)獨立管理其 DMA 傳輸記憶體。 當來自主機或 FW 側的 ISHTP 客戶端想要傳送某些內容時,它會決定是透過 IPC 還是透過 DMA 傳送; 對於每次傳輸,該決策都是獨立的。 當訊息位於相應的宿主緩衝區中時,傳送方會發送 DMA_XFER 訊息(主機客戶端傳送時為 TX,FW 客戶端傳送時為 RX)。 DMA 訊息的接收者以 DMA_XFER_ACK 響應,表明該訊息的記憶體區域可以重複使用。
DMA 初始化從主機發送 DMA_ALLOC_NOTIFY 匯流排訊息(包括 RX 緩衝區)開始,FW 以 DMA_ALLOC_NOTIFY_ACK 響應。 除了 DMA 地址通訊之外,此序列還檢查功能:如果主機不支援 DMA,則它不會發送 DMA 分配,因此 FW 無法傳送 DMA; 如果 FW 不支援 DMA,則它不會以 DMA_ALLOC_NOTIFY_ACK 響應,在這種情況下,主機將不使用 DMA 傳輸。 在這裡,ISH 充當匯流排主控 DMA 控制器。 因此,當主機發送 DMA_XFER 時,它是執行主機->ISH DMA 傳輸的請求; 當 FW 傳送 DMA_XFER 時,這意味著它已經完成了 DMA,並且該訊息駐留在主機中。 因此,DMA_XFER 和 DMA_XFER_ACK 充當所有權指示器。
在初始狀態下,所有傳出的記憶體都屬於傳送者(TX 給主機,RX 給 FW),DMA_XFER 將包含 ISHTP 訊息的區域的所有權轉移到接收方,DMA_XFER_ACK 將所有權返回給傳送者。 只要其所有權中剩餘的連續記憶體足夠,傳送者無需等待之前的 DMA_XFER 被確認,就可以傳送另一條訊息。 原則上,可以一次傳送多個 DMA_XFER 和 DMA_XFER_ACK 訊息(最多 IPC MTU),從而允許進行中斷抑制。 目前,如果 ISHTP 訊息大於 3 個 IPC 片段,則 ISH FW 決定透過 DMA 傳送,否則透過 IPC 傳送。
環形緩衝區¶
當客戶端啟動連線時,會分配 RX 和 TX 緩衝區的環形。 環形的大小可以由客戶端指定。 HID 客戶端分別將 TX 和 RX 緩衝區設定為 16 和 32。 在客戶端的傳送請求時,要傳送的資料會被複制到其中一個傳送環形緩衝區,並計劃使用匯流排訊息協議傳送。 需要這些緩衝區是因為 FW 可能尚未處理上一條訊息,並且可能沒有足夠的流量控制信用可以傳送。 相同的情況適用於接收端,並且需要流量控制。
主機列舉¶
主機列舉匯流排命令允許發現 FW 中存在的客戶端。 可以有多個感測器客戶端和用於校準功能的客戶端。
為了簡化實現並允許獨立的驅動程式處理每個客戶端,此傳輸層利用了 Linux 匯流排驅動程式模型。 每個客戶端都會註冊為傳輸匯流排(ishtp 匯流排)上的裝置。
訊息的列舉序列
主機發送 HOST_START_REQ_CMD,表明主機 ISHTP 層已啟動。
FW 以 HOST_START_RES_CMD 響應
主機發送 HOST_ENUM_REQ_CMD(列舉 FW 客戶端)
FW 以 HOST_ENUM_RES_CMD 響應,其中包含可用 FW 客戶端 ID 的點陣圖
對於在該點陣圖中找到的每個 FW ID,主機發送 HOST_CLIENT_PROPERTIES_REQ_CMD
FW 以 HOST_CLIENT_PROPERTIES_RES_CMD 響應。 屬性包括 UUID、最大 ISHTP 訊息大小等。
一旦主機收到最後一個發現的客戶端的屬性,它就認為 ISHTP 裝置完全正常執行(並分配 DMA 緩衝區)
HID over ISH 客戶端¶
位置:drivers/hid/intel-ish-hid
ISHTP 客戶端驅動程式負責
列舉 FW ISH 客戶端下的 HID 裝置
獲取報告描述符
將自身註冊為 HID 核心的 LL 驅動程式
處理 Get/Set 功能請求
獲取輸入報告
HID 感測器 Hub MFD 和 IIO 感測器驅動程式¶
這些驅動程式中的功能與外部感測器 Hub 相同。 請參閱 HID 感測器框架,瞭解 HID 感測器 ABI 檔案測試/sysfs-bus-iio,瞭解 IIO ABI 到使用者空間。
端到端 HID 傳輸序列圖¶
HID-ISH-CLN ISHTP IPC HW
| | | |
| | |-----WAKE UP------------------>|
| | | |
| | |-----HOST READY--------------->|
| | | |
| | |<----MNG_RESET_NOTIFY_ACK----- |
| | | |
| |<----ISHTP_START------ | |
| | | |
| |<-----------------HOST_START_RES_CMD-------------------|
| | | |
| |------------------QUERY_SUBSCRIBER-------------------->|
| | | |
| |------------------HOST_ENUM_REQ_CMD------------------->|
| | | |
| |<-----------------HOST_ENUM_RES_CMD--------------------|
| | | |
| |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
| | | |
| |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
| Create new device on in ishtp bus | |
| | | |
| |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
| | | |
| |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
| Create new device on in ishtp bus | |
| | | |
| |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
| | | |
probed()
|----ishtp_cl_connect--->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
| | | |
| |<----------------CLIENT_CONNECT_RES_CMD----------------|
| | | |
|register event callback | | |
| | | |
|ishtp_cl_send(
HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|
| | | |
| | |<-----IRQ(IPC_PROTOCOL_ISHTP---|
| | | |
|<--ENUM_DEVICE RSP------| | |
| | | |
for each enumerated device
|ishtp_cl_send(
HOSTIF_GET_HID_DESCRIPTOR|----------fill ishtp_msg_hdr struct write to HW----- >|
| | | |
...Response
| | | |
for each enumerated device
|ishtp_cl_send(
HOSTIF_GET_REPORT_DESCRIPTOR|--------------fill ishtp_msg_hdr struct write to HW-- >|
| | | |
| | | |
hid_allocate_device
| | | |
hid_add_device | | |
| | | |
從主機載入 ISH 韌體的流程¶
從 Lunar Lake 世代開始,ISH 韌體被分為兩個元件,以實現更好的空間最佳化和更高的靈活性。 這些元件包括一個整合到 BIOS 中的引導載入程式和一個儲存在作業系統檔案系統中的主韌體。
該過程如下所示
最初,ISHTP 驅動程式向 ISH 引導載入程式傳送命令 HOST_START_REQ_CMD。 作為響應,引導載入程式發回 HOST_START_RES_CMD。 此響應包括 ISHTP_SUPPORT_CAP_LOADER 位。 隨後,ISHTP 驅動程式檢查是否設定了此位。 如果是,則從主機開始韌體載入過程。
在此過程中,ISHTP 驅動程式首先呼叫
request_firmware()函式,然後傳送 LOADER_CMD_XFER_QUERY 命令。 收到來自引導載入程式的響應後,ISHTP 驅動程式傳送 LOADER_CMD_XFER_FRAGMENT 命令。 收到另一個響應後,ISHTP 驅動程式傳送 LOADER_CMD_START 命令。 引導載入程式做出響應,然後繼續執行主韌體。該過程結束後,ISHTP 驅動程式會呼叫 release_firmware() 函式。
有關更多詳細資訊,請參閱以下提供的流程描述
+---------------+ +-----------------+
| ISHTP Driver | | ISH Bootloader |
+---------------+ +-----------------+
| |
|~~~Send HOST_START_REQ_CMD~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send HOST_START_RES_CMD(Includes ISHTP_SUPPORT_CAP_LOADER bit)----|
| |
****************************************************************************************
* if ISHTP_SUPPORT_CAP_LOADER bit is set *
****************************************************************************************
| |
|~~~start loading firmware from host process~~~+ |
| | |
|<---------------------------------------------+ |
| |
--------------------------- |
| Call request_firmware() | |
--------------------------- |
| |
|~~~Send LOADER_CMD_XFER_QUERY~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send response-----------------------------------------------------|
| |
|~~~Send LOADER_CMD_XFER_FRAGMENT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send response-----------------------------------------------------|
| |
|~~~Send LOADER_CMD_START~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send response-----------------------------------------------------|
| |
| |~~~Jump to Main Firmware~~~+
| | |
| |<--------------------------+
| |
--------------------------- |
| Call release_firmware() | |
--------------------------- |
| |
****************************************************************************************
* end if *
****************************************************************************************
| |
+---------------+ +-----------------+
| ISHTP Driver | | ISH Bootloader |
+---------------+ +-----------------+
供應商自定義韌體載入¶
在 ISH 內部執行的韌體可以由 Intel 提供,也可以由供應商使用 Intel 提供的韌體開發套件 (FDK) 開發。 Intel 會將 Intel 構建的韌體上傳到 linux-firmware.git 儲存庫,該儲存庫位於路徑 intel/ish/ 下。 對於 Lunar Lake 平臺,Intel 構建的 ISH 韌體將被命名為 ish_lnlm.bin。 希望上傳其自定義韌體的供應商應遵循以下命名其韌體檔案的指南
韌體檔名應使用以下模式之一
ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.binish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.binish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.binish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin
${intel_plat_gen}表示 Intel 平臺代(例如,Lunar Lake 的lnlm),並且長度不得超過 8 個字元。${SYS_VENDOR_CRC32}是來自 DMI 欄位DMI_SYS_VENDOR的sys_vendor值的 CRC32 校驗和。${PRODUCT_NAME_CRC32}是來自 DMI 欄位DMI_PRODUCT_NAME的product_name值的 CRC32 校驗和。${PRODUCT_SKU_CRC32}是來自 DMI 欄位DMI_PRODUCT_SKU的product_sku值的 CRC32 校驗和。
在系統啟動期間,ISH Linux 驅動程式將嘗試按以下順序載入韌體,優先載入具有更精確匹配模式的自定義韌體
intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.binintel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.binintel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.binintel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.binintel/ish/ish_${intel_plat_gen}.bin
驅動程式將載入第一個匹配的韌體並跳過其餘韌體。 如果找不到匹配的韌體,它將按指定順序繼續執行下一個模式。 如果所有搜尋都失敗,則將載入預設的 Intel 韌體(在上面的順序中最後列出)。
ISH 除錯¶
要除錯 ISH,請使用事件跟蹤機制。 要啟用除錯日誌
echo 1 > /sys/kernel/tracing/events/intel_ish/enable
cat /sys/kernel/tracing/trace
Lenovo thinkpad Yoga 260 上的 ISH IIO sysfs 示例¶
root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
/sys/bus/iio/devices/
├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
│ ├── buffer
│ │ ├── enable
│ │ ├── length
│ │ └── watermark
...
│ ├── in_accel_hysteresis
│ ├── in_accel_offset
│ ├── in_accel_sampling_frequency
│ ├── in_accel_scale
│ ├── in_accel_x_raw
│ ├── in_accel_y_raw
│ ├── in_accel_z_raw
│ ├── name
│ ├── scan_elements
│ │ ├── in_accel_x_en
│ │ ├── in_accel_x_index
│ │ ├── in_accel_x_type
│ │ ├── in_accel_y_en
│ │ ├── in_accel_y_index
│ │ ├── in_accel_y_type
│ │ ├── in_accel_z_en
│ │ ├── in_accel_z_index
│ │ └── in_accel_z_type
...
│ │ ├── devices
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_intensity_both_raw
│ │ │ │ ├── in_intensity_hysteresis
│ │ │ │ ├── in_intensity_offset
│ │ │ │ ├── in_intensity_sampling_frequency
│ │ │ │ ├── in_intensity_scale
│ │ │ │ ├── name
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_intensity_both_en
│ │ │ │ │ ├── in_intensity_both_index
│ │ │ │ │ └── in_intensity_both_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_magn_hysteresis
│ │ │ │ ├── in_magn_offset
│ │ │ │ ├── in_magn_sampling_frequency
│ │ │ │ ├── in_magn_scale
│ │ │ │ ├── in_magn_x_raw
│ │ │ │ ├── in_magn_y_raw
│ │ │ │ ├── in_magn_z_raw
│ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_raw
│ │ │ │ ├── in_rot_hysteresis
│ │ │ │ ├── in_rot_offset
│ │ │ │ ├── in_rot_sampling_frequency
│ │ │ │ ├── in_rot_scale
│ │ │ │ ├── name
...
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_magn_x_en
│ │ │ │ │ ├── in_magn_x_index
│ │ │ │ │ ├── in_magn_x_type
│ │ │ │ │ ├── in_magn_y_en
│ │ │ │ │ ├── in_magn_y_index
│ │ │ │ │ ├── in_magn_y_type
│ │ │ │ │ ├── in_magn_z_en
│ │ │ │ │ ├── in_magn_z_index
│ │ │ │ │ ├── in_magn_z_type
│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_en
│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_index
│ │ │ │ │ └── in_rot_from_north_magnetic_tilt_comp_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_anglvel_hysteresis
│ │ │ │ ├── in_anglvel_offset
│ │ │ │ ├── in_anglvel_sampling_frequency
│ │ │ │ ├── in_anglvel_scale
│ │ │ │ ├── in_anglvel_x_raw
│ │ │ │ ├── in_anglvel_y_raw
│ │ │ │ ├── in_anglvel_z_raw
│ │ │ │ ├── name
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_anglvel_x_en
│ │ │ │ │ ├── in_anglvel_x_index
│ │ │ │ │ ├── in_anglvel_x_type
│ │ │ │ │ ├── in_anglvel_y_en
│ │ │ │ │ ├── in_anglvel_y_index
│ │ │ │ │ ├── in_anglvel_y_type
│ │ │ │ │ ├── in_anglvel_z_en
│ │ │ │ │ ├── in_anglvel_z_index
│ │ │ │ │ └── in_anglvel_z_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_anglvel_hysteresis
│ │ │ │ ├── in_anglvel_offset
│ │ │ │ ├── in_anglvel_sampling_frequency
│ │ │ │ ├── in_anglvel_scale
│ │ │ │ ├── in_anglvel_x_raw
│ │ │ │ ├── in_anglvel_y_raw
│ │ │ │ ├── in_anglvel_z_raw
│ │ │ │ ├── name
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_anglvel_x_en
│ │ │ │ │ ├── in_anglvel_x_index
│ │ │ │ │ ├── in_anglvel_x_type
│ │ │ │ │ ├── in_anglvel_y_en
│ │ │ │ │ ├── in_anglvel_y_index
│ │ │ │ │ ├── in_anglvel_y_type
│ │ │ │ │ ├── in_anglvel_z_en
│ │ │ │ │ ├── in_anglvel_z_index
│ │ │ │ │ └── in_anglvel_z_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...