【LED子系统】七、触发器实现

news2025/1/15 14:41:34
img
个人主页:董哥聊技术
我是董哥,高级嵌入式软件开发工程师,从事嵌入式Linux驱动开发和系统开发,曾就职于世界500强公司!
创作理念:专注分享高质量嵌入式文章,让大家读有所得!
img

文章目录

    • 1、前言
    • 2、触发器
    • 3、heartbeat触发器的注册注销
    • 4、heartbeat触发器相关定义和实现
      • 4.1 heartbeat_panic_nb
      • 4.2 heartbeat_reboot_nb
      • 4.3 heartbeat_led_trigger
      • 4.4 heartbeat_trig_groups实现
      • 4.5 struct heartbeat_trig_data
      • 4.6 heartbeat_trig_activate
      • 4.7 heartbeat_trig_deactivate
      • 4.8 led_heartbeat_function
    • 5、总结

1、前言

上面几篇文章,我们详细解释了核心层的相关实现,主要包括:led-core.cled-class.cled-triggers.c

下面我们来主要了解一下LED触发器的实现

image-20230417084033734

在上文中,我们提及到led-triggers.c中,只是对外提供了注册注销接口,闪烁设置接口,那么要想去实现闪烁功能,必定要有一个地方去调用这些函数!

 

2、触发器

我们在第一章已经了解到在drivers/leds/trigger/ledtrig-xxx.c中,都是关于触发器的实现,常见的触 发方式如下表所示:

触发方式说明
none无触发方式
disk-activity硬盘活动
nand-disknand flash活动
mtdmtd设备活动
timer定时器
heartbeat系统心跳

不同的触发方式,以控制LED实现不同的效果!下面我们以ledtrig-heartbeat.c为例分析,打开该文件!

 

3、heartbeat触发器的注册注销

static int __init heartbeat_trig_init(void)
{
    int rc = led_trigger_register(&heartbeat_led_trigger);		//	注册到LED子系统框架中

    if (!rc) {
        atomic_notifier_chain_register(&panic_notifier_list,
                           &heartbeat_panic_nb);				//	注册panic通知链路
        register_reboot_notifier(&heartbeat_reboot_nb);			//	注册到重启通知链路
    }
    return rc;
}

static void __exit heartbeat_trig_exit(void)
{
    unregister_reboot_notifier(&heartbeat_reboot_nb);
    atomic_notifier_chain_unregister(&panic_notifier_list,
                     &heartbeat_panic_nb);
    led_trigger_unregister(&heartbeat_led_trigger);
}

module_init(heartbeat_trig_init);
module_exit(heartbeat_trig_exit);

MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
MODULE_DESCRIPTION("Heartbeat LED trigger");
MODULE_LICENSE("GPL v2");

我们分析驱动,一般都以module_init为入口函数,

函数介绍module_init该函数主要将heartbeat_led_trigger定义的触发器注册进入led_classdev中,说明白点,也就是LED子系统中。

实现思路

  1. 调用led_trigger_register接口,将定义的触发器,添加到LED子系统中
  2. 调用atomic_notifier_chain_register接口,将heartbeat_panic_nb注册到panic_notifier_list链路中,在内核发生panic时将调用该链。
  3. 调用register_reboot_notifier接口,注册heartbeat_reboot_nb通知函数,在系统重新启动时将调用该notifier

 

4、heartbeat触发器相关定义和实现

heartbeat_trig_init函数中,我们看到了heartbeat_led_trigger变量,heartbeat_panic_nbheartbeat_reboot_nb等一系列未知函数,那么下面我们分析这些变量的定义和实现!

4.1 heartbeat_panic_nb

static struct notifier_block heartbeat_panic_nb = {
	.notifier_call = heartbeat_panic_notifier,
};

static int heartbeat_panic_notifier(struct notifier_block *nb,
				     unsigned long code, void *unused)
{
	panic_heartbeats = 1;
	return NOTIFY_DONE;
}

函数介绍:该函数主要用于kernel出发panic后执行的函数,这里设置panic_heartbeats = 1后,关闭LED

 

