Linux内核红外遥控子系统LIRCWord下载.docx

上传人:b****6 文档编号:20463457 上传时间:2023-01-23 格式:DOCX 页数:14 大小:167.83KB
下载 相关 举报
Linux内核红外遥控子系统LIRCWord下载.docx_第1页
第1页 / 共14页
Linux内核红外遥控子系统LIRCWord下载.docx_第2页
第2页 / 共14页
Linux内核红外遥控子系统LIRCWord下载.docx_第3页
第3页 / 共14页
Linux内核红外遥控子系统LIRCWord下载.docx_第4页
第4页 / 共14页
Linux内核红外遥控子系统LIRCWord下载.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

Linux内核红外遥控子系统LIRCWord下载.docx

《Linux内核红外遥控子系统LIRCWord下载.docx》由会员分享,可在线阅读,更多相关《Linux内核红外遥控子系统LIRCWord下载.docx(14页珍藏版)》请在冰豆网上搜索。

Linux内核红外遥控子系统LIRCWord下载.docx

脉冲宽度1200微秒表示逻辑1,宽度600微秒表示逻辑0.

幀格式

当按下遥控器上的按键时,遥控器会发送一个命令信号,这个信号就是一个幀,它包含了命令字段和地址(设备)字段,以及扩展字段。

当按住按键不放时,遥控器会不断的发送这一命令信号,直到松开。

SIRC协议的幀格式有12位、15位、20位三种,如下所示:

一个幀以一个起始标志(图中的红色)开始,它是一个2400微秒的脉冲并跟一个间隔。

之后是7字节的命令字段(图中的橙色),这个字段用于识别按下了遥控器上的哪个按键;

然后是地址字段(图中的蓝色),用于识别控制的是什么类型的设备;

对于20位宽格式,还有一个扩展字段,用于传输其他信息。

址值和设备类型映射表

一种命令值和具体按键的映射表

示例:

Sony电视遥控器上“音量-”按键对应的脉冲波形

对于脉冲波形的解码,一般用一个专门的硬件单元完成,也可以在CPU中利用如GPIO等检测接收器输出的波形然后使用软件的方式解码,但这种方式效率显然很低。

2.Linux对红外遥控的支持

Linux上通过LIRC子系统对红外控制提供支持,它包含几个部分:

lirc核心、协议原始脉冲解码器、按键映射表、红外输入设备驱动。

LIRC代码在:

drivers/media/IR

2.1.协议原始脉冲解码器模块

解码器模块实现用软件的方法对原始脉冲进行解码。

解码器用一个ir_raw_handler结构表示。

structir_raw_handler

{

structlist_headlist;

int(*decode)(structinput_devinput_dev,structir_raw_eventevent);

/*解码函数*/

int(*raw_register)(structinput_devinput_dev);

/*注册函数*/

int(*raw_unregister)(structinput_devinput_dev);

/*卸载函数*/

};

解码器通过注册和卸载函数:

intir_raw_handler_register(structir_raw_handler*ir_raw_handler)

voidir_raw_handler_unregister(structir_raw_handler*ir_raw_handler)

当注册解码器时,ir_raw_handler的raw_register函数被调用,所以可在其进行一些解码器初始化工作。

相应的,卸载时raw_unregister函数被调用。

所有注册的解码器放在一个全局链表ir_raw_handler_list中,lirc会便利每个解码器对报告的波形进行解码,注意,此时当任何一个解码器返回一个错误,后面的解码器不会被执行,所以不要将不使用的解码器模块同时加载到内核中。

解码器的主体就是decode函数,lirc核心会将驱动报告的每个脉冲一次一次的传递到decode函数,而decode函数的实现就是一个状态机,每一次输入导致进入下一状态,直到一次解码完成,然后返回起始状态进行下次解码。

再LIRC中,每个脉冲(包括脉冲间隔)用一个ir_raw_event结构表示:

structir_raw_event

unsignedpulse:

1;

/*是脉冲还是间隔*/

unsignedduration:

31;

/*宽度,以ns为单位,一个0ns的脉冲表示重新开始解码*/

lirc中对于脉冲宽度的比较使用eq_margin()、geq_margin()函数,它允许宽度值在二分之一单元上下波动。

boolgeq_margin(unsignedd1,unsignedd2,unsignedmargin)

booleq_margin(unsignedd1,unsignedd2,unsignedmargin)

解码器的完整实现可参考sonysirc解码器实现:

ir-sony-decoder.c

2.2.按键映射表模块

按键映射模块都放在keymaps目录下。

不同的遥控器有不同的按键映射,按键映射模块的作用就是将扫描码与Linuxinput系统标准事件对应起来。

