OpenHarmony——Linux之IR驱动

Linux之IR驱动

背景

在光谱中波长自760nm至400um的电磁波称为红外线,它是一种不可见光。红外遥控成本很低,以前广泛应用在电视,空调等电器的控制上面,现在随着蓝牙遥控器慢慢普及,红外遥控越来越少,但在某些场景,还保留着红外通信

红外属于media子系统里面的rc(remote control)模块,所以相关驱动代码目录为 drivers/media/rc/

相关内核文档:

  • Documentation/devicetree/bindings/media/gpio-ir-receiver.txt
  • Documentation/devicetree/bindings/media/rc.yaml

下面就从红外的接收、发送和编解码协议简单记录下

接收

红外接收的处理有很多种方式,有些soc有专门的硬件模块,有些使用的是通用的gpio,这里以常见的gpio为例,其他的都大同小异。

用通用的GPIO来接收红外原理比较简单,代码实现主要在:

  • drivers/media/rc/gpio-ir-recv.c
  • drivers/media/rc/rc-main.c
  • drivers/media/rc/rc-ir-raw.c

主要流程

probe函数:
    --> devm_rc_register_device 注册rc设备
    --> devm_request_irq 申请gpio中断(上升沿和下降沿)

中断处理函数 gpio_ir_recv_irq:
    --> gpiod_get_value 获取gpio状态
    --> ir_raw_event_store_edge 保存边沿事件数据

重点的是这里的 devm_rc_register_device() 和 ir_raw_event_store_edge() 函数,下面分开具体来看

devm_rc_register_device()函数

devm_rc_register_device
    -> rc_register_device
        -> ir_raw_event_prepare
            -> timer_setup ir_raw_edge_handle: 设置一个定时器
            -> INIT_KFIFO: 初始化一个fifo,用来保存ir数据
        -> rc_prepare_rx_device: rc_map,keymap相关处理
        -> lirc_register: 注册lirc,后面转发keycodes数据给用户空间
        -> rc_setup_rx_device: 注册input设备
        -> ir_raw_event_register
            -> kthread_run ir_raw_event_thread: 运行一个内核线程,
                -> kfifo_out: 从上面fifo里拿数据
                -> decode: 根据协议解码数据
                -> lirc_raw_event: 通过 lirc 转发到用户空间

注:

  • LIRC(Linux Infrared Remote Control), 主要提供与核外的交互接口,核外有一个对应的开源软件包,这里对 lirc 就不展开了
  • 关于keymap协议相关处理
  • 关于decode解码在后面的部分专门来说明

ir_raw_event_store_edge()函数

ir_raw_event_store_edge: 保存这次的电平pulse及上次边沿到这次边沿的时长duration
    -> ir_raw_event_store_with_timeout: 
        -> ktime_get: 保存这次的时间,为last_event
        -> ir_raw_event_store 
            -> kfifo_put: 保存包含pulse和duration数据(struct ir_raw_event结构)到上面的fifo中
        -> timer 设置timeout 默认15ms

定时器回调函数ir_raw_edge_handle()里面的处理:

ir_raw_edge_handle
    -> 判断时间间隔,ir_raw_event_store 保存超时事件
    -> ir_raw_event_handle 
        -> wake_up_process(dev->raw->thread) 唤醒处理线程

判断时间间隔说明:

如果从上次边沿触发到这次定时器触发的间隔时间interval大于 dev->timeout[这里gpio的方式默认为 IR_DEFAULT_TIMEOUT(125ms)] 就保存一个超时事件 timeout event,否则修改定时器的超时时间为 dev->timeout - ktime_to_us(interval)

发送

发送是接收的逆过程,红外发送主要有通用gpio、pwm等实现方式,主要代码在:

  • drivers/media/rc/gpio-ir-tx.c
  • drivers/media/rc/pwm-ir-tx.c
  • drivers/media/rc/rc-ir-raw.c
  • drivers/media/rc/lirc_dev.c

这里主要记录下常用的pwm方式,原理比较简单:

probe 函数: devm_rc_register_device: 注册rc 设备,重要的代码如下:

rcdev->priv = pwm_ir;
rcdev->driver_name = DRIVER_NAME;
rcdev->device_name = DEVICE_NAME;
rcdev->tx_ir = pwm_ir_tx;
rcdev->s_tx_duty_cycle = pwm_ir_set_duty_cycle;
rcdev->s_tx_carrier = pwm_ir_set_carrier;

