Linux驱动开发1 - Platform设备
背景
所有驱动开发都是基于全志T507(Android 10)进行开发,用于记录驱动开发过程。
简介
什么是platform驱动自己上网搜索了解。
在driver/linux/platform_device.h中定义了platform_driver结构体。
struct platform_driver {int (*probe)(struct platform_device *);int (*remove)(struct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table;bool prevent_deferred_probe;
};
驱动实现
步骤一、实现platform_driver 结构体。
在longan/kernel/linux-4.9/drivers目录下创建自己的文件夹,定义一个led_drv.c文件。
定义platform结构体:
/* platform驱动结构体 */
static struct platform_driver gpio_led_driver = {.driver = {.name = "devled", // 无设备树时,用于设备和驱动间的匹配.of_match_table = gpio_led_of_match, // 有设备树后,利用设备树匹配表},.probe = gpio_led_probe,.remove = gpio_led_remove,
};
1、实现的是以下两个方法
//驱动匹配成功后会回调这个函数,用来给驱动进行初始化操作
.probe = xxx,
//驱动被移除或被卸载后会回调这个函数,用来释放资源
.remove = xxx,
2、用于和指定的设备树驱动进行匹配
.driver = {.name = "devled", // 无设备树时,用于设备和驱动间的匹配.of_match_table = gpio_led_of_match, // 有设备树后,利用设备树匹配表},
因此需要定义匹配列表,这里compatible就是设备树里面要定义的名称,这样才能正确识别到设备树配置的驱动。
/* 匹配列表 */
static const struct of_device_id gpio_led_of_match[] = {{ .compatible = "devled" },{}
};
在设备树中定义一个设备节点,注意这里led子节点根据实际情况进行配置。这里以PI1为例
led_test {compatible = "devled";pinctrl-names = "default";status = "okay";pinctrl-0 = <&pinctrl_led_test>;led {gpios = <&pio PI 1 1 2 0 1>;state = "on";};};
在PIO节点下定义pinctrl_led_test节点,主要用于配置IO口。
soc@03000000 {pio: pinctrl@0300b000 {...pinctrl_led_test: led_test_grp@0 {allwinner,pins = "PI1";allwinner,function = "led_test_grp";allwinner,muxsel = <0x01>;allwinner,drive = <0x00>;allwinner,pull = <0x01>;allwinner,data = <0x01>;};...}}
步骤2、定义设备节点
主要定义一下gpio_leds_priv,用来存放节点信息,用于生成/dev/xxx节点。
/* 存放led信息的结构体 */
struct gpio_led_data
{char name[16]; // 设备名字int pin; // gpio编号int active; // 控制亮灭的标志
};/* 存放led的私有属性 */
struct gpio_leds_priv
{struct cdev cdev; // cdev结构体struct class *dev_class; // 自动创建设备节点的类int num_leds; // led的数量struct gpio_led_data led; // 存放led信息的结构体数组
};
步骤3、初始化设备
定义一个初始化方法gpio_led_probe,并绑定到步骤1中的.probe
static int gpio_led_probe(struct platform_device *pdev)
{struct gpio_leds_priv *priv; // 临时存放私有属性的结构体struct device *dev; // 设备结构体dev_t devno; // 设备的主次设备号int i, rv = 0; /* 1)解析设备树并初始化led状态 */rv = parser_dt_init_led(pdev);if( rv < 0 )return rv;/* 将之前存入的私有属性,放入临时的结构体中 */priv = platform_get_drvdata(pdev);/* 2)分配主次设备号 */if (0 != dev_major) { /* 静态分配主次设备号 */devno = MKDEV(dev_major, 0); rv = register_chrdev_region(devno, priv->num_leds, "devled"); } else { /* 动态分配主次设备号 */rv = alloc_chrdev_region(&devno, 0, priv->num_leds, "devled"); dev_major = MAJOR(devno); } if (rv < 0) { dev_err(&pdev->dev, "major can't be allocated\n"); return rv; } /* 3)分配cdev结构体 */cdev_init(&priv->cdev, &led_fops);priv->cdev.owner = THIS_MODULE;rv = cdev_add (&priv->cdev, devno , priv->num_leds); if( rv < 0) {dev_err(&pdev->dev, "struture cdev can't be allocated\n");goto undo_major;}/* 4)创建类,实现自动创建设备节点 */priv->dev_class = class_create(THIS_MODULE, "led");if( IS_ERR(priv->dev_class) ) {dev_err(&pdev->dev, "fail to create class\n");rv = -ENOMEM;goto undo_cdev;}/* 5)创建设备 */for(i=0; i<priv->num_leds; i++){devno = MKDEV(dev_major, i);dev = device_create(priv->dev_class, NULL, devno, NULL, "led");if( IS_ERR(dev) ) {dev_err(&pdev->dev, "fail to create device\n");rv = -ENOMEM;goto undo_class;}}printk("success to install driver[major=%d]!\n", dev_major);return 0;undo_class:class_destroy(priv->dev_class);undo_cdev:cdev_del(&priv->cdev);undo_major:unregister_chrdev_region(devno, priv->num_leds);return rv;}
parser_dt_init_led用于获取设备树中的节点信息,并进行初始化。
/* 解析设备树并初始化led属性 */
static int parser_dt_init_led(struct platform_device *pdev)
{struct device_node *np = pdev->dev.of_node; // 当前设备节点struct device_node *child; // 当前设备节点的子节点struct gpio_leds_priv *priv; // 存放私有属性int num_leds, gpio; // led数量和gpio编号 /* 获取该节点下子节点的数量 */num_leds = 1;if(num_leds <= 0) {dev_err(&pdev->dev, "fail to find child node\n");return -EINVAL;}/* devm_kzalloc是内核内存分配函数,跟设备有关的,驱动卸载时,内存会被自动释放* void * devm_kzalloc (struct device * dev, size_t size, gfp_t gfp)* dev:申请内存的目标设备 size:申请的内存大小 gfp:申请内存的类型标志* GFP_KERNEL是分配内核空间的内存时的一个标志位,无内存可用时可引起休眠*/priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(num_leds), GFP_KERNEL);if (!priv){return -ENOMEM;}priv->num_leds = 1;/* 找到子节点并传给child */child = of_get_child_by_name(np, "led");/* 解析dts并且获取gpio口,函数返回值就得到gpio号,并且读取gpio现在的标志 */gpio = of_get_named_gpio(child, "gpios", 0);/* 将子节点的名字,传给私有属性结构体中的led信息结构体中的name属性 */strncpy(priv->led.name, child->name, sizeof(priv->led.name)); printk(">>>>> init_led gpio=%d name=%s\n", gpio, priv->led.name);/* 将gpio编号和控制亮灭的标志传给结构体* active属性,1代表亮,0代表灭,初始属性为亮*/priv->led.active = 1; priv->led.pin = gpio; /* 申请gpio口,相较于gpio_request增加了gpio资源获取与释放功能 */gpio_request(priv->led.pin, "led");/* 设置gpio为输出模式,并设置初始状态 */gpio_direction_output(priv->led.pin, 1);/* 将led的私有属性放入platform_device结构体的device结构体中的私有数据中 */platform_set_drvdata(pdev, priv);return 0;}
步骤4、移除设备
常规操作,将所有设备依次注销回收。
static int gpio_led_remove(struct platform_device *pdev)
{struct gpio_leds_priv *priv = platform_get_drvdata(pdev);int i;dev_t devno = MKDEV(dev_major, 0);/* 注销设备结构体,class结构体和cdev结构体 */for(i=0; i<priv->num_leds; i++){devno = MKDEV(dev_major, i);device_destroy(priv->dev_class, devno);}class_destroy(priv->dev_class);cdev_del(&priv->cdev); unregister_chrdev_region(MKDEV(dev_major, 0), priv->num_leds);/* 将led的状态设置为灭 */for (i = 0; i < priv->num_leds; i++) {gpio_set_value(priv->led.pin, ~priv->led.active);} printk("success to remove driver[major=%d]!\n", dev_major);return 0;}
步骤5、字符设备描述file_operations
static struct file_operations led_fops =
{.owner = THIS_MODULE,.open = led_open,.release = led_release,.unlocked_ioctl = led_ioctl,.compat_ioctl = led_ioctl,
};
实现led_open、led_release、led_ioctl。
static int led_open(struct inode *inode, struct file *file)
{struct gpio_leds_priv *priv;priv = container_of(inode->i_cdev, struct gpio_leds_priv, cdev);file->private_data = priv;return 0;}static int led_release(struct inode *inode, struct file *file)
{return 0;
}static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{struct gpio_leds_priv *priv;priv = file->private_data;printk(">>>>> led_ioctl command=%d arg=%d\n", cmd, arg);switch (cmd){case LED_ON:printk("LED_ON:%d state: %d\n", priv->led.pin, gpio_get_value(priv->led.pin));gpio_set_value(priv->led.pin, 1);priv->led.active = 1;printk("gpio_pin: %d\n", priv->led.pin);break;case LED_OFF:printk("LED_OFF:%d state: %d\n", priv->led.pin, gpio_get_value(priv->led.pin));gpio_set_value(priv->led.pin, 0);priv->led.active = 0;printk("gpio_pin: %d\n", priv->led.pin);break;default:printk("Ioctl command=%d can't be supported\n", cmd);break;}return 0;}
步骤6、编译环境MakeFile
在自定义目录下创建Makefile文件。这里默认加载设备。
obj-y += led_drv.o
也可以创建Kconfig文件,添加配置项后就可以在驱动中进行配置。
config CHR_DEV_BASEtristate "First chr device"default yhelpThis is first che device.
obj-${CONFIG_CHR_DEV_BASE} += led_drv.o
源码
附上全部驱动代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of_device.h>
#include <linux/slab.h>#define LED_OFF 0
#define LED_ON 1static int dev_major = 0;/* 存放led信息的结构体 */
struct gpio_led_data
{char name[16]; // 设备名字int pin; // gpio编号int active; // 控制亮灭的标志
};/* 存放led的私有属性 */
struct gpio_leds_priv
{struct cdev cdev; // cdev结构体struct class *dev_class; // 自动创建设备节点的类int num_leds; // led的数量struct gpio_led_data led; // 存放led信息的结构体数组
};/* 为led私有属性开辟存储空间的函数 */
static inline int sizeof_gpio_leds_priv(int num_leds)
{return sizeof(struct gpio_leds_priv) + (sizeof(struct gpio_led_data) * num_leds);
}/* 解析设备树并初始化led属性 */
static int parser_dt_init_led(struct platform_device *pdev)
{struct device_node *np = pdev->dev.of_node; // 当前设备节点struct device_node *child; // 当前设备节点的子节点struct gpio_leds_priv *priv; // 存放私有属性int num_leds, gpio; // led数量和gpio编号 /* 获取该节点下子节点的数量 */num_leds = 1;if(num_leds <= 0) {dev_err(&pdev->dev, "fail to find child node\n");return -EINVAL;}/* devm_kzalloc是内核内存分配函数,跟设备有关的,驱动卸载时,内存会被自动释放* void * devm_kzalloc (struct device * dev, size_t size, gfp_t gfp)* dev:申请内存的目标设备 size:申请的内存大小 gfp:申请内存的类型标志* GFP_KERNEL是分配内核空间的内存时的一个标志位,无内存可用时可引起休眠*/priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(num_leds), GFP_KERNEL);if (!priv){return -ENOMEM;}priv->num_leds = 1;/* 找到子节点并传给child */child = of_get_child_by_name(np, "led");/* 解析dts并且获取gpio口,函数返回值就得到gpio号,并且读取gpio现在的标志 */gpio = of_get_named_gpio(child, "gpios", 0);/* 将子节点的名字,传给私有属性结构体中的led信息结构体中的name属性 */strncpy(priv->led.name, child->name, sizeof(priv->led.name)); printk(">>>>> init_led gpio=%d name=%s\n", gpio, priv->led.name);/* 将gpio编号和控制亮灭的标志传给结构体* active属性,1代表亮,0代表灭,初始属性为亮*/priv->led.active = 1; priv->led.pin = gpio; /* 申请gpio口,相较于gpio_request增加了gpio资源获取与释放功能 */gpio_request(priv->led.pin, "led");/* 设置gpio为输出模式,并设置初始状态 */gpio_direction_output(priv->led.pin, 1);/* 将led的私有属性放入platform_device结构体的device结构体中的私有数据中 */platform_set_drvdata(pdev, priv);return 0;}static int led_open(struct inode *inode, struct file *file)
{struct gpio_leds_priv *priv;priv = container_of(inode->i_cdev, struct gpio_leds_priv, cdev);file->private_data = priv;return 0;}static int led_release(struct inode *inode, struct file *file)
{return 0;
}static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{struct gpio_leds_priv *priv;priv = file->private_data;printk(">>>>> led_ioctl command=%d arg=%d\n", cmd, arg);switch (cmd){case LED_ON:printk("LED_ON:%d state: %d\n", priv->led.pin, gpio_get_value(priv->led.pin));gpio_set_value(priv->led.pin, 1);priv->led.active = 1;printk("gpio_pin: %d\n", priv->led.pin);break;case LED_OFF:printk("LED_OFF:%d state: %d\n", priv->led.pin, gpio_get_value(priv->led.pin));gpio_set_value(priv->led.pin, 0);priv->led.active = 0;printk("gpio_pin: %d\n", priv->led.pin);break;default:printk("Ioctl command=%d can't be supported\n", cmd);break;}return 0;}static struct file_operations led_fops =
{.owner = THIS_MODULE,.open = led_open,.release = led_release,/*** 注: 20250403 yozad.von* 如果是32位内核+32位用户空间或者64位内核+64位用户空间只配置unlocked_ioctl就行*/.unlocked_ioctl = led_ioctl,/*** 注: 20250403 yozad.von* adb shell getprop ro.product.cpu.abi查安卓版本是armeabi-v7a,即32位系统。* compat_ioctl,是为兼容32位的用户空间程序在64位内核上执行ioctl操作* 所以测试发现只有写1是正常的,写其他值都返回-1*/.compat_ioctl = led_ioctl,
};static int gpio_led_probe(struct platform_device *pdev)
{struct gpio_leds_priv *priv; // 临时存放私有属性的结构体struct device *dev; // 设备结构体dev_t devno; // 设备的主次设备号int i, rv = 0; /* 1)解析设备树并初始化led状态 */rv = parser_dt_init_led(pdev);if( rv < 0 )return rv;/* 将之前存入的私有属性,放入临时的结构体中 */priv = platform_get_drvdata(pdev);/* 2)分配主次设备号 */if (0 != dev_major) { /* 静态分配主次设备号 */devno = MKDEV(dev_major, 0); rv = register_chrdev_region(devno, priv->num_leds, "devled"); } else { /* 动态分配主次设备号 */rv = alloc_chrdev_region(&devno, 0, priv->num_leds, "devled"); dev_major = MAJOR(devno); } if (rv < 0) { dev_err(&pdev->dev, "major can't be allocated\n"); return rv; } /* 3)分配cdev结构体 */cdev_init(&priv->cdev, &led_fops);priv->cdev.owner = THIS_MODULE;rv = cdev_add (&priv->cdev, devno , priv->num_leds); if( rv < 0) {dev_err(&pdev->dev, "struture cdev can't be allocated\n");goto undo_major;}/* 4)创建类,实现自动创建设备节点 */priv->dev_class = class_create(THIS_MODULE, "led");if( IS_ERR(priv->dev_class) ) {dev_err(&pdev->dev, "fail to create class\n");rv = -ENOMEM;goto undo_cdev;}/* 5)创建设备 */for(i=0; i<priv->num_leds; i++){devno = MKDEV(dev_major, i);dev = device_create(priv->dev_class, NULL, devno, NULL, "led");if( IS_ERR(dev) ) {dev_err(&pdev->dev, "fail to create device\n");rv = -ENOMEM;goto undo_class;}}printk("success to install driver[major=%d]!\n", dev_major);return 0;undo_class:class_destroy(priv->dev_class);undo_cdev:cdev_del(&priv->cdev);undo_major:unregister_chrdev_region(devno, priv->num_leds);return rv;}static int gpio_led_remove(struct platform_device *pdev)
{struct gpio_leds_priv *priv = platform_get_drvdata(pdev);int i;dev_t devno = MKDEV(dev_major, 0);/* 注销设备结构体,class结构体和cdev结构体 */for(i=0; i<priv->num_leds; i++){devno = MKDEV(dev_major, i);device_destroy(priv->dev_class, devno);}class_destroy(priv->dev_class);cdev_del(&priv->cdev); unregister_chrdev_region(MKDEV(dev_major, 0), priv->num_leds);/* 将led的状态设置为灭 */for (i = 0; i < priv->num_leds; i++) {gpio_set_value(priv->led.pin, ~priv->led.active);} printk("success to remove driver[major=%d]!\n", dev_major);return 0;} /* 匹配列表 */
static const struct of_device_id gpio_led_of_match[] = {{ .compatible = "devled" },{}
};MODULE_DEVICE_TABLE(of, gpio_led_of_match);/* platform驱动结构体 */
static struct platform_driver gpio_led_driver = {.driver = {.name = "devled", // 无设备树时,用于设备和驱动间的匹配.of_match_table = gpio_led_of_match, // 有设备树后,利用设备树匹配表},.probe = gpio_led_probe,.remove = gpio_led_remove,
};module_platform_driver(gpio_led_driver);MODULE_LICENSE("GPL");
相关文章:
Linux驱动开发1 - Platform设备
背景 所有驱动开发都是基于全志T507(Android 10)进行开发,用于记录驱动开发过程。 简介 什么是platform驱动自己上网搜索了解。 在driver/linux/platform_device.h中定义了platform_driver结构体。 struct platform_driver {int (*probe…...
力扣-hot100(盛最多水的容器)
11. 盛最多水的容器 中等 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明…...
使用 PyTorch 构建 UNet 图像去噪模型:从数据加载到模型训练的完整流程
图像去噪是计算机视觉中的一个基础问题,在医学图像、遥感、夜间视觉等领域有广泛应用。本文将手把手带你用 PyTorch 构建一个 UNet 架构的图像去噪模型,包括数据预处理、网络搭建、PSNR 评估与模型保存的完整流程。 本项目已支持将数据增强版本保存为独立…...
从信号处理角度理解图像处理的滤波函数
目录 1、预备知识 1.1 什么是LTI系统? 1.1.1 首先来看什么是线性系统,前提我们要了解什么是齐次性和叠加性。...
集合框架--List集合详解
List集合 List 接口直接继承 Collection 接口,它定义为可以存储重复元素的集合,并且元素按照插入顺序有序排列,且可以通过索引访问指定位置的元素。常见的实现有:ArrayList、LinkedList。 Arraylist:有序、可重复、有索引 Linke…...
需求分析---软件架构师武器库中的天眼系统
在软件架构中,需求分析决定了系统的核心设计方向。 然而,现实中的需求往往存在以下问题: 需求被二次加工:产品经理或业务方可能直接提供“解决方案”(如“我们需要一个聊天功能”),而非原始需…...
Spring Cloud Gateway 的执行链路详解
Spring Cloud Gateway 的执行链路详解 🎯 核心目标 明确 Spring Cloud Gateway 的请求处理全过程(从接收到请求 → 到转发 → 到返回响应),方便你在合适的生命周期节点插入你的逻辑。 🧱 核心执行链路图(执…...
Python----机器学习(基于PyTorch框架的逻辑回归)
逻辑回归是一种广泛使用的统计学习方法,主要用于处理二分类问题。它基于线性回归模型,通过Sigmoid函数将输出映射到[0, 1]范围内,表示实例属于正类别的概率。尽管逻辑回归适用于二分类任务,但在多分类问题中常使用Softmax函数&…...
工业数据治理范式革新:时序数据库 TDengine虚拟表技术解析
小T导读:在工业数字化过程中,数据如何从设备采集顺利“爬坡”到上层应用,一直是个难题。传统“单列模型”虽贴合设备协议,却让上层分析举步维艰。TDengine 用一种更聪明的方法打通了这条数据通路:不强求建模、不手动转…...
Linux的应用领域,Linux的介绍,VirtualBox和Ubuntu的安装,VMware的安装和打开虚拟机CentOS
目录 Linux的应用领域 Linux的介绍 Linux的介绍 Linux发行版 Unix和Linux的渊源 虚拟机和Linux的安装 VirtualBox和Ubuntu的安装 安装VirtualBox 安装Ubuntu 下载Ubuntu操作系统的镜像文件 创建虚拟机 虚拟机设置 启动虚拟机,安装Ubuntu系统 Ubuntu基…...
使用 Java 8 Stream实现List重复数据判断
import java.util.*; import java.util.stream.Collectors;public class DeduplicateStreamExample {static class ArchiveItem {// 字段定义与Getter/Setter省略(需根据实际补充)private String mATNR;private String lIFNR;private String suppSpecMod…...
GDAL:地理数据的万能瑞士军刀
目录 1. 什么是GDAL?2. 为什么需要GDAL?3. GDAL的主要功能3.1. 数据转换3.2. 数据裁剪和处理3.3. 读取和写入多种格式 4. 实际应用场景4.1 环境监测4.2 城市规划4.3 导航系统 5. 技术原理简单解释6. 如何使用GDAL?6.1 简单命令示例 7. 学习建…...
每日文献(十三)——Part two
今天从第三章节:“实现细节”开始介绍。 目录 三、实现细节 四、实验 五、总结贡献 六、致谢 三、实现细节 我们在多尺度图像上训练和测试区域建议和目标检测网络。这是在KITTI目标检测基准[13]上基于CNN的目标检测的趋势。例如,在[16]中ÿ…...
ArrayList 和 LinkedList 区别
ArrayList 和 LinkedList 是 Java 集合框架中两种常用的列表实现,它们在底层数据结构、性能特点和适用场景上有显著的区别。以下是它们的详细对比以及 ArrayList 的扩容机制。 1. ArrayList 和 LinkedList 的底层区别 (1) 底层数据结构 ArrayList: 基于…...
【iOS】UITableView性能优化
UITableView性能优化 前言优化从何入手优化的本质 CPU层级优化1. Cell的复用2. 尽量少定义Cell,善于使用hidden控制显示视图3. 提前计算并缓存高度UITableView的代理方法执行顺序Cell高度缓存高度数组 4. 异步绘制5. 滑动时按需加载6. 使用异步加载图片,…...
通过检索增强生成(RAG)和重排序提升大语言模型(LLM)的准确性
探索大语言模型(LLM)结合有效信息检索机制的优势。实现重排序方法,并将其整合到您自己的LLM流程中。 想象一下,一个大语言模型(LLM)不仅能提供相关答案,还能根据您的具体需求进行精细筛选、优先…...
IDEA202403常用快捷键【持续更新】
文章目录 一、全局搜索二、美化格式三、替换四、Git提交五、代码移动六、调试运行 在使用IDEA进行程序开发,快捷键会让这个过程更加酸爽,下面记录各种快捷键的功能。 一、全局搜索 快捷键功能说明Shift Shift全局搜索Ctrl N搜索Java类 二、美化格式 …...
硬件元件三极管:从基础到进阶的电子探秘
一、基础理论 1. PN结(二极管) PN 结是采用不同的掺杂工艺,将 P 型半导体与 N 型半导体紧密接触而形成的一个界面区域。也就是我们常说的二极管。(P型带正电、N型带负电,电流由P流向N) 形成过程࿱…...
4. k8s核心概念 pod deployment service
以下是 Kubernetes 的核心概念详解,涵盖 Pod、Service、Deployment 和 Node,以及它们之间的关系和实际应用场景: 1. Pod 定义与作用 • 最小部署单元:Pod 是 Kubernetes 中可创建和管理的最小计算单元,包含一个或多个…...
12.第二阶段x64游戏实战-远程调试
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:11.第二阶段x64游戏实战-框架代码细节优化 本次写的内容是关于调试、排错相关的…...
自然语言处理的进化:BERT模型深度剖析
自然语言处理(NLP)领域近年来取得了跨越式的发展,尤其是随着深度学习技术的应用,不少新兴模型应运而生。其中,BERT(Bidirectional Encoder Representations from Transformers)作为一种革命性的…...
鸿蒙学习笔记(5)-HTTP请求数据
一、Http请求数据 http模块是鸿蒙内置的一个模块,提供了网络请求的能力。不需要再写比较原始的AJAS代码。 ps:在项目中如果要访问网络资源,不管是图片文件还是网络请求,必须给项目开放权限。 (1)网络连接方式 HTTP数…...
Golang 的 GMP 协程模型详解
Golang 的 GMP 协程模型详解 Golang 的并发模型基于 GMP(Goroutine-M-Processor) 机制,是其高并发能力的核心支撑。以下从原理、机制、优势、缺点和设计理念展开分析: 一、GMP 的组成与运作原理 Goroutine(Gÿ…...
ReportLab 导出 PDF(页面布局)
ReportLab 导出 PDF(文档创建) ReportLab 导出 PDF(页面布局) ReportLab 导出 PDF(图文表格) PLATYPUS - 页面布局和排版 1. 设计目标2. 开始3. Flowables3.1. Flowable.draw()3.2. Flowable.drawOn(canvas,x,y)3.3. F…...
Ubuntu 安装与配置 Docker
Ubuntu 安装与配置 Docker Docker 是一个开源的容器化平台,允许开发者将应用程序及其依赖项打包在一个轻量级、可移植的容器中。它可以帮助开发者和运维人员快速构建、部署和管理应用程序,提升开发和运维效率。本文将介绍如何在 Ubuntu 系统上安装和配置…...
【数据结构与算法】LeetCode每日一题
此题跟27.移除数组中的指定值 类似,都是移除且双指针玩法,只不过判断条件发生了变化...
【HDFS入门】数据存储原理全解,从分块到复制的完整流程剖析
目录 1 HDFS架构概览 2 文件分块机制 2.1 为什么需要分块? 2.2 块大小配置 3 数据写入流程 4 数据复制机制 4.1 副本放置策略 4.2 复制流程 5 数据读取流程 6 一致性模型 7 容错机制 7.1 数据节点故障处理 7.2 校验和验证 8 总结 在大数据时代&#x…...
力扣热题100——普通数组(不普通)
普通数组但一点不普通! 最大子数组和合并区间轮转数组除自身以外数组的乘积缺失的第一个正数 最大子数组和 这道题是非常经典的适用动态规划解决题目,但同时这里给出两种解法 动态规划、分治法 那么动态规划方法大家可以在我的另外一篇博客总结中看到&am…...
Ubuntu中snap
通过Snap可以安装众多的软件包。需要注意的是,snap是一种全新的软件包管理方式,它类似一个容器拥有一个应用程序所有的文件和库,各个应用程序之间完全独立。所以使用snap包的好处就是它解决了应用程序之间的依赖问题,使应用程序之…...
uniapp(Vue)开发微信小程序 之 保存图片到本地
一、保存图片到本地(要拿到图片的 src): 查看隐私条约是否加上相册(仅写入)权限: 微信公众平台 -》 左下角头像 -》账号设置 -》 用户隐私保护指引 -》去完善 -》 相册(仅写入)权限 …...
TailwindCss快速上手
什么是Tailwind Css? 一个实用优先的 CSS 框架,可以直接在标记中组合以构建任何设计。 开始使用Tailwind Css 如何安装 下面是使用vite构建工具的方法 ①安装 Tailwind CSS: tailwindcss通过tailwindcss/vitenpm安装。 npm install tailwindcss tailwindcss…...
Gladinet CentreStack Triofox 远程RCE漏洞(CVE-2025-30406)
免责声明 本文档所述漏洞详情及复现方法仅限用于合法授权的安全研究和学术教育用途。任何个人或组织不得利用本文内容从事未经许可的渗透测试、网络攻击或其他违法行为。使用者应确保其行为符合相关法律法规,并取得目标系统的明确授权。 对于因不当使用本文信息而造成的任何直…...
ASP.NET WEB 手动推送 URL 到百度站长工具实例
下面是一个完整的 ASP.NET Web 应用程序示例,演示如何手动推送 URL 到百度站长工具。 1. 创建推送页面 (PushToBaidu.aspx) <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="PushToBaidu.aspx.cs" Inherits="BaiduPushEx…...
【Ragflow】18.更好的推理框架:vLLM的docker部署方式
概述 看到不少人说“Ollama就图一乐,生产环境还得用vLLM”。 本文决定使用docker对vLLM进行部署,并解决模型配置中,IP地址的硬编码问题。 Ollama与vLLM风评比较 查询相关资料,Ollama与vLLM主要特点及对比情况如下[1]: Ollama:轻量级本地大模型部署工具,面向个人用户…...
智能 GitHub Copilot 副驾驶® 更新升级!
智能 GitHub Copilot 副驾驶 迎来重大升级!现在,所有 VS Code 用户都能体验支持 Multi-Context Protocol(MCP)的全新 Agent Mode。此外,微软还推出了智能 GitHub Copilot 副驾驶 Pro 订阅计划,提供更强大的…...
什么是高防服务器
高防服务器是具备高强度防御能力、专门应对网络攻击(如DDoS、 CC攻击)的服务器类 型,通过流量清洗、多层防护等技术保障业务稳定运行。具备高强度防御能力和智能攻击识别技术,可保障业务在极端网络环境下稳定运行。其核心特点及技术原理如下:…...
纷析云开源财务软件:企业财务数字化转型的灵活解决方案
纷析云是一家专注于开源财务软件研发的公司,自2018年成立以来,始终以“开源开放”为核心理念,致力于通过技术创新助力企业实现财务管理的数字化与智能化转型。其开源财务软件凭借高扩展性、灵活部署和全面的功能模块,成为众多企业…...
open webui 介绍 是一个可扩展、功能丰富且用户友好的本地部署 AI 平台,支持完全离线运行。
AI MCP 系列 AgentGPT-01-入门介绍 Browser-use 是连接你的AI代理与浏览器的最简单方式 AI MCP(大模型上下文)-01-入门介绍 AI MCP(大模型上下文)-02-awesome-mcp-servers 精选的 MCP 服务器 AI MCP(大模型上下文)-03-open webui 介绍 是一个可扩展、功能丰富且用户友好的…...
Spring缓存抽象机制
一、核心架构图解 #mermaid-svg-pUShmqsPanYTNVBI {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-pUShmqsPanYTNVBI .error-icon{fill:#552222;}#mermaid-svg-pUShmqsPanYTNVBI .error-text{fill:#552222;stroke:#5…...
[Jenkins]pnpm install ‘pnpm‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。
这个错误提示再次说明:你的系统(CMD 或 Jenkins 环境)找不到 pnpm 命令的位置。虽然你可能已经用 npm install -g pnpm 安装过,但系统不知道它装在哪里,也就无法执行 pnpm 命令。 ✅ 快速解决方法:直接用完…...
如何用AI辅助数据分析及工具推荐
以下是针对数据分析的 AI辅助工具推荐,结合国内外主流工具的功能特点、优劣势及适用场景分析,并标注是否为国内软件及付费情况: 一、国内工具推荐 1. WPS AI 特点:集成于WPS Office套件,支持智能数据分析、自动生成可…...
使用KeilAssistant代替keil的UI界面
目录 一、keil Assistant的优势和缺点 二、使用方法 (1)配置keil的路径 (2)导入并使用工程 (3)默认使用keil自带的ARM编译器而非GUN工具链 一、keil Assistant的优势和缺点 在日常学…...
spark-SQL数据加载和保存
数据加载与保存 通用方式: 通过 spark.read.load 和 df.write.save 实现数据加载与保存。可利用 format 指定数据格式,如 csv 、 jdbc 等; option 用于设置特定参数,像 jdbc 格式下的数据库连接信息; load 和 save 则…...
strings.Replace 使用详解
目录 1. 官方包 2. 支持版本 3. 官方说明 4. 作用 5. 实现原理 6. 推荐使用场景和不推荐使用场景 推荐场景 不推荐场景 7. 使用场景示例 示例1:官方示例 示例2:模板变量替换 示例3:敏感信息脱敏(隐藏手机号中间四位&a…...
K8S微服务部署及模拟故障观测
概述 本文介绍了如何在 Kubernetes (K8S) 集群中部署微服务,并模拟常见的故障场景(如 Pod 故障、节点故障、网络故障)以测试系统的容错能力。通过本实验,了解 Kubernetes 的自动恢复机制以及如何通过监控和日志分析快速定位和解决…...
3.k8s是如何工作的
Kubernetes 是一个复杂的分布式系统,其核心设计理念是 声明式管理 和 自动化控制。以下是 Kubernetes 的工作机制详解,从用户提交应用到容器运行的全流程: 1. 核心架构:控制平面(Control Plane)与工作节点&…...
打通任督二脉 - Device Plugin 让 k8s “看见” GPU
打通任督二脉 - Device Plugin 让 k8s “看见” GPU 上一篇咱们聊了为啥要把 GPU 这个“计算猛兽”拉进 Kubernetes (k8s) 这个“智能调度中心”。目标很美好:提高效率、简化管理、弹性伸缩。但现实是,k8s 天生并不认识 GPU 这位“新朋友”。就像你的电脑操作系统,默认只认…...
锚定“体验驱动”,锐捷EDN让园区网络“以人为本”
作者 | 曾响铃 文 | 响铃说 传统的网络升级路径,一如巴别塔的建造思路一般——工程师们按技术蓝图逐层堆砌,却常与地面用户的实际需求渐行渐远,从而带来了诸多体验痛点,如手工配置效率低下、关键业务用网无法保障、网络架构趋于…...
Flutter的自动化测试 python flutter编程
Flutter应用开发入门指南 第一步:创建Flutter应用 创建一个默认的Flutter应用后,将以下代码复制到 lib/main.dart 中: import package:flutter/material.dart;//运行Flutter应用,创建了一个自己实现的Widget对象 void main() > runApp(…...
Day09【基于jieba分词和RNN实现的简单中文分词】
基于jieba分词和RNN实现的中文分词 目标数据准备主程序预测效果 目标 本文基于给定的中文词表,将输入的文本基于jieba分词分割为若干个词,词的末尾对应的标签为1,中间部分对应的标签为0,同时将分词后的单词基于中文词表做初步序列…...