lv15 input子系统框架、外设驱动开发 5

一、input子系统基本框架

 在我们日常的Linux系统中,存在大量的输入设备,例如按键、鼠标、键盘、触摸屏、摇杆等,他们本身就是字符设备,linux内核将这些字符设备的共同性抽象出来,简化驱动开发建立了一个input子系统。

Linux内核为了两个目的:

  1. 简化纯输入类外设(如:键盘、鼠标、游戏杆、轨迹球、触摸屏。。。等等)的驱动开发

  2. 统一输入类外设产生的数据格式(struct input_event),更加方便应用层编程

设计了输入子系统框架

Linux 内核驱动可以都是遵循一个逐层抽象的架构: 最上层的抽象层便于系统软件的访问,中间层的实现硬件协议细节,同时提供上下两层连接的接口,对于最下层的 driver 来说就是要定义底层驱动要实现的接口和实际的设备控制,由于 Linux 内核各类驱动的框架支持,driver 可以更加关注设备本身的特性。
Linux输入子系统(linux input subsystem)也不例外,从上到下可以分为三层实现,分别为:输入子系统事件处理层(EventHandler)、输入子系统核心层(InputCore)和输入子系统设备驱动层。

事件处理层:接收来自核心层上报的事件,并选择对应的handler(事件处理器 struct input_handler)去处理。内核维护着多个事件处理器对象,每个input_handler对象专门处理一类事件,所有产生同类事件的设备驱动共用同一个handler。

设备驱动层:主要实现获取硬件设备的数据信息(包括触摸屏被按下、按下位置、鼠标移动、键盘按下等等),并转换为核心层定义的规范事件后提交给核心层,该层每个设备对应一个struct input_dev对象,

核心层:负责连接设备驱动层和事件处理层,为设备驱动层提供输入设备驱动的接口(struct input_dev)以及输入设备驱动的注册函数(input_register_device),为事件处理层提供输入事件驱动的接口;通知事件处理层对事件进行处理。

二、驱动开发步骤

/*init或probe函数中:
1. 创建struct input_dev对象input_allocate_device
2. 设置事件类型以及相关参数set_bit
3. 注册struct input_dev对象input_register_device
*/
​
/*exit或remove函数中:
1. 注销struct input_dev对象input_unregister_device
2. 销毁struct input_dev对象input_free_device
*/
​
/*上报事件两种事件上报方式:1. 对有中断支持的输入设备:在其中断处理函数(上半部或下半部)中上报事件2. 对无中断支持的输入设备:使用workqueue循环定时上报(struct delayed_work)主要函数:input_event       //通用上报,上报的是分量,如x轴分量input_report_abs  //上报绝对坐标input_sync        //完整数据检查统一上报在这边处理,如x、y、z轴数据统一上报
*/
​

相关接口:

/*_init*/
struct input_dev *input_allocate_device(void)//创建对象
​
void set_bit(struct input_dev *dev,unsigned long whichbits)//设置事件类型
​
void input_set_abs_params(struct input_dev *dev,unsigned int axis,int min,int max,int fuzz,int flat)
​
int input_register_device(struct input_dev *dev)//注册input设备到内核
​
/*_exit*/
void input_unregister_device(struct input_dev *dev)
void input_free_device(struct input_dev *dev)
​
/*上报事件*/
void input_event(struct input_dev *,unsigned int t,unsigned int c,int v)
​
void input_report_key(struct input_dev *,unsigned int c,int v) //上报按键事件
void input_report_abs(struct input_dev *,unsigned int c,int v)//上报绝对坐标事件void input_sync(struct input_dev *)//上报完成后需要调用这些函数来通知系统处理完整事件
​
/*应用层数据类型*/
struct input_event {struct timeval time;       // 时间戳__u16 type;             // 事件类型__u16 code;             // 哪个分值__s32 value;            // 具体值      
};

三、key2-input版代码解析