rc = devm_rc_register_device(&pdev->dev, rcdev);
if (rc < 0)
    dev_err(&pdev->dev, "failed to register rc device\n");

最主要是下面三个函数:

pwm_ir_tx() 发送最重要的函数,负责控制pwm来发送红外,用户空间通过lirc最后会调用到这里

  • pwm_ir_set_duty_cycle(): 设置pwm的占空比
  • pwm_ir_set_carrier(): 设置pwm载波的频率,默认的是38000,即38K
  • pwm_ir_tx()函数说明

代码如下,

static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
             unsigned int count)
{
    struct pwm_ir *pwm_ir = dev->priv;
    struct pwm_device *pwm = pwm_ir->pwm;
    int i, duty, period;
    ktime_t edge;
    long delta;

    period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, pwm_ir->carrier);
    duty = DIV_ROUND_CLOSEST(pwm_ir->duty_cycle * period, 100);

    pwm_config(pwm, duty, period);

    edge = ktime_get();

    for (i = 0; i < count; i++) {
        if (i % 2) // space
            pwm_disable(pwm);
        else
            pwm_enable(pwm);

        edge = ktime_add_us(edge, txbuf[i]);
        delta = ktime_us_delta(edge, ktime_get());
        if (delta > 0)
            usleep_range(delta, delta + 10);
    }

    pwm_disable(pwm);

    return count;
}

为啥发送这里没有协议编码相关的呢?

上面已经说了,tx_ir函数即这里的pwm_ir_tx()最后会被lirc调用到来发送,所以相关协议编码主要在lirc代码里,即lirc_transmit()里的ir_raw_encode_scancode()函数,调用流程如下:

用户空间调用lirc的write函数
    -> lirc_transmit()
        -> ir_raw_encode_scancode()
            -> encode(): 协议编码
        -> tx_ir(): 发送函数
            -> pwm_ir_tx(): 这里pwm就对应此函数

编解码协议

这里主要记录下最常见最常用的协议之一—NEC协议

NEC协议介绍

NEC协议是众多红外线协议中的一种,以前广泛用在电视机,投影仪设备里,之前的万能电视遥控器就是走的NEC协议

​NEC协议的特征: ​

1.8位地址码和8位命令码长度;

2.单次传输主要分为5部分(不算重复码): 引导码+地址码+地址反码+命令码+命令反码,地址和命令两次传输,提高准确性;

3.停止码主要起隔离作用,一般不进行判断

4.载波频率为38KHz

5.脉冲时间间隔调制

6.位时间为1.125ms和2.25ms,具体见下面说明

NEC码位的定义:一个脉冲对应562.5us的连续载波,一个逻辑1传输需要2.25ms(562.5us脉冲+1687.5us低电平),一个逻辑0的传输需要1.125ms(562.5us脉冲+562.5us低电平)。

​而遥控接收头在收到脉冲时为低电平​,在没有收到脉冲时为高电平,因此, 我们在接收头端收到的信号为:逻辑1应该是562.5us低+1687.5us高,逻辑0应该是562.5us低+562.5us高。

对于接收方:

  • 引导码: 9ms的低电平 + 4.5ms的高电平
  • 逻辑0: 562.5us低电平 + 562.5us高电平
  • 逻辑1: 562.5us低电平 + 1687.5us高电平
  • 重复码:9ms的低电平 + 2.25ms的高电平

对于发送方:

如果我们规定1拍是562.5us载波脉冲, 那么:

  • 引导码: 16拍的红外发射 + 8拍的空闲
  • 逻辑0: 1拍的发射 + 1拍的空闲
  • 逻辑1: 1拍的发射 + 3拍的空闲
  • 重复码:16拍的红外发射 + 4拍的空闲
  • 结束码:1拍的发射

NEC相关代码

内核中nec协议相关的源码实现在: drivers/media/rc/ir-nec-decoder.c

主要提供上面接收和发送时编解码相关的接口和参数,如decode, encode函数,carrier参数等

static struct ir_raw_handler nec_handler = {
    .protocols  = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX |
                            RC_PROTO_BIT_NEC32,
    .decode     = ir_nec_decode,
    .encode     = ir_nec_encode,
    .carrier    = 38000,
    .min_timeout    = NEC_TRAILER_SPACE,
};

想学习更多华为鸿蒙HarmonyOS开发知识,在这里我为大家准备了华为鸿蒙HarmonyOS开发者资料大全,大家可以自行点击链接领取:《做鸿蒙应用开发到底学习些啥?》