4.2 heartbeat_reboot_nb

static struct notifier_block heartbeat_reboot_nb = {
	.notifier_call = heartbeat_reboot_notifier,
};

static int heartbeat_reboot_notifier(struct notifier_block *nb,
				     unsigned long code, void *unused)
{
	led_trigger_unregister(&heartbeat_led_trigger);
	return NOTIFY_DONE;
}

函数介绍:该函数主要用于系统重启时,调用该函数,来注销掉此触发器。

 

4.3 heartbeat_led_trigger

static struct led_trigger heartbeat_led_trigger = {
	.name     = "heartbeat",
	.activate = heartbeat_trig_activate,
	.deactivate = heartbeat_trig_deactivate,
	.groups = heartbeat_trig_groups,
};

led_trigger结构体在之前文章有分析过, 这里创建heartbeat_led_trigger心跳触发器,然后并配置相关激活函数和sysfs对应的设备文件。

 

4.4 heartbeat_trig_groups实现

static ssize_t led_invert_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct heartbeat_trig_data *heartbeat_data =
		led_trigger_get_drvdata(dev);

	return sprintf(buf, "%u\n", heartbeat_data->invert);
}

static ssize_t led_invert_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	struct heartbeat_trig_data *heartbeat_data =
		led_trigger_get_drvdata(dev);
	unsigned long state;
	int ret;

	ret = kstrtoul(buf, 0, &state);
	if (ret)
		return ret;

	heartbeat_data->invert = !!state;

	return size;
}

static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);

static struct attribute *heartbeat_trig_attrs[] = {
	&dev_attr_invert.attr,
	NULL
};
ATTRIBUTE_GROUPS(heartbeat_trig);

函数介绍led_invert_showled_invert_storesysfs文件系统中,对外开放的文件节点,这两个函数实现了文件节点的读写。

实现思路

  1. 调用led_trigger_get_drvdata接口,获取heartbeat_trig_data相关数据
  2. 读写heartbeat_datainvert属性

这里牵涉到heartbeat_trig_data结构体,我们来了解下

 

4.5 struct heartbeat_trig_data

往下分析前,我们先看一下这个结构体

struct heartbeat_trig_data {
	struct led_classdev *led_cdev;
	unsigned int phase;
	unsigned int period;
	struct timer_list timer;
	unsigned int invert;
};
  • led_cdev:指向struct led_classdev对象的指针
  • phase:表示心跳当前阶段
  • period:表示心跳周期
  • timer:用于调度心跳函数的struct timer_list对象
  • invert:表示是否反转心跳。

 

4.6 heartbeat_trig_activate

static int heartbeat_trig_activate(struct led_classdev *led_cdev)
{
	struct heartbeat_trig_data *heartbeat_data;

	heartbeat_data = kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
	if (!heartbeat_data)
		return -ENOMEM;

	led_set_trigger_data(led_cdev, heartbeat_data);
	heartbeat_data->led_cdev = led_cdev;

	timer_setup(&heartbeat_data->timer, led_heartbeat_function, 0);
	heartbeat_data->phase = 0;
	if (!led_cdev->blink_brightness)
		led_cdev->blink_brightness = led_cdev->max_brightness;
	led_heartbeat_function(&heartbeat_data->timer);
	set_bit(LED_BLINK_SW, &led_cdev->work_flags);

	return 0;
}

函数介绍:该函数的主要功能是为激活对应的LED触发器。

实现方式

  1. 定义heartbeat_trig_data结构体变量,表示触发器的相关数据
  2. 调用led_set_trigger_data接口,将结构体heartbeat_trig_dataled_classdev关联起来
  3. 调用timer_setup接口,配置触发器的定时器函数
  4. 最后调用set_bit,设置工作位为LED_BLINK_SW,表示触发器正常工作

 

4.7 heartbeat_trig_deactivate

static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
{
	struct heartbeat_trig_data *heartbeat_data =
		led_get_trigger_data(led_cdev);

	del_timer_sync(&heartbeat_data->timer);
	kfree(heartbeat_data);
	clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
}