借用直接按键驱动的代码,按键中所有根字符设备相关的input子系统已经帮我们实现好了,都可以不需要。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/input.h>   //<------------
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/uaccess.h>struct fs4412key2_dev
{struct input_dev *pdev;int gpio;int irqno;
};struct fs4412key2_dev *pgmydev = NULL;irqreturn_t key2_irq_handle(int no,void *arg)  
{struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)arg;int status1 = 0;int status2 = 0;status1 = gpio_get_value(pmydev->gpio);mdelay(1);status2 = gpio_get_value(pmydev->gpio);if(status1 != status2){return IRQ_NONE;}if(status1){input_event(pmydev->pdev,EV_KEY,KEY_2,0);    //<--------------------上报事件,0按下input_sync(pmydev->pdev);                    //往核心层上报}else{input_event(pmydev->pdev,EV_KEY,KEY_2,1);    //<--------------------上报事件,1抬起input_sync(pmydev->pdev);                    //往核心层上报}return IRQ_HANDLED;
}int __init fs4412key2_init(void)
{int ret = 0;struct device_node *pnode = NULL;pnode = of_find_node_by_path("/fs4412-key2");if(NULL == pnode){printk("find node failed\n");return -1;}pgmydev = (struct fs4412key2_dev *)kmalloc(sizeof(struct fs4412key2_dev),GFP_KERNEL);if(NULL == pgmydev){printk("kmallc for struct fs4412key2_dev failed\n");return -1;}pgmydev->gpio = of_get_named_gpio(pnode,"key2-gpio",0);pgmydev->irqno = irq_of_parse_and_map(pnode,0);//<---------------------pgmydev->pdev = input_allocate_device();  //分配pdev空间set_bit(EV_KEY,pgmydev->pdev->evbit);     //设置事件set_bit(KEY_2,pgmydev->pdev->keybit);     //上报的哪个按键ret = input_register_device(pgmydev->pdev);//注册到系统ret = request_irq(pgmydev->irqno,key2_irq_handle,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"fs4412key2",pgmydev);if(ret){printk("request_irq failed\n");input_unregister_device(pgmydev->pdev);  //反操作input_free_device(pgmydev->pdev);        //反操作kfree(pgmydev);pgmydev = NULL;return -1;}return 0;
}void __exit fs4412key2_exit(void)
{free_irq(pgmydev->irqno,pgmydev);input_unregister_device(pgmydev->pdev);    //反操作input_free_device(pgmydev->pdev);          //反操作kfree(pgmydev);pgmydev = NULL;
}MODULE_LICENSE("GPL");module_init(fs4412key2_init);
module_exit(fs4412key2_exit);

测试

testkey.2

#include <sys/types.h>
#include <sys/stat.h>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>#include <stdio.h>int main(int argc,char *argv[])
{int fd = -1;struct input_event evt;if(argc < 2){printf("Argument is too few\n");return 1;}/*open*/fd = open(argv[1],O_RDONLY);if(fd < 0){printf("open %s failed\n",argv[1]);return 2;}/*init mpu6050*/while(1){read(fd,&evt,sizeof(evt));if(evt.type == EV_KEY && evt.code == KEY_2){if(evt.value){printf("KEY2 DOWN\n");}else{printf("KEY2 UP\n");}}}/*close*/close(fd);fd = -1;return 0;
}

Makefile 

ifeq ($(KERNELRELEASE),)ifeq ($(ARCH),arm)
KERNELDIR ?= /home/linux/Linux_4412/kernel/linux-3.14
ROOTFS ?= /opt/4412/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesmodules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_installclean:rm -rf  *.o  *.ko  .*.cmd  *.mod.*  modules.order  Module.symvers   .tmp_versionselseCONFIG_MODULE_SIG=nobj-m += fs4412_key2.oendif

 编译拷贝到跟文件系统测试

 

四、mpu6050-input版代码解析

mpu6050_drv_input.c