其次就是考虑到市场上还没有系统性的学习资料,同时我也整理了一份《鸿蒙 (Harmony OS)开发学习手册》特意整理成PDF文档方式,分享给大家参考学习,大家可以根据自身情况进行获取:《鸿蒙开发学习指南》

《鸿蒙 (Harmony OS)开发学习手册》

一、入门必看

1. 应用开发导读(ArkTS)

2. 应用开发导读(Java)

3.......

二、HarmonyOS 概念

1. 系统定义

2. 技术架构

3. 技术特性

4. 系统安全

5......

三、如何快速入门?《鸿蒙基础入门开发宝典!》

1. 基本概念

2. 构建第一个ArkTS应用

3. 构建第一个JS应用

4. ……

四、开发基础知识

1. 应用基础知识

2. 配置文件

3. 应用数据管理

4. 应用安全管理

5. 应用隐私保护

6. 三方应用调用管控机制

7. 资源分类与访问

8. 学习ArkTS语言

9. ……

五、基于ArkTS 开发

1. Ability开发

2. UI开发

3. 公共事件与通知

4. 窗口管理

5. 媒体

6. 安全

7. 网络与链接

8. 电话服务

9. 数据管理

10. 后台任务(Background Task)管理

11. 设备管理

12. 设备使用信息统计

13. DFX

14. 国际化开发

15. 折叠屏系列

16. ……

更多了解更多鸿蒙开发的相关知识可以参考:《做鸿蒙应用开发到底学习些啥?》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/323800.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

确定性网络技术怎样实现网络的可靠性?

确定性网络技术通过采用特定的协议、机制和策略&#xff0c;有助于提高网络的可靠性。本文通过一些关键的方面&#xff0c;来说明确定性网络技术如何实现这一目标。 时钟同步机制 时钟同步机制是确定性网络中的核心角色。为了实现高度可靠的通信&#xff0c;需要采用先进的时钟…

运筹说 第65期 | 动态规划的基本概念和基本原理

20世纪50年代初&#xff0c;美国数学家R. Bellman 等人在解决多阶段决策优化问题时提出了一种高效的求解方法——动态规划&#xff08;Dynamic Programming&#xff09;&#xff0c;该方法基于多阶段决策优化问题的特点&#xff0c;把多阶段问题转换为一系列互相联系的单阶段问…

档案数字化加工是如何利用档案的

档案数字化加工是通过将实体档案转化为电子形式&#xff0c;利用数字化技术对档案进行处理和管理。这样做可以带来以下几个方面的利益&#xff1a; 1. 提高档案的可访问性&#xff1a;数字化档案可以轻松存储在电脑或云存储中&#xff0c;可以随时随地通过计算机或移动设备访问…

HNU-算法设计与分析-实验3

算法设计与分析实验3 计科210X 甘晴void 202108010XXX 目录 文章目录 算法设计与分析<br>实验31 用Dijkstra贪心算法求解单源最短路径问题问题重述证明模板&#xff1a;Dijkstra算法代码验证算法分析 1【扩展】 使用堆优化的Dijkstra原因代码算法分析验证 2 回溯法求解…

[docker] Compose 简介

文章目录 Compose 简介Compose 安装1、使用二进制安装包安装2、用pip安装 使用1、准备2、创建 Dockerfile 文件3、创建 docker-compose.yml4、使用 Compose 命令构建和运行您的应用 yml 配置指令参考versionbuildcap_add&#xff0c;cap_dropcgroup_parentcommandcontainer_nam…

设计模式⑥ :访问数据结构

一、前言 有时候不想动脑子&#xff0c;就懒得看源码又不像浪费时间所以会看看书&#xff0c;但是又记不住&#xff0c;所以决定开始写"抄书"系列。本系列大部分内容都是来源于《 图解设计模式》&#xff08;【日】结城浩 著&#xff09;。该系列文章可随意转载。 …

《C++大学教程》4.34阶乘

题目&#xff1a; 对一个非负整数n来说&#xff0c;它的阶乘可以写成 n! (读作“n的阶乘”)&#xff0c;其计算公式定义如下&#xff1a; n! n x (n-1) x (n-2)x......x1&#xff08;对于大于1的 n &#xff09; 和 n! 1 ( 对于等于0或者等于1的n ) 例如&#xff0c;5&…

