6.1. 簡介

LIRC 代表 Linux 紅外遙控。LIRC 裝置介面是一個雙向介面,用於在使用者空間和核心空間之間傳輸原始紅外資料和解碼後的掃描碼資料。從根本上說,它只是一個字元裝置 (/dev/lircX,其中 X = 0, 1, 2, ...),在其上定義了許多標準的 struct file_operations。關於來回傳輸原始紅外資料和解碼後的掃描碼,基本的 fops 是 read、write 和 ioctl。

也可以將 BPF 程式附加到 LIRC 裝置,用於將原始紅外資料解碼為掃描碼。

驅動程式向 LIRC 註冊後示例 dmesg 輸出

$ dmesg |grep lirc_dev
rc rc0: lirc_dev: driver mceusb registered at minor = 0, raw IR receiver, raw IR transmitter

您應該看到的字元裝置資訊

$ ls -l /dev/lirc*
crw-rw---- 1 root root 248, 0 Jul 2 22:20 /dev/lirc0

請注意,v4l-utils 軟體包包含用於使用 LIRC 裝置的工具

  • ir-ctl:可以接收原始紅外資料和傳輸紅外資料,以及查詢 LIRC 裝置功能。

  • ir-keytable:可以載入鍵對映;允許您設定紅外核心協議;載入 BPF 紅外解碼器和測試紅外解碼。還提供了一些 BPF 紅外解碼器。

6.2. LIRC 模式

LIRC 支援一些接收和傳送紅外程式碼的模式,如下表所示。

LIRC_MODE_SCANCODE

此模式用於傳送和接收紅外資料。

對於傳輸(又名傳送),建立一個 struct lirc_scancode,並在 scancode 成員中設定所需的掃描碼,將 rc_proto 設定為 紅外協議,並將所有其他成員設定為 0。將此結構寫入 lirc 裝置。

對於接收,您可以從 LIRC 裝置讀取 struct lirc_scancodescancode 欄位設定為接收到的掃描碼,紅外協議rc_proto 中設定。如果掃描碼對映到有效的鍵程式碼,則將其設定在 keycode 欄位中,否則將其設定為 KEY_RESERVED

如果切換位在支援它的協議(例如 rc-5 和 rc-6)中設定,則 flags 可以設定 LIRC_SCANCODE_FLAG_TOGGLE,或者如果接收到支援它的協議的重複(例如 nec),則可以設定 LIRC_SCANCODE_FLAG_REPEAT

在 Sanyo 和 NEC 協議中,如果按住遙控器上的按鈕,而不是重複整個掃描碼,遙控器會發送一個更短的訊息,其中沒有掃描碼,這僅僅意味著按鈕被按住,即“重複”。當接收到此訊息時,將設定 LIRC_SCANCODE_FLAG_REPEAT,並且重複掃描碼和鍵程式碼。

使用 nec,無法區分“按鈕按住”和“重複按下同一按鈕”。rc-5 和 rc-6 協議有一個切換位。當釋放一個按鈕並再次按下時,切換位會反轉。如果設定了切換位,則設定 LIRC_SCANCODE_FLAG_TOGGLE

timestamp 欄位使用掃描碼解碼時的時間納秒(在 CLOCK_MONOTONIC 中)填充。

LIRC_MODE_MODE2

驅動程式將脈衝和空間程式碼的序列作為一系列 u32 值返回給使用者空間。

此模式僅用於紅外接收。

高 8 位確定資料包型別,低 24 位確定有效負載。使用 LIRC_VALUE() 宏來獲取有效負載,宏 LIRC_MODE2() 將為您提供型別,它是以下之一

LIRC_MODE2_PULSE

表示以微秒為單位的紅外存在,也稱為閃光

LIRC_MODE2_SPACE

表示以微秒為單位的紅外不存在,也稱為間隙

LIRC_MODE2_FREQUENCY

如果使用 ioctl LIRC_SET_MEASURE_CARRIER_MODE 啟用了載波頻率的測量,則此資料包會為您提供以赫茲為單位的載波頻率。

LIRC_MODE2_TIMEOUT

由於未檢測到紅外訊號,使用 ioctl LIRC_GET_REC_TIMEOUT 和 LIRC_SET_REC_TIMEOUT 設定的超時到期時,將傳送此資料包,其中包含未檢測到紅外訊號的微秒數。

LIRC_MODE2_OVERFLOW

表示紅外接收器遇到溢位,並且丟失了一些紅外訊號。此後的紅外資料應再次正確。實際值並不重要,但核心將其設定為 0xffffff 以與 lircd 相容。