函数介绍:该函数的主要功能是将对应的LED触发器失效

实现方式

  1. 调用del_timer_sync接口,删除定时器
  2. 调用clear_bit接口,清除LED_BLINK_SW位,表示定时器关闭

 

4.8 led_heartbeat_function

static void led_heartbeat_function(struct timer_list *t)
{
    struct heartbeat_trig_data *heartbeat_data =
        from_timer(heartbeat_data, t, timer);			//	获取heartbeat_trig_data数据结构指针
    struct led_classdev *led_cdev;
    unsigned long brightness = LED_OFF;
    unsigned long delay = 0;

    led_cdev = heartbeat_data->led_cdev;

    if (unlikely(panic_heartbeats)) {
        led_set_brightness_nosleep(led_cdev, LED_OFF);
        return;
    }

    if (test_and_clear_bit(LED_BLINK_BRIGHTNESS_CHANGE, &led_cdev->work_flags))
        led_cdev->blink_brightness = led_cdev->new_blink_brightness;				//	判断是否亮度有变化	

    /* acts like an actual heart beat -- ie thump-thump-pause... */
    switch (heartbeat_data->phase) {
    case 0:
        /*
         * The hyperbolic function below modifies the
         * heartbeat period length in dependency of the
         * current (1min) load. It goes through the points
         * f(0)=1260, f(1)=860, f(5)=510, f(inf)->300.
         */
        heartbeat_data->period = 300 +
            (6720 << FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT));
        heartbeat_data->period =
            msecs_to_jiffies(heartbeat_data->period);
        delay = msecs_to_jiffies(70);
        heartbeat_data->phase++;
        if (!heartbeat_data->invert)
            brightness = led_cdev->blink_brightness;
        break;
    case 1:
        delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
        heartbeat_data->phase++;
        if (heartbeat_data->invert)
            brightness = led_cdev->blink_brightness;
        break;
    case 2:
        delay = msecs_to_jiffies(70);
        heartbeat_data->phase++;
        if (!heartbeat_data->invert)
            brightness = led_cdev->blink_brightness;
        break;
    default:
        delay = heartbeat_data->period - heartbeat_data->period / 4 -
            msecs_to_jiffies(70);
        heartbeat_data->phase = 0;
        if (heartbeat_data->invert)
            brightness = led_cdev->blink_brightness;
        break;
    }

    led_set_brightness_nosleep(led_cdev, brightness);
    mod_timer(&heartbeat_data->timer, jiffies + delay);
}

函数介绍led_heartbeat_function 是定时器的核心函数,也是控制心跳LED触发器的关键函数。

实现思路

  1. 通过调用from_timer来获取结构体heartbeat_trig_activate的首地址空间
  2. 调用test_and_clear_bit,判断是否亮度发生变化,如果变化,赋值新的亮度
  3. 中间的case主要适配CPU不同的负载来稳定产生一个稳定的定时效果,并且根据heartbeat_data->invert的值,设置亮灭效果。(PS:注意这里判断heartbeat_data->invert的时候,是有无!的区别来实现亮灭的)
  4. 最后调用led_set_brightness_nosleep将闪烁亮度和延迟设置进去。

 

5、总结

该部分主要实现了心跳灯的效果,表示Linux正常运行,正常情况下,我们这里只需要将该驱动编译进去内核即可实现该效果!

这个驱动程序主要有两个步骤:

  1. 实现驱动框架,赋值相关函数
  2. 产生一个定时器,循环亮灭

 

好啦,到这里我们基本将LED子系统全部详细了解完毕了,真的可谓麻雀虽小,五脏俱全呀,仅仅一个LED子系统,总结下来也花费不少时间,同时也希望大家多多点赞,收藏,支持一波!

点赞+关注,永远不迷路

img
欢迎关注【嵌入式艺术】,董哥原创!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

探索未来:人工智能如何改变室内外设计

