【Linux驱动】设备树模型的LED驱动 | 查询方式的按键驱动
🐱作者:一只大喵咪1201
🐱专栏:《Linux驱动》
🔥格言:你只管努力,剩下的交给时间!
目录
- 🍮设备树模型的LED驱动
- 🍩设备树文件
- 🍩驱动程序
- 🍮应用层读取按键值
- 🍩查询方式
- 🍩休眠唤醒方式
- 🍩poll方式
- 🍩异步通知方式
- 🍮查询方式实现按键驱动
- 编程
- 🍮总结
🍮设备树模型的LED驱动
目前有三种方式来写LED驱动程序:
- 最简单的驱动模型——硬件操作绑定在驱动函数中。
- 总线驱动模型。
- 设备树驱动模型。
下面设备树驱动模型来实现一下LED驱动程序,该模型主要分为两部分,设备树文件和驱动程序。
🍩设备树文件
如上图所示设备树文件,在设备树中增加Big-Miaomi-LED@0
和Big-Miaomi-LED@1
两个设备节点:
-
compatible
属性:属性值都是BigMiaomi,LED_Driver
。 -
pin
属性:属性值是各自节点所用GPIO组和引脚编号组成的32位整数。 -
如果在设备树节点里使用
reg
属性,内核在生成对应的platform_device
时,reg
属性会被转换成IORESOURCE_MEM
类型的资源。 -
如果在设备树节点里使用
interrputs
属性,内核在生成对应的platform_device
时,interrupts
属性会被转换成IORESOURCE_IRQ
类型的资源。
但是本喵写的Big-Miaomi-LED
节点中,属性名是pin
,该属性名是本喵自己定义的,不在内核自动转换资源类型的的命名范围内。
所以就不能从转换后的platform_device
结构体中的resources
数组中获得引脚资源了,具体获取方式编程时候再说。
如上图,然后在内核目录中使用make dtbs
指令编译设备树文件,转换为内核认识的dtb
文件。
🍩驱动程序
驱动程序在总线驱动模型的基础上进行修改,驱动层的上层不用动,只需要改变下层中的部分代码:
如上图所示,由于现在支持了设备树,所以需要初始化platform_deiver
结构体中driver
成员里的of_match_table
成员,这是一个struct of_device_id
类型的数组。
所以需要定义一个struct of_device_id
类型的数组,名为BigMiaomi_LEDs
:
- 只用
platform_device
和platform_driver
匹配规则中优先级最高的compatible
属性来匹配。 - 只支持LED设备,所以
compatible
属性只有一个值。
compatible属性的值,必须和设备树中要支持节点的compatible属性值相同,才能匹配成功。
然后就是在匹配成功以后,会自动调用paltform_driver
中的probe
函数,在该函数中,原本是从paltform_device
的resources
数组中获取硬件资源,但是此时不能这样干了:
如上图所示probe
函数,在该函数中首先要获取pin
资源:
- 设备树中的
pin
属性没有被转换到resources
数组中,但是在第一次转换为device_node
里的properties
中是有该属性的。- 从匹配成功的
platform_device
中得到当前节点的device_node
结构体指针of_node
。
- 从匹配成功的
- 使用
of_property_read_32
函数,从np
指向的当前节点deivce_node
中的properties
里找到pin
属性,并且以32位整数的方式读取该属性的value
值。- 将表示引脚资源的32位属性值放入到记录引脚资源的全局数组
g_ledpins
中。
- 将表示引脚资源的32位属性值放入到记录引脚资源的全局数组
获取到引脚资源后的其他操作和总线模型中相同,也是要使用led_class_create_device
在/dev
目录下创建设备节点。
- 设备树文件中的设备节点,内核加载后并不会在
/dev
目录下创建相应的文件,它不属于文件字符设备文件系统。
如上图代码所示,既然probe
中的获取引脚资源的方式变了,那么在remove
中获取引脚资源的方式和其他处理也要做出相应变化:
- 从要移除设备节点的
device_node
中获取引脚资源led_pin
。 - 遍历存放引脚资源的全局数组找到要移除的节点,移除后将对应的值修改为-1。
- 最后判断一下是否该类型的设备节点全部移除了,如果存放引脚资源的全局数组中,所有值都成了-1,则说明全部移除了。
此时整个驱动程序就修改完毕了,相比于总线驱动模型,只是在获取引脚资源的方式上做了改变。
如上图所示Makfile
文件,只需要编译驱动层上层led_drv.c
和下层chip_led_opr.c
即可,board_A.c
不用再参与编译了。
- 因为引脚资源不再由
board_A.c
中的platform_device
结构体提供了。 - 引脚资源由设备树文件提供,由内核将设备节点转换为
platform_device
结构体。
如上图所示,将在Linux服务器中编译好的dtb
设备树文件和led_drv.ko
及chip_led_opr.ko
驱动文件,还有led_drv_test
测试文件拷贝到网络根文件系统中。
在开发板上将dtb
设备树文件拷贝到/boot
目录下,然后重启开发板.
如上图所示,在/sys/firmware/devicetree/base/
路径下,存在Big-Miaomi-LED@0
和Big-Miaomi-LED@1
两个设备节点,这是我们在设备树文件中添加的两个节点,此时加载到了内核中。然后使用insmod led_drv.ko
和insmod chip_led_opr.ko
安装驱动程序。
如上图所示,此时执行测试程序,在命令行中输入./led_drv_test /dev/BigMiaomi_LED0 on
,内核打印信息现实操作了GPIO3_1
。
🍮应用层读取按键值
应用层读取按键值有4种方式:
- 查询方式
- 休眠-唤醒方式
- poll方式
- 异步通知方式
无论使用哪个方式都需要有按键驱动程序,通过这四种方式可以掌握一些驱动的基本技能:中断、休眠、唤醒、poll等机制。
这些基本技能是驱动开发的基础,其他大型驱动复杂的地方是它的框架及设计思想,但是基本技能就只有这些。
🍩查询方式
如上图所示查询方式的驱动模型,这种方式最简单,这里并不考虑驱动层中的架构,只看驱动层所做的工作。
在驱动程序中构造并注册一个file_operations
结构体,里面提供对应的drv_open
和drv_read
函数,当应用层调用open
系统调用时,在驱动层的drv_open
函数中配置相应的引脚为输入引脚。
当应用层调用read
系统调用时,在驱动层的drv_read
函数中读取该GPIO引脚的寄存器,把引脚的状态返回给应用层。
- 读取引脚状态时,直接返回寄存器中的值,没有其他多余的动作。
🍩休眠唤醒方式
如上图所示休眠唤醒方式的驱动模型,在驱动层中的drv_open
函数中,除了要把GPIO设置为输入引脚,还有注册GPIO的中断处理函数。
当应用层调用read
系统调用时,在驱动层的drv_read
驱动函数中:
- 如果有按键数据,则直接返回给应用层。
- 如果没有按键数据,则应用层的APP在内核态休眠。
当用户按下按键时,GPIO
中断被触发,导致drv_open
中注册的中断服务程序被执行,在中断服务程序中:
- 记录按键数据。
- 唤醒休眠中的应用层APP。
应用层的APP被唤醒以后,继续在内核态运行,即执行驱动层代码,把中断服务程序中记录的按键数据返回给应用层的APP。
- 没有读取到数据时,就会休眠,直到有按键数据到来才被唤醒。
🍩poll方式
上面的休眠-唤醒方式存在一个缺点:如果用户一直没有按下按键,那么应用层的APP就永远休眠阻塞不再执行了,所以可以给APP定个闹钟,这就是poll方式:
如上图所示poll
驱动模型,poll
是应用层实现多路转接的系统调用接口,在驱动层的file_operations
结构体中,同样有一个poll
函数指针:
如上图所示file_operations
结构体的定义,所以当应用层的APP调用poll
系统调用时,会调用到驱动层该结构体中poll
函数指针指向的函数。
所以需要我们在驱动层去定义poll
函数指针指向的函数,使得整个驱动层符合poll
驱动模型。驱动层总体步骤为:
- 注册
file_operations
结构体,里面提供open
,read
,poll
等驱动层的函数。 - 应用层APP调用
open
时,驱动层的drv_open
会将GPIO设置为输入引脚,并且注册中断处理函数。 - 应用层APP调用
poll/select
时,意图是查询按键数据是否就绪,并且可以指定一个超时时间:- 当按键数据就绪时,驱动层的
poll
向应用层返回就绪状态,APP继续使用read
读取按键数据。 - 当按键数据没有就绪时,驱动层的
poll
就会在内核态休眠一段时间。
- 当按键数据就绪时,驱动层的
当APP被唤醒时,有两种情况:
- 在休眠期间,硬件按键被按下,按键数据就绪。
- 超时时间到了,硬件按键仍然没有按下,按键数据没有就绪。
被唤醒后进行判断,如果是数据就绪被唤醒,则调用read
从按键的寄存器中读取按键数据,如果是超时被唤醒,则不调用read
去读取了。
poll/select
起到监视事件就绪的作用,驱动层的drv_poll
都会告诉应用层APP所监视事件的状态。- APP根据驱动层告知的事件状态进行下一步动作。
🍩异步通知方式
如上图所示异步通知方式,在该模型中,应用层在打开要操作的设备时,要调用fcntl
设置其fd
的FASYNC
标志,此时会调用驱动层的drv_fasync
函数:
如上图所示,在file_operations
结构体中也有一个fsync
函数指针,在该模型中,该指针指向的函数只需要记录当前进程的PID。
除了设置给fd
设置FASYNC
表示异步通知外,还需要使用signal
系统调用注册信号处理函数my_func
。
此时该模型的处理步骤为:
- APP调用
open
配置GPIO引脚为输入方式,并注册中断服务函数。 - APP调用
fcntl
设置fd
指向的文件为异步通知方式,并且注册信号处理函数. - 当硬件按键被按下时,中断服务程序会给记录下来的进程PID表示的进程发送信号,信号递达后执行注册的
my_func
信号处理函数。 - 在信号处理函数中,调用
read
来读取按键数据,此时必然是有按键数据的。
- 在没有按键按下时,APP正常执行,当按键按下后立刻去读取按键数据,使得应用层实现了中断的处理方式。
我们的驱动程序可以实现上述 4 种提供按键驱动的方法,但是驱动程序不应该限制APP使用哪种方法。
- 这就是驱动设计的一个原则:只提供能力,不提供策略。
就是说,APP想用哪种方法都行,驱动程序都可以提供;但是驱动程序不能限制APP使用哪种方法。
🍮查询方式实现按键驱动
前面介绍了按键的四种驱动模型,但是由于后面三种都涉及到中断方面的知识,而到目前为止本喵还没有介绍驱动程序中的中断,所以这里先仅用查询方式实现一下按键驱动程序:
如上图所示,采用简单的驱动层分层模型来实现查询方式的按键驱动层数:
- 应用层
open/read
系统调用和驱动层的drv_open/drv_read
通过file_operations
结构体来建立联系。 - 驱动层上层的
drv_open/drv_read
和驱动层下层的board_button_init/board_button_read
通过button_opr
结构体连建立联系。
驱动层下层的board_button_init/board_button_read
由具体的单板提供:
- 驱动层下层的
board_button_init
根据设备号确定哪个按键,并将GPIO配置为输入引脚。 - 驱动层下层的
board_button_read
根据设备号确定哪个按键,并读取对应寄存器中的值返回引脚电平。
驱动层上层:
如上图所示,在button_operations.h
中定义button_operations
结构体:
count
:表示按键设备个数init
:驱动层下层提供的初始化按键设备方法。read
:驱动层下层提供的读取按键状态方法。
如上图所示,在button_drv.c
中,创建file_operations
结构体,并且用drv_open
和drv_read
初始化open
和read
函数指针:
- 在
drv_open
函数中,使用p_button_opr
结构体中的init
,根据次设备号进行初始化。 - 在
drv_read
函数中,使用p_button_opr
结构体中的read
,根据次设备号读取按键状态。- 将读取到的按键状态
level
拷贝到用户层缓冲区。
- 将读取到的按键状态
如上图所示,在入口函数button_init
中使用register_chrdev
向内核中注册file_operations
结构体,并且获得主设备号。还要创建button_class
设备类来提供设备信息。
在出口函数button_exit
中,销毁设备类button_class
,并且使用unregister_chrdev
函数从内核中将前面注册的file_operations
移除。
如上图,由于p_button_opr
结构体指针是由驱动层下层提供的,所以驱动层上层要提供一个register_button_operations
函数给下层,让下层向上层注册p_button_opr
结构体。
- 在注册时,还要将所有按键设备使用
device_create
在文件系统中创建设备节点文件。 - 在卸载时,使用
device_destroy
将文件系统中的所有按键设备文件移除掉。
由于下层在使用这两个函数时会用到上层的button_class
类,所以这两个函数需要使用EXPORT_SYMBOL
导出给下层,供下层先使用。
如上图,最后完善一下设备信息,告诉内核哪个是入口函数,哪个是出口函数,并且声明该驱动程序使用GPL
协议。
驱动层下层:
如上图所示,在驱动层下层的board_button.c
文件中,创建button_operations
结构体,并进行初始化:
count
:按键设备有两个。init
:初始化按键设备的函数board_button_init
。read
:读取按键设备状态的函数board_button_read
。
在入口函数中,使用驱动层上层提供的register_button_operations
函数将下层创建的my_button_oprs
结构体对象注册到上层,供上层使用下层提供的初始化和读取数据的方法。
在出口函数汇中,使用上层提供的unregister_button_operations
函数移除在文件系统中创建的设备节点文件。
最后完善一下设备信息。
对于驱动层下层,重点在于初始化和读取数据函数的实现:
如上图所示IMX6ULL
按键的电路原理图:
KEY1
:与GPIO5_1
相连,按键按下时是低电平(0),未按下时是高电平(1)。KEY2
:与GPIO4_IO14
相连,按键按下时是低电平(0),未按下时是高电平(1)。
- 使能GPIO
如上图所示使能GPIO的寄存器:
CCM_CCGR1
:物理地址是0x020C406C
,其中的[31,30]
控制GPIO5
的使能,但是这里保留了,GPIO5
默认使能,CCM_CCGR3
:物理地址是0x020C4074
,其中的[13,12]
控制GPIO
的使能,当这两个比特位为11
时,GPIO4
使能。
- 选择GPIO模式
如上图所示IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1
寄存器:
- 物理地址是
0x0229000C
。 MUX_MODE
:这四个bit为101
时,表示GPIO5_IO01
引脚用作通用GPIO。
如上图所示IOMUXC_SW_MUX_CTL_PAD_NAND_CE1_B
寄存器:
- 物理地址是
0x020E01B0
。 MUX_MODE
:这四个bit为0101
时,表示GPIO4_IO14
引脚用作通用GPIO。
- 设置GPIO方向
如上图所示内存映射表:
GPIO5
:该组寄存器的基地址是0x020AC000
。GPIO4
:该组寄存器的基地址是0x020A8000
。
如上图所示GPIO所有寄存器的内存映射表,以GPIO4
为例:
- 一共8个寄存器,每组GPIO都是这样。
- 从
DR
寄存器开始,到EDGE_SEL
寄存器结束,地址从低到高,每个寄存器所占4个字节。
所以定义一个结构体来描述GPIO组中的所有寄存器:
如上图所示结构体,用该结构体创建gpio5
和gpio4
结构体对象来操作相应的GPIO。
如上图所示GDIR
寄存器:
- 对于
GPIO5_1
:将gpio5->gdir
的bit1
设置为0,表示输入。 - 对于
GPIO4_14
:将gpio4->gdir
的bit14
设置为0,表示输入。
- 读取按键状态:
如上图所示PSR
寄存器:
- 对于
GPIO5_1
:gpio5->psr
的bit1
为0,表示按键按下,为低电平,为1,表示按键没有按下,为高电平。 - 对于
GPIO4_14
:gpio4->gdir
的bit14
为0,表示按键按下,为低电平,为1,表示按键没有按下,为高电平。
编程
如上图所示,在驱动层下层board_button.c
中,将用到的寄存器全部定义出来,并且创建gpio4
和gpio5
两个结构体变量来表示GPIO。
board_button_init:
如上图所示初始化函数中:
- 将所有涉及到的寄存器都在内存中映射相应的虚拟地址,只映射一次。
- 其中GPIO组进行整体映射,大小为
struct imx6ull_gpio
结构体的大小。
- 其中GPIO组进行整体映射,大小为
- 根据次设备号对GPIO口进行初始化,控制相关寄存器。
- 使能GPIO组,设置引脚模式为通用GPIO,设置方向为输入。
board_button_read:
如上图所示读取按键数据的函数,根据次设备号确定读取gpio5
还是gpio4
中的psr
寄存器,然后返回该寄存器中的值。
应用层测试函数:
如上图应用层测试函数,在测试的时候,命令行中输入./button_test /dev/BigMiaomi_button0
或者./button_test /dev/BigMiaomi_button1
,在mian
函数中会使用read
系统调用去获取按键状态,最终会调用驱动层下层的board_button_read
函数。
- 如果打印1,表示按键没有按下。
- 如果打印0,表示按键按下。
如上图所示Makefile
文件中,make
以后:
- 会生成
button_test
可执行程序,用来测试。 - 会生成
button_drv.ko
和board_button.ko
两个模块文件,用来安装驱动程序。
如上图所示,在开发板上安装两个按键的驱动程序,可以看到在./dev
目录下有BigMiaomi_button0
和BigMiaomi_button1
两个设备节点。
如上图所示,在开发板上执行测试程序:
- 未在开发板上按下
KEY1
和KEY2
两个按键时,打印出的值是1,表示高电平,和电路逻辑相符。 - 按下开发板上按下
KEY1
和KEY2
两个按键时,打印出的值是0,表示低电平,和电路逻辑相符。
🍮总结
要会使用设备树向内核中注册设备节点,并且会对驱动程序做相应的修改。除此之外,要知道APP读取按键的四种方式,以及实现简单的APP按键驱动程序编程。
相关文章:
【Linux驱动】设备树模型的LED驱动 | 查询方式的按键驱动
🐱作者:一只大喵咪1201 🐱专栏:《Linux驱动》 🔥格言:你只管努力,剩下的交给时间! 目录 🍮设备树模型的LED驱动🍩设备树文件🍩驱动程序 …...
GZ075 云计算应用赛题第4套
2023年全国职业院校技能大赛(高职组) “云计算应用”赛项赛卷4 某企业根据自身业务需求,实施数字化转型,规划和建设数字化平台,平台聚焦“DevOps开发运维一体化”和“数据驱动产品开发”,拟采用开源OpenSt…...
小型肉制品厂废水处理设备加工厂家
诸城市鑫淼环保小编带大家了解一下小型肉制品厂废水处理设备加工厂家 在小型肉制品厂,处理肉类加工废水是非常重要的环保问题。废水中含有蛋白质、脂肪、悬浮物和有机物等,需要进行合适的处理以减少对环境的污染。以下是一些常见的小型肉制品厂废水处理设…...
SpringBoot整合ElasticSearch实现CRUD操作
本文来说下SpringBoot整合ES实现CRUD操作 文章目录 概述项目搭建ES简单的crud操作本文小结 概述 SpringBoot支持两种技术和es交互。一种的jest,还有一种就是SpringData-ElasticSearch。根据引入的依赖不同而选择不同的技术。反正作为spring全家桶,目前是…...
香橙派--关于jammy-xfce-arm64.f12a43b3e629442a073a7236bf9166ce.tar.lz4的rootfs定制与镜像制作
使用 x64 的 Ubuntu22.04 电脑编译 Linux SDK,即 orangepi-build,支持在安装有 Ubuntu 22.04 的电脑上运行,所以下载 orangepi-build 前,请首先确保自己电脑已安装的 Ubuntu 版本是 Ubuntu22.04。查看电脑已安装的 Ubuntu 版本的命…...
前端八股文(HTML篇)一
目录 1.什么是DOCTYPE,有何用呢? 2.说说对html语义化的理解 3.src和href的区别? 4.title与h1的区别,b与strong的区别,i与em的区别? 5.什么是严格模式与混杂模式? 6.前端页面有哪三层构成,分…...
数据结构与算法python版本之线性结构之无序表抽象数据类型有序链表抽象数据类型和总结
我们知道,列表List是一种简单强大的数据集结构,提供了丰富的操作接口;但是并不是所有的编程语言都提供了List数据类型,有时候需要程序员自己实现。 那么什么是列表呐? 列表是一种数据项按照相对位置存放的数据集&…...
识别pdf中论文标题并重命名PDF名称(2024.1.2,第二次更新)判断标题中是否以空格结尾
63~66行增加语句,判断标题是否以空格结尾 83~85行增加语句,判断选句是否以空格结尾 import os import timeimport fitzdef find_largest_font_sentence(pdf_path):largest_font_size 0largest_font_sentence maxsize0# 打开PDF文件document fitz.ope…...
01.02作业
整理思维导图复习课上代码全局变量,int monster 10000;定义英雄类hero,受保护的属性string name,int hp,int attck;公有的无参构造,有参构造,虚成员函数 void Atk(){blood-0;},法师类继承自英雄…...
WPF+Halcon 培训项目实战(11):HS组件封装
文章目录 前言相关链接项目专栏运行环境匹配图片封装组件新增类库项目选择依赖顺序并添加Nuget修改原本矩形方法运行结果: 对矩形进行抽象封装抽象基类矩形抽象改造 圆形抽象封装代码运行结果 前言 为了更好地去学习WPFHalcon,我决定去报个班学一下。原…...
VUE——IDEA 启动前端工程VS文件启动前端工程
IDEA 启动前端 目录 前言一、打开控制台二、输入npm install三、依赖下载完之后,输入npm run dev,运行前端项目1、IDEA启动前端工程2、文件目录启动前端工程 四、点击http://localhost:8080后续敬请期待 前言 启动已有的vue前端项目 一、打开控制台 选…...
自动驾驶论文
文章目录 一、Convolutional Social Pooling for Vehicle Trajectory Prediction二、QCNet:Query-Centric Trajectory Prediction三、VectorNet: Encoding HD Maps and Agent Dynamics from Vectorized Representation 一、Convolutional Social Pooling for Vehicl…...
Java经典框架之SpringDataJPA
SpringDataJPA Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring整合Hibernate 2…...
向爬虫而生---Redis 基石篇3 <拓展List>
前言: 继上一篇向爬虫而生---Redis 基石篇2 <拓展Hash>-CSDN博客.往下继续---挖一挖list 正文: 在Redis中,列表(List)是一个常用的数据结构,尤其在爬虫应用中。例如,可以用列表实现…...
CSS渲染性能优化
✨ 专栏介绍 HTML/CSS专栏合集是一个涵盖HTML和CSS两个方面的栏目。HTML是一种标记语言,用于创建网页的结构和内容,而CSS是一种样式表语言,用于控制网页的外观和布局。 在HTML/CSS专栏合集中,我们将深入探讨HTML和CSS的基础知识…...
【C++入门】类和对象(完)
前言 在谈论C时,常常会涉及到一些高级特性和概念,比如初始化列表、static成员、友元、内部类、匿名对象等。这些概念在C编程中起着非常重要的作用,对于想要深入了解C语言的开发者来说,掌握这些知识是至关重要的。本文,…...
webshell检测方式深度剖析 --- Pixy系列二(数据流分析)
开篇 书接上文,这次我们来聊聊数据流分析,数据流分析的内容非常广泛,我们力求深入浅出通俗易懂,在简短的篇幅内将这一概念描述清楚。 简单来说,数据流分析是一种用来获取相关数据沿着程序执行路径流动的信息分析技术…...
[DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]
文章目录 概要I Introduction小结 概要 提出的架构,双注意力U-Net与特征融合(DAU-FI Net),解决了语义分割中的挑战,特别是在多类不平衡数据集上,这些数据集具有有限的样本。DAU-FI Net 整合了多尺度空间-通…...
使用Triton部署ONNX模型
介绍 适用于各种 AI 工作负载的推理:借助 NVIDIA Triton™,在任何处理器(GPU、CPU 或其他)上,对使用基于任何框架的,经过训练的机器学习模型或深度学习模型,进行推理部署。Triton 是 NVIDIA AI…...
Python访问ElasticSearch
ElasticSearch是广受欢迎的NoSQL数据库,其分布式架构提供了极佳的数据空间的水平扩展能力,同时保障了数据的可靠性;反向索引技术使得数据检索和查询速度非常快。更多功能参见官网介绍 https://www.elastic.co/cn/elasticsearch/ 下面简单罗列…...
Flutter 混合开发 - 动态下发 libflutter.so libapp.so
背景 最近在做包体积优化,在完成代码混淆、压缩,裁剪ndk支持架构,以及资源压缩(如图片转webp、mp3压缩等)后发现安装包的中占比较大的仍是 so 动态库依赖。 具体查看发现 libflutter.so 和 libapp.so 的体积是最大的&…...
Peter算法小课堂—动态规划
Peter推荐算法书:《算法导论》 图示: 目录 钢条切割 打字怪人 钢条切割 算法导论(第四版)第十四章第一节:钢条切割 题目描述: 给定一根长度为 n 英寸的钢条和一个价格表 ,其中 i1,2,…,n …...
2022–2023学年2021级计算机科学与技术专业数据库原理 (A)卷
一、单项选择题(每小题1.5分,共30分) 1、构成E—R模型的三个基本要素是( B )。 A.实体、属性值、关系 B.实体、属性、联系 C.实体、实体集、联系 D.实体、实体…...
Clojure 实战(4):编写 Hadoop MapReduce 脚本
Hadoop简介 众所周知,我们已经进入了大数据时代,每天都有PB级的数据需要处理、分析,从中提取出有用的信息。Hadoop就是这一时代背景下的产物。它是Apache基金会下的开源项目,受Google两篇论文的启发,采用分布式的文件…...
Django 分页(表单)
目录 一、手动分页二、分页器分页 一、手动分页 1、概念 页码:很容易理解,就是一本书的页码每页数量:就是一本书中某一页中的内容(数据量,比如第二页有15行内容),这 15 就是该页的数据量 每一…...
socket实现视频通话-WebRTC
最近喜欢研究视频流,所以思考了双向通信socket,接下来我们就一起来看看本地如何实现双向视频通讯的功能吧~ 客户端获取视频流 首先思考如何获取视频流呢? 其实跟录音的功能差不多,都是查询电脑上是否有媒体设备,如果…...
simulink代码生成(九)—— 串口显示数据(纸飞机联合调试)
纸飞机里面的协议是固定的,必须按照协议配置; (1)使用EasyHEX协议,测试int16数据类型 测试串口发出的数据是否符合? 串口接收数据为: 打开纸飞机绘图侧: (1)…...
Mysql数据库(中)——增删改查的学习(全面,详细)
上一篇主要对查询操作进行了详细的总结,本篇主要对增删改操作以及一些常用的函数进行总结,包括流程控制等;以下的代码可以直接复制到数据库可视化软件中,便于理解和练习; 常用的操作: #函数: S…...
test dbtest-03-对比 Liquibase、flyway、dbDeploy、dbsetup
详细对比 Liquibase、flyway、dbDeploy、dbsetup,给出对比表格 下面是一个简要的对比表格,涵盖了 Liquibase、Flyway、dbDeploy 和 DbSetup 这四个数据库变更管理工具的一些主要特点。 特点/工具LiquibaseFlywaydbDeployDbSetup开发语言Java࿰…...
力导向图与矩阵排序
Graph-layout force directed(力导向图布局)是一种用于可视化网络图的布局算法。它基于物理模型,模拟了图中节点之间的相互排斥和连接弹性,以生成具有良好可读性和美观性的图形布局。 在力导向图布局中,每个节点被视为…...
wordpress 模特模板/提交网址给百度
时间滑动计算 今天遇到一个需求大致是这样的,我们有一个业务涉及到用户打卡,用户可以一天多次打卡,我们希望计算出7天内打卡8次以上,且打卡时间分布在4天以上的时间,当然这只是个例子,我们具体解释一下这个需求 用户一天可以打卡多次,所以要求打卡必须分布在4天以上7天…...
建设部的网站/seo站长优化工具
下面是定义初始化 #初始化输入的张量 - torch.empty是返回一个包含未初始化数据的张量self.input torch.empty(size(self.opt.batchsize, 3, self.opt.isize, self.opt.isize), dtypetorch.float32, deviceself.device)self.label torch.empty(size(self.opt.batchsize,), dt…...
流量网站应该怎么做/百度seo排名点击器
一、什么是AS(ActionScript) ActionScript,简称AS,中译为“动作脚本语言”。 用于在Flash上实现一些光用Flash无法实现的功能。 在Flash界面下的动作面板中编写AS。 二、时间轴控制命令 初识AS,首先让我们来认识一下AS…...
wordpress用户中心授权码/营业推广策略
阅读本文前,请您先点击上面的蓝色字体,再点击“关注”,这样您就可以继续免费收到最新文章了。每天都有分享。完全是免费订阅,请放心关注。 …...
建设部指定招标网站/站长之家ip地址查询
上一篇ESFramework扩展之EsfP2P -- 基于ESFramework的P2P实现 主要介绍了EsfP2P如何协助建立P2P Session,那只是整个故事的一半,EsfP2P主要职能的另一半是确保P2P消息的可靠传递。我们已经知道,目前的EsfP2P扩展的实现…...
网站做数据统计/品牌广告语经典100条
1. web标准介绍 w3c:万维网联盟组织,用来制定web标准的机构(组织) web标准:制作网页遵循的规范 web标准规范的分类:结构标准、表现标准、行为标准。 结构:html。表示:css。行为&a…...