LIRC_MODE_PULSE

在脈衝模式下,一系列脈衝/空間整數值使用 LIRC write() 寫入 lirc 裝置。

這些值是以微秒為單位的脈衝和空間長度交替出現。第一個和最後一個條目必須是脈衝,因此必須有奇數個條目。

此模式僅用於紅外發送。

6.3. LIRC_MODE_SCANCODE 使用的資料型別

struct lirc_scancode

解碼後的掃描碼,帶有用於 LIRC_MODE_SCANCODE 的協議

定義:

struct lirc_scancode {
    __u64 timestamp;
    __u16 flags;
    __u16 rc_proto;
    __u32 keycode;
    __u64 scancode;
};

成員

timestamp

使用 CLOCK_MONOTONIC 解碼紅外訊號時的納秒時間戳。

flags

對於傳輸應為 0。當接收掃描碼時,可以根據協議設定 LIRC_SCANCODE_FLAG_TOGGLE 或 LIRC_SCANCODE_FLAG_REPEAT

rc_proto

請參閱 enum rc_proto

keycode

轉換後的鍵程式碼。對於傳輸設定為 0。

scancode

接收或要傳送的掃描碼

enum rc_proto

遠端控制器協議

常量

RC_PROTO_UNKNOWN

協議未知

RC_PROTO_OTHER

協議已知但專有

RC_PROTO_RC5

Philips RC5 協議

RC_PROTO_RC5X_20

Philips RC5x 20 位協議

RC_PROTO_RC5_SZ

RC5 的 StreamZap 變體

RC_PROTO_JVC

JVC 協議

RC_PROTO_SONY12

Sony 12 位協議

RC_PROTO_SONY15

Sony 15 位協議

RC_PROTO_SONY20

Sony 20 位協議

RC_PROTO_NEC

NEC 協議

RC_PROTO_NECX

擴充套件 NEC 協議

RC_PROTO_NEC32

NEC 32 位協議

RC_PROTO_SANYO

Sanyo 協議

RC_PROTO_MCIR2_KBD

類似 RC6 的 MCE 鍵盤

RC_PROTO_MCIR2_MSE

類似 RC6 的 MCE 滑鼠

RC_PROTO_RC6_0

Philips RC6-0-16 協議

RC_PROTO_RC6_6A_20

Philips RC6-6A-20 協議

RC_PROTO_RC6_6A_24

Philips RC6-6A-24 協議

RC_PROTO_RC6_6A_32

Philips RC6-6A-32 協議

RC_PROTO_RC6_MCE

MCE (Philips RC6-6A-32 子型別) 協議

RC_PROTO_SHARP

Sharp 協議

RC_PROTO_XMP

XMP 協議

RC_PROTO_CEC

CEC 協議

RC_PROTO_IMON

iMon Pad 協議

RC_PROTO_RCMM12

RC-MM 協議 12 位

RC_PROTO_RCMM24

RC-MM 協議 24 位

RC_PROTO_RCMM32

RC-MM 協議 32 位

RC_PROTO_XBOX_DVD

Xbox DVD 電影播放套件協議

RC_PROTO_MAX

enum rc_proto 的最大值

6.4. 基於 BPF 的紅外解碼器

核心支援解碼最常見的 紅外協議,但有許多協議不受支援。為了支援這些協議,可以載入一個 BPF 程式來執行解碼。這隻能在支援讀取原始紅外訊號的 LIRC 裝置上完成。

首先,使用帶有 BPF_LOAD_PROG 引數的 bpf(2) 系統呼叫,必須載入 BPF_PROG_TYPE_LIRC_MODE2 型別的程式。一旦附加到 LIRC 裝置,就會在 LIRC 裝置上的每個脈衝、空間或超時事件中呼叫此程式。BPF 程式的上下文是指向無符號整數的指標,它是 LIRC_MODE_MODE2 值。當程式解碼掃描碼後,可以使用 BPF 函式 bpf_rc_keydown()bpf_rc_repeat() 提交它。可以使用 bpf_rc_pointer_rel() 報告滑鼠或指標移動。

一旦您有了 BPF_PROG_TYPE_LIRC_MODE2 BPF 程式的檔案描述符,就可以使用 bpf(2) 系統呼叫將其附加到 LIRC 裝置。目標必須是 LIRC 裝置的檔案描述符,並且附加型別必須是 BPF_LIRC_MODE2。一次最多可以將 64 個 BPF 程式附加到單個 LIRC 裝置。