映射表的注册和卸载:

intir_register_map(structrc_keymap*map)

voidir_unregister_map(structrc_keymap*map)

按键映射模块的主体就是一个ir_scancode结构数组,每个元素是一对按键映射。

2.3.红外输入设备驱动

红外输入设备驱动负责向LIRC核心报告脉冲或直接报告扫描码事件。

红外输入设备用ir_input_dev结构描述:

structir_input_dev

structdevicedev;

/*device*/

char*driver_name;

/*Nameofthedrivermodule*/

structir_scancode_tablerc_tab;

/*scan/keytable*/

unsignedlongdevno;

/*devicenumber*/

conststructir_dev_props*props;

/*Deviceproperties*/

structir_raw_event_ctrl*raw;

/*forrawpulse/spaceevents*/

structinput_dev*input_dev;

/*theinputdeviceassociatedwiththisdevice*/

/*keyinfo-neededbyIRkeycodehandlers*/

spinlock_tkeylock;

/*protectsthebelowmembers*/

boolkeypressed;

/*currentstate*/

unsignedlongkeyup_jiffies;

/*whenshouldthecurrentkeypressbereleased?

*/

structtimer_listtimer_keyup;

/*timerforreleasingakeypress*/

u32last_keycode;

/*keycodeoflastcommand*/

u32last_scancode;

/*scancodeoflastcommand*/

u8last_toggle;

/*toggleoflastcommand*/

设备注册和卸载:

intir_input_register(structinput_dev*dev,constchar*map_name,

conststructir_dev_props*props,constchar*driver_name)

voidir_input_unregister(structinput_dev*input_dev)

注册流程:

(1)分配一个input设备,input_allocate_device();

(2)对input设备进行一些初始化设置,但事件掩码不需要设置;

(3)将分配的input设备结构的地址作为参数调用ir_input_register(),以后与lirc核心的交互都是通过这个input设备结构的地址进行的。

ir_input_register()函数的map参数指定要使用的按键映射表,所有映射表定义在rc-map.h中,比如RC_MAP_RC5_TV。

props参数可以为NULL,但若要使用解码器模块对原始脉冲解码(比如无法直接从硬件获得扫描码时),则要设置。

比如:

