7.3.5. 设计说明¶
7.3.5.1. 源码说明¶
CIR模块的源码位于 bsp/artinchip/:
- bsp/artinchip/drv/cir/drv_cir.c,cir driver层接口实现 
- bsp/artinchip/include/drv/drv_cir.h,cir driver层接口头文件 
- bsp/artinchip/drv/cir/nec_decoder.c,NEC协议编解码实现 
- bsp/artinchip/drv/cir/rc5_decoder.c,RC5协议编解码实现 
- bsp/artinchip/drv/cir/ir_raw.c,编解码调用及注册接口实现 
- bsp/artinchip/drv/cir/ir_raw.h,编解码调用及注册接口头文件 
- bsp/artinchip/hal/cir/hal_cir.c,cir hal层接口实现 
- bsp/artinchip/include/hal/hal_cir.h,cir hal层接口头文件及寄存器定义 
7.3.5.2. 模块架构¶
linux内核中rc的基本框架如下图所示:
 
红外信号的编码和解码工作由CIR协议负责完成。在完成编码后,应用层需要发送的信号被编码为一系列的带有宽度的高低电平(pulse/space),CIR driver在发送端就是需要将这一系列的pulse/space写入发送FIFO发送出去。在接收红外信号时,CIR driver需要将接收到的一系列高低电平送入到CIR协议进行解码,最终将解码得到的scancode返回给driver层,最终送给app程序完成红外信号的接收。所以,CIR驱动的主要任务有:
- 将编码得到的高低电平信号以游码的形式写入TX-FIFO,发送红外信号 
- 将CIR模块接收的RX-FIFO中的游码正确表示为高低电平的形式,相邻的高电平或低电平需要进行合并。 
- 根据用户空间传递的红外参数,对CIR的底层寄存器进行配置,如配置载波频率,配置占空比等 
由于红外信号的数据量都很少,所以在红外信号的发送端,一般是利用循环将所有的数据一次性全部发送出去,而不会采用中断或DMA的方式。在红外信号的接收端,一般是采用中断的方式进行数据的接收,在接收完成后,调用相应的CIR协议解码函数进行解码。
CIR模块理论上可以支持任何的红外协议,对不同红外协议的支持可以通过对载波配置寄存器的设置来实现。luban-lite中目前提供了NEC和RC5协议的编解码,默认配置的是NEC协议。
7.3.5.3. 关键流程设计¶
7.3.5.3.1. 初始化流程¶
CIR模块的初始化流程如下:
- 释放clock和reset信号 
- 设置噪声阈值,接收激活阈值,空闲阈值等底层配置 
- 设置TX-FIFO和RX-FIFO的阈值 
- 将所选择的CIR协议注册到cir_raw_handler_list链表 
7.3.5.3.3. CIR协议注册¶
cir的driver层驱动定义了一个全局链表cir_raw_handler_list,在系统启动时,会根据menuconfig中所选择的红外协议进行注册,实际就是将红外协议添加到链表cir_raw_handler_list,可将NEC和RC5协议同时注册到链表。应用层的代码通过 rt_device_control 设置将要使用的红外协议。在对数据进行编解码时,会查找cir_raw_handler_list链表上是否已注册要使用的红外协议,如已注册,则调用协议的编解码函数。
7.3.5.4. 数据结构设计¶
7.3.5.4.1. driver层数据结构¶
typedef struct aic_cir
{
    struct rt_device    dev;
    aic_cir_ctrl_t      aic_cir_ctrl;
    cir_config_t        config;
} aic_cir_t;
7.3.5.4.2. hal层数据结构¶
typedef enum {
    CIR_EVENT_RECEIVE_COMPLETE,
    CIR_EVENT_ERROR,
} cir_event_t;
typedef struct aic_cir_ctrl aic_cir_ctrl_t;
struct aic_cir_ctrl {
    unsigned long       cir_base;
    uint8_t             irq_num;
    uint8_t             clk_idx;
    void (*callback)(aic_cir_ctrl_t *aic_cir_ctrl, cir_event_t event,
                     void *arg);
    void                *arg;
    uint8_t             tx_data[128];
    uint8_t             rx_data[128];
    uint32_t            rx_idx;
    uint8_t             rx_level;
    uint8_t             rx_flag; /* Indicates if rxfifo has received data */
};
7.3.5.5. 接口设计¶
7.3.5.5.1. driver层接口设计¶
7.3.5.5.1.1. drv_cir_init¶
| 函数原型 | rt_err_t drv_cir_init(rt_device_t pdev) | 
|---|---|
| 功能说明 | CIR模块初始化 | 
| 参数定义 | pdev: 指向CIR设备的指针 | 
| 返回值 | 执行成功返回RT_EOK | 
| 注意事项 | 
7.3.5.5.1.2. drv_cir_open¶
| 函数原型 | rt_err_t drv_cir_open(rt_device_t pdev, rt_uint16_t oflag) | 
|---|---|
| 功能说明 | 打开红外模块 | 
| 参数定义 | pdev: 指向CIR设备的指针 oflag: 打开设备时设置的标志 | 
| 返回值 | 执行成功返回RT_EOK,否则返回-RT_EINVAL | 
| 注意事项 | oflag可设置的值: RT_DEVICE_FLAG_WRONLY RT_DEVICE_FLAG_RDONLY RT_DEVICE_FLAG_RDWR RT_DEVICE_FLAG_INT_RX 设置RT_DEVICE_FLAG_RDONLY时,必须同时设置RT_DEVICE_FLAG_INT_RX | 
7.3.5.5.1.3. drv_cir_close¶
| 函数原型 | rt_err_t drv_cir_close(rt_device_t pdev) | 
|---|---|
| 功能说明 | 关闭红外模块 | 
| 参数定义 | pdev: 指向CIR设备的指针 | 
| 返回值 | 执行成功返回RT_EOK | 
| 注意事项 | 
7.3.5.5.1.4. drv_cir_read¶
| 函数原型 | rt_size_t drv_cir_read(rt_device_t pdev, rt_off_t pos, void *buffer, rt_size_t size) | 
|---|---|
| 功能说明 | 读取CIR接收到的红外信号 | 
| 参数定义 | pdev: 指向CIR设备的指针 buffer: 指向接收数据的指针 size: 读取的数据字节数 | 
| 返回值 | 执行成功返回0 | 
| 注意事项 | 
7.3.5.5.2. hal层接口设计¶
7.3.5.5.2.1. hal_cir_set_tx_carrier¶
| 函数原型 | int hal_cir_set_tx_carrier(aic_cir_ctrl_t * aic_cir_ctrl, uint8_t protocol, uint32_t tx_duty); | 
|---|---|
| 功能说明 | 设置CIR的发送载波参数 | 
| 参数定义 | aic_cir_ctrl: 指向aic_cir_ctrl_t的指针 protocol: 使用的CIR协议 tx_duty: 协议的占空比 | 
| 返回值 | 执行成功返回0 | 
| 注意事项 | protocol取值: NEC, 0; RC5, 1 tx_duty: 若占空比为33%,则tx_duty设置为33 | 
7.3.5.5.2.2. hal_cir_send_data¶
| 函数原型 | void hal_cir_send_data(aic_cir_ctrl_t * aic_cir_ctrl, uint8_t * tx_data, uint32_t size); | 
|---|---|
| 功能说明 | CIR发送数据 | 
| 参数定义 | aic_cir_ctrl: 指向aic_cir_ctrl_t的指针 tx_data: 指向要发送的数据指针 size: 发送的数据字节数 | 
| 返回值 | 执行成功返回0 | 
| 注意事项 | 
7.3.5.5.2.3. hal_cir_set_rx_sample_clock¶
| 函数原型 | void hal_cir_set_rx_sample_clock(aic_cir_ctrl_t * aic_cir_ctrl, uint8_t protocol); | 
|---|---|
| 功能说明 | 设置CIR接收采样时钟 | 
| 参数定义 | aic_cir_ctrl: 指向aic_cir_ctrl_t的指针 protocol: 使用的CIR协议 | 
| 返回值 | 执行成功返回0 | 
| 注意事项 | 