注:绝对坐标的上报事件,如角速度加速度无变化核心层会屏蔽掉,除非有变化

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/input.h>
#include <linux/io.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>#define SMPLRT_DIV 0x19
#define CONFIG 0x1A
#define GYRO_CONFIG 0x1B
#define ACCEL_CONFIG 0x1C#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48#define PWR_MGMT_1  0x6Bstruct mpu6050_dev
{struct input_dev * pinput;   //<---------------------struct i2c_client *pclient;struct delayed_work work;    //可设置时间,到时间work回调函数会被调用
};struct mpu6050_dev *pgmydev = NULL;int mpu6050_read_byte(struct i2c_client *pclt,unsigned char reg)
{int ret = 0;char txbuf[1] = {reg};char rxbuf[1] = {0};struct i2c_msg msg[2] = {{pclt->addr,0,1,txbuf},{pclt->addr,I2C_M_RD,1,rxbuf}};ret = i2c_transfer(pclt->adapter,msg,ARRAY_SIZE(msg));if(ret < 0){printk("ret = %d,in mpu6050_read_byte\n",ret);return ret;}return rxbuf[0];
}int mpu6050_write_byte(struct i2c_client *pclt,unsigned char reg,unsigned char val)
{int ret = 0;char txbuf[2] = {reg,val};struct i2c_msg msg[1] = {{pclt->addr,0,2,txbuf},};ret = i2c_transfer(pclt->adapter,msg,ARRAY_SIZE(msg));if(ret < 0){printk("ret = %d,in mpu6050_write_byte\n",ret);return ret;}return 0;
}void mpu6050_work_func(struct work_struct *pwk)
{struct mpu6050_dev *pmydev = container_of((struct delayed_work *)pwk,struct mpu6050_dev,work);unsigned short ax = 0;unsigned short ay = 0;unsigned short az = 0;unsigned short gx = 0;unsigned short gy = 0;unsigned short gz = 0;unsigned short temp = 0;ax = mpu6050_read_byte(pmydev->pclient,ACCEL_XOUT_L);ax = mpu6050_read_byte(pmydev->pclient,ACCEL_XOUT_H) << 8;input_report_abs(pmydev->pinput,ABS_X,ax);    //<-----上报分量ay = mpu6050_read_byte(pmydev->pclient,ACCEL_YOUT_L);ay = mpu6050_read_byte(pmydev->pclient,ACCEL_YOUT_H) << 8;input_report_abs(pmydev->pinput,ABS_Y,ay);az = mpu6050_read_byte(pmydev->pclient,ACCEL_ZOUT_L);az = mpu6050_read_byte(pmydev->pclient,ACCEL_ZOUT_H) << 8;input_report_abs(pmydev->pinput,ABS_Z,az);gx = mpu6050_read_byte(pmydev->pclient,GYRO_XOUT_L);gx = mpu6050_read_byte(pmydev->pclient,GYRO_XOUT_H) << 8;input_report_abs(pmydev->pinput,ABS_RX,gx);gy = mpu6050_read_byte(pmydev->pclient,GYRO_YOUT_L);gy = mpu6050_read_byte(pmydev->pclient,GYRO_YOUT_H) << 8;input_report_abs(pmydev->pinput,ABS_RY,gy);gz = mpu6050_read_byte(pmydev->pclient,GYRO_ZOUT_L);gz = mpu6050_read_byte(pmydev->pclient,GYRO_ZOUT_H) << 8;input_report_abs(pmydev->pinput,ABS_RZ,gz);temp = mpu6050_read_byte(pmydev->pclient,TEMP_OUT_L);temp = mpu6050_read_byte(pmydev->pclient,TEMP_OUT_H) << 8;input_report_abs(pmydev->pinput,ABS_MISC,temp);input_sync(pmydev->pinput);        //<----------绝对坐标真正上报,如角速度加速度无变化核心层会屏蔽掉,除非有变化schedule_delayed_work(&pgmydev->work,msecs_to_jiffies(1000));  //<---------延时1秒调用
}void init_mpu6050(struct i2c_client *pclt)
{mpu6050_write_byte(pclt,PWR_MGMT_1,0x00);mpu6050_write_byte(pclt,SMPLRT_DIV,0x07);mpu6050_write_byte(pclt,CONFIG,0x06);mpu6050_write_byte(pclt,GYRO_CONFIG,0xF8);mpu6050_write_byte(pclt,ACCEL_CONFIG,0x19);
}static int mpu6050_probe(struct i2c_client *pclt,const struct i2c_device_id *pid)
{int ret = 0;pgmydev = (struct mpu6050_dev *)kmalloc(sizeof(struct mpu6050_dev),GFP_KERNEL);if(NULL == pgmydev){printk("kmalloc failed\n");return -1;}memset(pgmydev,0,sizeof(struct mpu6050_dev));pgmydev->pclient = pclt;init_mpu6050(pgmydev->pclient);pgmydev->pinput = input_allocate_device();     //<-----------------set_bit(EV_ABS,pgmydev->pinput->evbit);        //<-----------------设置绝对坐标类事件input_set_abs_params(pgmydev->pinput,ABS_X,-32768,32767,0,0);   //<--------32768,32767代表取值范围,0误差范围,0代表不使用平滑参数值input_set_abs_params(pgmydev->pinput,ABS_Y,-32768,32767,0,0);input_set_abs_params(pgmydev->pinput,ABS_Z,-32768,32767,0,0);input_set_abs_params(pgmydev->pinput,ABS_RX,-32768,32767,0,0);input_set_abs_params(pgmydev->pinput,ABS_RY,-32768,32767,0,0);input_set_abs_params(pgmydev->pinput,ABS_RZ,-32768,32767,0,0);input_set_abs_params(pgmydev->pinput,ABS_MISC,-32768,32767,0,0); //温度ret = input_register_device(pgmydev->pinput);  //<-----------------if(ret){printk("input_register_device failed\n");input_free_device(pgmydev->pinput);pgmydev->pinput = NULL;kfree(pgmydev);pgmydev = NULL;return -1;}INIT_DELAYED_WORK(&pgmydev->work,mpu6050_work_func);   //<-----------------schedule_delayed_work(&pgmydev->work,msecs_to_jiffies(1000));  //<-----------------1s后函数会被调用return 0;
}static int mpu6050_remove(struct i2c_client *pclt)
{cancel_delayed_work(&pgmydev->work);        //<-----------------取消每隔1秒的函数input_unregister_device(pgmydev->pinput);   //<-----------------input_free_device(pgmydev->pinput);pgmydev->pinput = NULL;kfree(pgmydev);pgmydev = NULL;return 0;
}struct of_device_id mpu6050_dt[] = 
{{.compatible = "invensense,mpu6050"},{}
};struct i2c_device_id mpu6050_ids[] = 
{{"mpu6050",0},{}
};struct i2c_driver mpu6050_driver = 
{.driver = {.name = "mpu6050",.owner = THIS_MODULE,.of_match_table = mpu6050_dt,},.probe = mpu6050_probe,.remove = mpu6050_remove,.id_table = mpu6050_ids,
};#if 0
int __init mpu6050_driver_init(void)
{i2c_add_driver(&mpu6050_driver);
}void __exit mpu6050_driver_exit(void)
{i2c_del_driver(&mpu6050_driver);
}
module_init(mpu6050_driver_init);
module_exit(mpu6050_driver_exit);
#else
module_i2c_driver(mpu6050_driver);
#endifMODULE_LICENSE("GPL");