【SpringMVC】—— 如何配置使用SpringMVC(详细步骤)

目录 引言 使用 1、新建模块 2、导入坐标 3、创建SpringMVC控制器类 4、初始化SpringMVC环境 5、初始化Servlet容器&#xff0c;加载SpringMVC环境 6、配置运行 引言 SpringMVC是一种基于Java实现MVC模型的轻量级Web框架&#xff0c;SpringMVC是表现层(web层)的框架,也…

Java开发笔记

一、参数校验 1、校验json字符串是否符合规范 &#xff08;1&#xff09;业务场景&#xff1a;接收前端传输过来的json串&#xff0c;需要将其写入数据库&#xff0c;写入之前需要校验其是否能够转换成对应实体类&#xff0c;以便后续从数据库读取   &#xff08;2&#xff0…

条件控制生成---相关论文集合

1. IP-Adapter 论文地址 解决问题&#xff1a; 如何将图片作为prompt输入网络&#xff0c;并无需更改开源模型参数 解决思路&#xff1a; 新增一个cross-attention layers&#xff0c;结果与text prompt的cross-attention layers结果相加后输入网络&#xff0c;只需要训练Wk, …

细说JavaScript对象(JavaScript对象详解)

在JavaScript中对象作为数据类型之一&#xff0c;它的数据结构区别于其余5中数据类型&#xff0c;从数据结构角度看对象就是数据值的几个&#xff0c;其书就结构就是若干组名值对&#xff0c;类似于其他语言中的哈希、散列 关联数组等&#xff0c;但对象在JavaScript中不仅仅扮…

基于Python+Django,我搭建一个视频点播平台

学习过程中&#xff0c;遇到问题可以咨询作者 功能介绍 平台采用B/S结构&#xff0c;后端采用主流的Python语言进行开发&#xff0c;前端采用主流的Vue.js进行开发。 整个平台包括前台和后台两个部分。 前台功能包括&#xff1a;首页、视频列表页面、视频详情页、用户中心模…

VMware workstation安装Fedora-Server-39-1.5虚拟机并配置网络

VMware workstation安装Fedora-Server-39-1.5虚拟机并配置网络 Fedora包含的软件以自由及开放源码许可来发布&#xff0c;并旨在成为该技术领域的领先者。Fedora在专注创新、抢先集成新技术、与上游Linux社区紧密工作方面拥有良好名声。该文档适用于在VMware workstation平台安…

一篇文章掌握负载均衡Ribbon作用和架构以及核心组件

目录 1、Ribbon是什么 2、Ribbon的作用 1.集中式LB 2.进程式LB 3、Ribbon负载均衡架构 总结&#xff1a; 4、Ribbon核心组件IRule 1、Ribbon是什么 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。 简单的说&#xff0c;Ribbon是Netflix发布…

消失的水母-第15届蓝桥第三次STEMA测评Scratch真题精选

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第165讲。 第15届蓝桥杯第3次STEMA测评已于2023年12月17日落下帷幕&#xff0c;编程题一共有6题&#xff0c;分别如下&…

【野火i.MX6NULL开发板】Linux系统下的Hello World

0、前言 参考资料&#xff1a; 《野火 Linux 基础与应用开发实战指南基于 i.MX6ULL 系列》PDF 第25章 本章比较抽象&#xff0c;涉及理论知识&#xff0c;不明白&#xff0c;可以看看视频讲解&#xff1a; https://www.bilibili.com/video/BV1JK4y1t7io?p29&vd_sourcef…

Day6 Qt

思维导图 1.数据库增删改查 头文件widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QSqlDatabase> //数据库管理类 #include <QSqlQuery> // 执行sql语句类 #include <QSqlRecord> //数据库记录类 #include <QSqlErro…

程序员的健康手册

大家好&#xff0c;我是 javapub。 马上迎来 2024 农历新年&#xff0c;这个是 COVID-19 后的第一个春节。用女朋友的话来说&#xff0c;这几年像在梦里一样&#xff0c;可能生活了几十年的人都想象不到会发生这样的事。不过不论世界怎么变&#xff0c;我们都要过生活、过好当…

leetcode 349 两个数组的集合

题目 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 示例 2&#xff1a; 输入&#xff1a…

LeetCode 0082.删除排序链表中的重复元素 II:模拟

【LetMeFly】82.删除排序链表中的重复元素 II&#xff1a;模拟 力扣题目链接&#xff1a;https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/ 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字…
最新文章