目录 注册&#xff1a; 使用RoomGPT进行室内和室外设计的步骤&#xff1a; 结果如下&#xff1a; RoomGPT是一款基于人工智能的设计工具&#xff0c;可以帮助专业人士和个人在几秒钟内生成照片般逼真的图像。以下是使用RoomGPT进行室内和室外设计的步骤&#xff1a; 注册&am…

聚观早报 | ChatGPT炒股回报率超500%;网易发布11新游戏

今日要闻&#xff1a;微信支付正式发布“微信刷掌”产品&#xff1b;ChatGPT炒股回报率超500%&#xff1b;网易发布11新游戏&#xff1b;国家超算中心发布中文大语言模型&#xff1b;B站试水付费专属视频 微信支付正式发布“微信刷掌”产品 5 月 21 日&#xff0c;北京轨道交通…

时序电路详解

1、什么是时序电路&#xff1f; 组合电路是根据当前输入信号的组合来决定输出电平的电路&#xff0c;换言之&#xff0c;就是现在的输出不会被过去的输入所左右&#xff0c;也可以说成是&#xff0c;过去的输入状态对现在的输出状态没有影响的电路。 时序电路和组合电路不同&…

「角」毫米波雷达前装增速放缓?哪些供应商位居TOP10

作为传统BSD&#xff08;盲区监测、并线辅助&#xff09;、DOW&#xff08;开门预警&#xff09;功能以及高阶智能驾驶的主要传感器之一&#xff0c;角&#xff08;盲区&#xff09;毫米波雷达在2022年实现了前装搭载的大幅增长。 高工智能汽车研究院监测数据显示&#xff0c;2…

Qt编写视频监控系统74-悬浮工具栏(半透明/上下左右位置/自定义按钮)

一、前言 在监控系统中一般在视频实时预览的时候&#xff0c;希望提供一个悬浮工具条&#xff0c;可以显示一些提示信息比如分辨率、码率、帧率&#xff0c;提供一堆快捷操作按钮&#xff0c;可以录像、抓拍、云台控制、关闭等操作&#xff0c;参考了国内很多监控厂商客户端软…

Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤

文章目录 ⛄引言一、酒店搜索和分页⛅需求分析⚡源码编写 二、酒店结果过滤⌚需求分析⏰修改搜索业务 ✅效果图⛵小结 ⛄引言 本文参考黑马 分布式Elastic search Elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据…

【社群运营】AI智能对话,打造自动化社群

人工智能大背景下&#xff0c;各行各业都在往智能化发展&#xff0c;无论是办公产品&#xff0c;还是生产器械都选择接入了更加智能的AI来提高生产效率。那么&#xff0c;在日常的社群管理工作中&#xff0c;我们又能否跟上这一波热度&#xff0c;让社群自动化高效运营&#xf…

深度学习实战32-构建ChatT5模型,实现智能问答系统,类ChatGPT(CPU部署)

大家好,我是微学AI,今天给大家介绍一下深度学习实战32-构建ChatT5模型,实现智能问答系统,类ChatGPT(CPU部署),ChatT5使用了T5架构来处理输入文本,具有高度的并行性和扩展性,使其能够快速处理大规模数据集。与传统NLP模型不同,ChatT5采用端到端的方式进行训练,从而可以…

ov2640子设备核心操作详细分析

ov2640子设备核心操作详细分析 文章目录 ov2640子设备核心操作详细分析ov2640_subdev_core_ops核心操作获取寄存器值ov2640_g_register设置寄存器值ov2640_s_registeri2c_smbus_xferi2c_imx_xferi2c_smbus_xfer_emulatedi2c_transfer__i2c_transfer 设置ov2640的电源ov2640_s_p…

解决城市内涝的措施有哪些?需要用到哪些监测设备?

随着城市化的不断推进&#xff0c;城市内涝问题日益凸显。极端天气事件如暴雨、台风等对城市基础设施和居民生活造成了严重影响。那么&#xff0c;解决城市内涝的措施有哪些?需要用到哪些监测设备?针对上述问题&#xff0c;本文会为大家一一进行讲解。 解决城市内涝的措施有哪…