testmpu6050_input.c

#include <sys/types.h>
#include <sys/stat.h>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>#include <stdio.h>int main(int argc,char *argv[])
{int fd = -1;struct input_event evt;if(argc < 2){printf("Argument is too few\n");return 1;}/*open*/fd = open(argv[1],O_RDONLY);if(fd < 0){printf("open %s failed\n",argv[1]);return 2;}/*init mpu6050*/while(1){read(fd,&evt,sizeof(evt));if(evt.type == EV_ABS){switch(evt.code){case ABS_X:printf("Accel-x:%d\n",evt.value);break;case ABS_Y:printf("Accel-y:%d\n",evt.value);break;case ABS_Z:printf("Accel-z:%d\n",evt.value);break;case ABS_RX:printf("Gyro-x:%d\n",evt.value);break;case ABS_RY:printf("Gyro-y:%d\n",evt.value);break;case ABS_RZ:printf("Gyro-z:%d\n",evt.value);break;case ABS_MISC:printf("Temp:%d\n",evt.value);break;}}}/*close*/close(fd);fd = -1;return 0;
}

Makefile

ifeq ($(KERNELRELEASE),)ifeq ($(ARCH),arm)
KERNELDIR ?= /home/linux/Linux_4412/kernel/linux-3.14
ROOTFS ?= /opt/4412/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesmodules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_installclean:rm -rf  *.o  *.ko  .*.cmd  *.mod.*  modules.order  Module.symvers   .tmp_versionselseCONFIG_MODULE_SIG=nobj-m += mpu6050_drv_input.oendif