staticstructir_dev_propsirc_props={

.driver_type=RC_DRIVER_IR_RAW,/*指定需要软件解码*/

.allowed_protos=IR_TYPE_SONY,

input_dev=input_allocate_device();

if(!

irc_input_dev){

ret=-ENOMEM;

gotoerr_input_allocate_device;

}

input_dev->

name="

IRC"

;

ret=ir_input_register(input_dev,RC_MAP_RC5_TV,&

irc_props,NULL);

if(ret){

gotoerr_ir_input_register;

input_dev->

rep[REP_DELAY]=400;

rep[REP_PERIOD]=33;

对于可直接从硬件读取到扫描码的设备,可用以下函数包括扫描码事件:

voidir_keydown(structinput_dev*dev,intscancode,u8toggle)

对于只能获得原始脉冲的设备,需先调用下面函数报告每个脉冲和脉冲间隔:

intir_raw_event_store(structinput_dev*input_dev,structir_raw_event*ev);

intir_raw_event_store_edge(structinput_dev*input_dev,enumraw_event_typetype)

第一个函数要求驱动自己填充ir_raw_event结构,并且在报告第一个脉冲前,需要调用ir_raw_event_reset()函数重置解码器,当驱动认为一个完成的波形已报告完毕后,调用ir_raw_event_handle()启动解码;

第二个函数自动生成一个ir_raw_event结构,脉冲宽度根据前后两次调用ir_raw_event_store_edge()函数的时间间隔字段计算,并且会自动调用ir_raw_event_reset()和ir_raw_event_handle()函数。

type参数指定是何脉冲。

enumraw_event_type

IR_SPACE=(1<

<

0),

IR_PULSE=(1<

1),

IR_START_EVENT=(1<

2),

IR_STOP_EVENT=(1<

3),

其他两个驱动常用的接口:

voidir_repeat(structinput_devdev)/*重复上次按键*/

u32ir_g_keycode_from_table(structinput_devinput_dev,u32scancode)/*获得扫描码对应的按键*/

2.4.LIRC对按住按键时重复事件的处理

首先,重复是自动的,它使用了input子系统的REP功能。

当第一次向lirc报一个扫描码事件时,lirc会向input子系统报告相应的按键事件,并启动一个定时器,该定时器在超时后会上报对应的按键松开事件;

之后若在250ms(这个值等于input子系统的rep延时的默认值)内该设备又报告了同一个扫描码,这时只是将定时器再推后250ms,并不报告新的按键事件,也就是说按键的重复由input系统处理。

这种设计主要是考虑到遥控器的限制,有的遥控器没有按键按下和松开之分(虽然在按下和松开时都有脉冲,但没有区分字段,而且有时可能会丢失信号)。

3.附使用GPIO接收遥控命令驱动代码

#include<

linux/init.h>

linux/module.h>

linux/interrupt.h>

linux/gpio.h>

linux/platform_device.h>

linux/workqueue.h>

linux/time.h>

linux/irq.h>

linux/spinlock.h>

media/ir-core.h>

asm/irq.h>

#defineGPIO_IRC_MAPRC_MAP_SONY_SIRC12_TV

//#defineDEBUG

staticstructinput_dev*irc_input_dev;

staticstructtimer_listirc_timer;

staticatomic_tf_restart;

externu64gpt_get_cycles(void);

externunsignedlonggpt_delta_to_ns(u64delta);

staticvoidgpio_irc_raw_event_reset()

ir_raw_event_reset(irc_input_dev);

atomic_set(&

f_restart,1);

}

staticvoidgpio_irc_timer_func(unsignedlongdata)

structir_raw_eventev;

/*endpulse*/

ev.pulse=false;

ev.duration=~0u;

ir_raw_event_store(irc_input_dev,&

ev);

ir_raw_event_handle(irc_input_dev);

gpio_irc_raw_event_reset();

#ifdefDEBUG

printk("

gpio_ircrestartevent\n"

);

#endif

staticirqreturn_tgpio_irc_rx_irq(intirq,void*dev_id)

staticbooltriger_falling=1;

staticunsignedlonglast;

if(atomic_read(&

f_restart)){

atomic_set(&

f_restart,0);

}else{

ev.pulse=!

triger_falling;

ev.duration=gpt_delta_to_ns((unsignedlong)gpt_get_cycles()-last);

ir_raw_event_store(irc_input_dev,&

last=(unsignedlong)gpt_get_cycles();

if(triger_falling)

set_irq_type(irq,IRQF_TRIGGER_RISING);

else

set_irq_type(irq,IRQF_TRIGGER_FALLING);

triger_falling=!

mod_timer(&

irc_timer,jiffies+HZ/50);

returnIRQ_HANDLED;

staticstructir_dev_propsgpio_irc_props={

.driver_type=RC_DRIVER_IR_RAW,

staticintgpio_irc_probe(structplatform_device*pdev)

intgpio,gpio_irq;

intret;

gpio=pdev->

resource[0].start;

gpio_irq=gpio_to_irq(gpio);

if(gpio_request(gpio,"

gpio_irc"

)){

dev_err(&

pdev->

dev,"

rxpinnotavailable\n"

return-1;

gpio_direction_input(gpio);

setup_timer(&

irc_timer,gpio_irc_timer_func,gpio_irq);

irc_input_dev=input_allocate_device();

irc_input_dev->

MXCGPIOIRreceiver"

ret=ir_input_register(irc_input_dev,GPIO_IRC_MAP,&

gpio_irc_props,NULL);

pr_err("

gpio_irc:

ir_input_register()failed\n"

gotoerr_ir_input_register;

ret=request_irq(gpio_irq,gpio_irc_rx_irq,0,"

pdev);

dev,"

unabaletorequestirq\n"

gotoerr_request_irq;

set_irq_type(gpio_irq,IRQF_TRIGGER_FALLING);

return0;

err_request_irq:

ir_input_unregister(irc_input_dev);

err_ir_input_register:

input_free_device(irc_input_dev);

err_input_allocate_device:

gpio_free(gpio);

returnret;

staticintgpio_irc_remove(structplatform_device*pdev)

del_timer_sync(&

irc_timer);

free_irq(gpio_irq,NULL);

staticintgpio_irc_suspend(structplatform_device*pdev,pm_message_tstate)

staticintgpio_irc_resume(structplatform_device*pdev)

staticstructplatform_driverirc_driver={

.driver={

.name="

},

.probe=gpio_irc_probe,

.remove=gpio_irc_remove,

.suspend=gpio_irc_suspend,

.resume=gpio_irc_resume,

staticintgpio_irc_init(void)

returnplatform_driver_register(&

irc_driver);

staticvoidgpio_irc_exit(void)

platform_driver_unregister(&

late_initcall_sync(gpio_irc_init);

module_exit(gpio_irc_exit);

MODULE_LICENSE("

GPL"

MODULE_DESCRIPTION("

infraredremotecontrolthroughgpio"

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 研究生入学考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1