全志V3S嵌入式驱动开发(uboot移植)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 安装了ubuntu操作系统&#xff0c;有了开发板&#xff0c;下面就可以进行我们的开发工作了。第一步&#xff0c;我们要面临的问题就是uboot移植。一…

2098-DSD-020X 具有集成的DeviceNet通信接口

描述:2098-DSD-020X-DN是艾伦-布拉德利Ultra 3000运动控制系列的一部分。该产品是一种数字伺服驱动器&#xff0c;可在120VAC / 240 VAC、单相、50-60 Hz的输入电源电压和18安培的输入电流下运行。该伺服驱动器提供120 / 240 VAC的输出电压、3相、0-400 Hz的可编程频率范围、10…

APACHE-ATLAS-2.1.0简介(二)

APACHE-ATLAS-2.1.0简介(一) 什么是元数据&#xff1f; 元数据(METADATA)&#xff0c;用一句话定义就是&#xff1a;描述数据的数据。元数据打通了数据源、数据仓库、数据应用之间的壁垒&#xff0c;记录了数据从产生到消费的全过程。 ATLAS的问题列表 APACHE-ATLAS-STACKO…

【CANN训练营0基础赢满分秘籍】应用开发深入讲解→模型推理

1 模型离线推理 各步要解析如下: Host&Device内存管理与数据传输: Host&Device上的内存申请与释放&#xff0c;内存间的相互拷贝;模型加载:将离线的om文件加载到Device上;在样例的资源初始化模块中进行。模型输入输出准备∶根据禹线om的输入输出&#xff0c;在Device…

【记者团】社团管理手册

志愿时长&#x1f381;&#xff1a;团内有时会有志愿服务等活动&#xff0c;志愿时长可以找自己班长或班上负责人统计&#xff0c;记者团孙老师会和团委老师对接&#xff0c;团委会记录志愿时长。 志愿时长用于校级奖学金、班级奖学金、校评优评先、青马班面试(青马对入党有帮助…

大数据应用——Hive操作示例

启动Hive完成如下任务: &#xff08;1&#xff09;新建member表&#xff08;2&#xff09;将本地文件“/home/hadoop/member.txt”导入 member表中 (3&#xff09;查询member表中所有记录 &#xff08;4&#xff09;查询member表中男同学&#xff08;性别值为1&#xff09;数…

炸金花底层模拟

一.说明 经常刷视频&#xff0c;看到一个有意思的项目&#xff0c;非常适合练手&#xff0c;今天这里我们实现炸金花的底层模拟。 二.游戏规则 1.一副扑克牌去掉大小王&#xff0c;剩下52张牌2.参与游戏的玩家每人发三张牌3.比较每个人手中牌的大小4.若三张牌相同&#xff0…

【工具】vscode的常用插件之注释插件

&#x1f41a;作者简介&#xff1a;花神庙码农&#xff08;专注于Linux、WLAN、TCP/IP、Python等技术方向&#xff09;&#x1f433;博客主页&#xff1a;花神庙码农 &#xff0c;地址&#xff1a;https://blog.csdn.net/qxhgd&#x1f310;系列专栏&#xff1a;善假于物&#…

CyberLink的视频编辑软件PowerDirector Ultimate 21.4版本在win10系统的下载与安装配置教程

目录 前言一、PowerDirector Ultimate安装二、使用配置总结 前言 PowerDirector Ultimate是由CyberLink公司开发的一款视频编辑软件&#xff0c;其为高级版本&#xff0c;拥有多种强大的视频编辑和效果功能。该软件具有许多强大的功能和工具&#xff0c;包括多轨时间线编辑、视…

CBLUE_中文生物医学语言理解评估基准_源码详解

CBLUE_中文生物医学语言理解评估基准_源码详解 源码链接&#xff1a;https://github.com/CBLUEbenchmark/CBLUE 项目中包括八个不同的中文医学NLP任务&#xff1a;1.中文医学命名实体识别&#xff08;CMeEE&#xff09;、2.中文医学文本实体关系抽取&#xff08;CMeIE&#xf…