编译拷贝到rootfs 

验证 

有数值变化才会上传值

拓展:

网络设备、块设备 的开发套路设计思想也类似。

网络设备面向的是协议栈

块设备面向的是文件系统

字符设备面向的是应用层

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

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

相关文章

羊大师的羊奶有几种口味呢?

羊大师提供的羊奶有6种不同口味可供选择。 1.新鲜羊奶不仅没有膻味&#xff0c;而且富含高钙无糖&#xff0c;并且含有丰富的优质蛋白质和超过200种营养物质。这非常适合缺钙或体弱的人饮用。 2.益生菌羊奶是一种含有保加利亚乳杆菌、嗜酸乳杆菌、双歧杆菌等益生菌群的产品&…

基于物联网的工业企业能耗监控系统

上海安科瑞电气股份有限公司 胡冠楠 咨询家&#xff1a;“Acrelhgn”&#xff0c;了解更多产品资讯 摘要&#xff1a;针对工业制造企业存在高能耗、高污染的问题&#xff0c;提出了一种用于工业企业能耗监控的多层级网络系统。本系统可完成企业内部电力、水资源以及燃气等能源…

如何探索和可视化用于图像中物体检测的 ML 数据

近年来&#xff0c;人们越来越认识到深入理解机器学习数据&#xff08;ML-data&#xff09;的必要性。不过&#xff0c;鉴于检测大型数据集往往需要耗费大量人力物力&#xff0c;它在计算机视觉&#xff08;computer vision&#xff09;领域的广泛应用&#xff0c;尚有待进一步…

陇剑杯 2021刷题记录

题目位置&#xff1a;https://www.nssctf.cn/上有 陇剑杯 2021 1. 签到题题目描述分析答案小结 2. jwt问1析1答案小结 问2析2答案小结 问3析3答案 问4析4答案 问5析5答案 问6析6答案 3. webshell问1析1答案 问2析2答案 问3析3答案 1. 签到题 题目描述 此时正在进行的可能是_…

防止被恶意调用API接口

前言 在面试时&#xff0c;经常会被问一个问题&#xff1a;如何防止别人恶意刷接口&#xff1f; 这是一个非常有意思的问题&#xff0c;防范措施挺多的。今天这篇文章专门跟大家一起聊聊&#xff0c;希望对你会有所帮助。 1 防火墙 防火墙是网络安全中最基本的安全设备之一&…

Linux RabbitMQ 安装及卸载

一、安装 1、前景 RabbitMQ是用Erlang编写的&#xff0c;所以需要先安装Erlang的编译环境 注意 Erlang和RabbitMQ的版本是有一些版本匹配关系的&#xff0c;如果不匹配会导致RabbitMQ无法启动 2、安装Erlang # 下载 wget https://packages.erlang-solutions.com/erlang/r…

家中R4S软路由iStoreOS配置内网穿透服务实现远程访问公司电脑桌面

文章目录 简介一、配置远程桌面公网地址二、家中使用永久固定地址 访问公司电脑**具体操作方法是&#xff1a;** 简介 软路由是PC的硬件加上路由系统来实现路由器的功能&#xff0c;也可以说是使用软件达成路由功能的路由器。 使用软路由控制局域网内计算机的好处&#xff1a…

【日常聊聊】深度学习进度

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 方向一&#xff1a;深度学习的基本原理和算法 方向二&#xff1a;深度学习的应用实例 方向三&#xff1a;深度学习的挑战和未…

JVM-JVM调优基础(理论)

申明&#xff1a;文章内容是本人学习极客时间课程所写&#xff0c;作为笔记进行记录&#xff0c;文字和图片基本来源于课程资料&#xff0c;在某些地方会插入一点自己的理解&#xff0c;未用于商业用途&#xff0c;侵删。 原资料地址&#xff1a;课程资料 JVM参数 标准参数 …

【正点原子STM32连载】 第五十章 手写识别实验 摘自【正点原子】APM32E103最小系统板使用指南

1&#xff09;实验平台&#xff1a;正点原子APM32E103最小系统板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/docs/boards/xiaoxitongban 第五…

lazada、速卖通卖家如何掌握自养号测评技巧打造高评价产品?

做跨境电商卖家都知道&#xff0c;国外的买家购物比较理性&#xff0c;也喜欢货比三家&#xff0c;所以店铺想要留住客户&#xff0c;就需要一些优质的产品来吸引他们。产品评价是卖家获取买家信任的重要途径&#xff0c;评价越高的产品&#xff0c;销量也就越好。 尤其是 Shop…

机器人常用传感器分类及一般性要求

机器人传感器的分类 传感技术是先进机器人的三大要素&#xff08;感知、决策和动作&#xff09;之一。根据用途不同&#xff0c;机器人传感器可以分为两大类&#xff1a;用于检测机器人自身状态的内部传感器和用于检测机器人相关环境参数的外部传感器。 内部传感器 内部传感…

CrossOver 24.0 让Mac可以运行Windows程序的工具

CrossOver 24.0最新版重点添加了对 DirectX 12 支持&#xff0c;从而在 Mac 上更好地模拟运行 Windows 游戏&#xff0c;开发者在 CrossOver 23 中可以调用 DirectX 12&#xff0c;在模拟游戏的过程中同时调用所有 GPU 核心&#xff0c;从而实现更优秀的渲染效果。 目前CrossOv…

CORROSION: 1

本机 192.168.223.128目标机 192.168.223.148 主机发现 nmap -sP 192.168.223.0/24 端口扫描 ​nmap -sV -p- -A 192.168.223.148开启了22 80 端口 看web&#xff0c;是个apache默认界面 扫目录 gobuster dir -u http://192.168.223.148 -x html,txt,php,bak --wordlist…

推送开权引导的技术内幕

人人都讨厌代码腐化&#xff0c;人人都在腐化代码&#xff01;本文介绍app消息推送开权提醒能力的服务端实现&#xff0c;并说明如何通过手搓一个简易的流程引擎来实现横向的业务场景隔离&#xff0c;纵向的业务流程编排&#xff0c;从而灵活支持业务需求&#xff0c;抑制代码腐…

曲线生成 | 图解B样条曲线生成原理(基本概念与节点生成算法)

目录 0 专栏介绍1 什么是B样条曲线&#xff1f;2 基函数的de Boor递推式3 B样条曲线基本概念图解4 节点生成公式 0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详细介绍全局规划(图搜索、采样法、智能算法等)…

java以及android类加载机制

类加载机制 一、Java类加载机制 java中&#xff0c;每一个类或者接口&#xff0c;在编译后&#xff0c;都会生成一个.class文件。 类加载机制指的是将这些.class文件中的二进制数据读入到内存中并对数据进行校验&#xff0c;解析和初始化。最终&#xff0c;每一个类都会在方…

OpenAI:Sora视频生成模型技术报告(中文)

概述 视频生成模型作为世界模拟器 我们探索视频数据生成模型的大规模训练。具体来说&#xff0c;我们在可变持续时间、分辨率和宽高比的视频和图像上联合训练文本条件扩散模型。我们利用transformer架构&#xff0c;在视频和图像潜在代码的时空补丁上运行。我们最大的模型Sor…

Springboot+vue的物流管理系统(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的物流管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的物流管理系统&#xff0c;采用M&#xff08;model&#xff09;…

用163邮箱或者outlook接收国科大邮箱的邮件

使用如图下路径&#xff0c;创建一个新的密码&#xff0c;用于在163大师邮箱或者outlook登录即可 如果不行&#xff0c;则需要手动配置邮箱服务器 参考网址&#xff1a;中国科学院邮件系统帮助中心