linux驱动(二):led补
本文主要探讨s5pv210的led驱动相关知识,包括驱动主次设备注册和取消,udev(mdev)机制,静态和动态映射操作寄存器。
字符设备驱动注册
老接口(register_chrdev)
static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
{return __register_chrdev(major, 0, 256, name, fops);
}
新接口(register_chrdev_region/alloc_chrdev_region)
int register_chrdev_region(dev_t from, unsigned count, const char *name)
{struct char_device_struct *cd;dev_t to = from + count;dev_t n, next;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);if (next > to)next = to;cd = __register_chrdev_region(MAJOR(n), MINOR(n),next - n, name);if (IS_ERR(cd))goto fail;}return 0;
fail:to = n;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));}return PTR_ERR(cd);
}
指定主次设备号(/proc/devices查看未使用驱动号)
form:起始设备号(static dev_t dev;)
count:次设备号数量
name:驱动名字
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
{struct char_device_struct *cd;cd = __register_chrdev_region(0, baseminor, count, name);if (IS_ERR(cd))return PTR_ERR(cd);*dev = MKDEV(cd->major, cd->baseminor);return 0;
}
内核分配主次设备号(从254开始查找未使用驱动号)
dev:内核分配的主次设备号(static dev_t dev;)
baseminor:次设备号起始号
count:次设备号个数
name:驱动名字
static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor,int minorct, const char *name)
{struct char_device_struct *cd, **cp;int ret = 0;int i;cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);if (cd == NULL)return ERR_PTR(-ENOMEM);mutex_lock(&chrdevs_lock);/* temporary */if (major == 0) {for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {if (chrdevs[i] == NULL)break;}if (i == 0) {ret = -EBUSY;goto out;}major = i;ret = major;}cd->major = major;cd->baseminor = baseminor;cd->minorct = minorct;strlcpy(cd->name, name, sizeof(cd->name));i = major_to_index(major);for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)if ((*cp)->major > major ||((*cp)->major == major &&(((*cp)->baseminor >= baseminor) ||((*cp)->baseminor + (*cp)->minorct > baseminor))))break;/* Check for overlapping minor ranges. */if (*cp && (*cp)->major == major) {int old_min = (*cp)->baseminor;int old_max = (*cp)->baseminor + (*cp)->minorct - 1;int new_min = baseminor;int new_max = baseminor + minorct - 1;/* New driver overlaps from the left. */if (new_max >= old_min && new_max <= old_max) {ret = -EBUSY;goto out;}/* New driver overlaps from the right. */if (new_min <= old_max && new_min >= old_min) {ret = -EBUSY;goto out;}}cd->next = *cp;*cp = cd;mutex_unlock(&chrdevs_lock);return cd;
out:mutex_unlock(&chrdevs_lock);kfree(cd);return ERR_PTR(ret);
}
注册都是用该函数,判断major为0则自动分配设备号,且从254依次递减查找未使用的号码
void unregister_chrdev_region(dev_t from, unsigned count)
{dev_t to = from + count;dev_t n, next;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);if (next > to)next = to;kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));}
}
注销驱动
form:驱动号
count:驱动个数
cdev结构体(字符设备描述,cdev.h)
struct cdev {struct kobject kobj; /* 内嵌的 kobject 对象 */struct module *owner; /*所属模块*/ const struct file_operations *ops; /*文件操作结构体*/struct list_head list; /*内核链表*/dev_t dev;/*设备号*/unsigned int count;/*设备个数*/
};
主设备号MAJOR(dev_t dev)
次设备号MINOR(dev_t dev)
生成设备号MKDEV(int major, int minor)
cdev中dev_t dev定义设备号(高12位为主设备号,低20 位为次设备号)
MAJOR和MINOR根据已实例化的cdev中的dev_t dev获得主次设备号
MKDEV实例化cdev中的dev_t dev设备号
cdev结构体操作函数
struct cdev *cdev_alloc(void)
{struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);if (p) {INIT_LIST_HEAD(&p->list);kobject_init(&p->kobj, &ktype_cdev_dynamic);}return p;
}
动态申请cdev内存
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{memset(cdev, 0, sizeof *cdev);INIT_LIST_HEAD(&cdev->list);kobject_init(&cdev->kobj, &ktype_cdev_default);cdev->ops = fops;
}
初始化cdev中的file_operation
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
注册设备,通常发生在驱动模块的加载函数中
void cdev_put(struct cdev *p);
释放动态申请cdev内存
void cdev_del(struct cdev *p);
注销设备
驱动注册和取消流程:register_chrdev_region/alloc_chrdev_region + cdev_alloc + cdev_init + cdev_add + cdev_put + cdev_del + unregister_chrdev_region
udev(mdev)
udev是应用程序,驱动注册和注销信息传给udev,udev在应用层进行设备文件创建和删除
自动创建/sys/class/设备类/设备目录
/etc/init.d/rcS有关于udev的配置
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
mdev -s:系统启动时扫描/sys/class和/sys/block查找dev文件
ex:/sys/class/tty/tty0/dev内容为4:0,即主设备号是4,次设备号是0,dev上级目录为设备名(tty0),/sys/class/下每个文件夹代表一个子系统
echo /sbin/mdev > /proc/sys/kernel/hotplug:有热插拔时内核调用/proc/sys/kernel/hotplug文件里指定应用程序来处理
创建驱动类
#define class_create(owner, name) \
({ \static struct lock_class_key __key; \__class_create(owner, name, &__key); \
})struct class *__class_create(struct module *owner, const char *name,struct lock_class_key *key)
{struct class *cls;int retval;cls = kzalloc(sizeof(*cls), GFP_KERNEL);if (!cls) {retval = -ENOMEM;goto error;}cls->name = name;cls->owner = owner;cls->class_release = class_create_release;retval = __class_register(cls, key);if (retval)goto error;return cls;error:kfree(cls);return ERR_PTR(retval);
}
owner:THIS_MODULE(通常)
name:类名
返回值class类指针
驱动类注销
void class_destroy(struct class *cls)
{if ((cls == NULL) || (IS_ERR(cls)))return;class_unregister(cls);
}
cls:创建的驱动类
创建设备
struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
{va_list vargs;struct device *dev;va_start(vargs, fmt);dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);va_end(vargs);return dev;
}
class:类设备
parent:父设备,一般为NULL
devt:设备号
drvdata:设备数据
fmt:设备名字
注销设备
void device_destroy(struct class *class, dev_t devt)
{struct device *dev;dev = class_find_device(class, NULL, &devt, __match_devt);if (dev) {put_device(dev);device_unregister(dev);}
}
class:类设备
devt:设备号
udev机制流程:kernel(class_create,class_destroy,device_create,device_destroy)-->udev(mdev,应用层)-->/sys/class/设备类/设备
函数嵌套:class_create -->__class_create-->__class_register-->kset_register-->kobject_uevent
函数嵌套:device_create-->device_create_vargs-->kobject_set_name_vargs-->device_register-->device_add-->kobject_add-->kobject_uevent
静态映射表建立
/* minimal IO mapping */static struct map_desc s5p_iodesc[] __initdata = {{.virtual = (unsigned long)S5P_VA_CHIPID,.pfn = __phys_to_pfn(S5P_PA_CHIPID),.length = SZ_4K,.type = MT_DEVICE,}, {.virtual = (unsigned long)S3C_VA_SYS,.pfn = __phys_to_pfn(S5P_PA_SYSCON),.length = SZ_64K,.type = MT_DEVICE,}, {.virtual = (unsigned long)S3C_VA_UART,.pfn = __phys_to_pfn(S3C_PA_UART),.length = SZ_4K,.type = MT_DEVICE,}, {.virtual = (unsigned long)VA_VIC0,.pfn = __phys_to_pfn(S5P_PA_VIC0),.length = SZ_16K,.type = MT_DEVICE,}, {.virtual = (unsigned long)VA_VIC1,.pfn = __phys_to_pfn(S5P_PA_VIC1),.length = SZ_16K,.type = MT_DEVICE,}, {.virtual = (unsigned long)S3C_VA_TIMER,.pfn = __phys_to_pfn(S5P_PA_TIMER),.length = SZ_16K,.type = MT_DEVICE,}, {.virtual = (unsigned long)S5P_VA_GPIO,.pfn = __phys_to_pfn(S5P_PA_GPIO),.length = SZ_4K,.type = MT_DEVICE,},
};
建立映射表的三个关键:物理地址和虚拟地址相关宏定义,映射表建立函数
映射表建立函数:smdkc110_map_io(mach-smdkc110.c)-->s5p_init_io-->iotable_init
s5p_iodesc(cpu.c)是结构体数组数组中每个元素为一段段物理地址到虚拟地址映射,iotable_init函数将结构体数组格式表建立成MMU页表映射关系
开机-->start_kernel-->setup_arch-->paging_init-->devicemaps_init:mdesc->map_io();
内核寄存器读写接口
include/asm/io.h
#define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); })
#define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); })
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
#define writesb(p,d,l) __raw_writesb(__mem_pci(p),d,l)
#define writesw(p,d,l) __raw_writesw(__mem_pci(p),d,l)
#define writesl(p,d,l) __raw_writesl(__mem_pci(p),d,l)#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
#define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
#define readsb(p,d,l) __raw_readsb(__mem_pci(p),d,l)
#define readsw(p,d,l) __raw_readsw(__mem_pci(p),d,l)
#define readsl(p,d,l) __raw_readsl(__mem_pci(p),d,l)v为值,c为地址,b为位,w为字节,l为4字节操
demo:
动态(静态)注册驱动
mdev机制
动态映射结构体方式操作寄存器
内核寄存器读写接口
led.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>#define FILE "/dev/led"char buf[16];
char led_cmd[3][4];void div_cmd(char *str)
{unsigned int m = 0;unsigned int n = 0;memset(led_cmd,'\0',sizeof(led_cmd));while(*str != '\0'){if(*str != ' '){led_cmd[m][n] = *str;n++;}else{led_cmd[m][n] = '\0';n = 0;m++;}str++;}
}void write_buf()
{int i;memset(buf,'\0',sizeof(buf));if(!strcmp(led_cmd[1],"on"))buf[0] = '0';if(!strcmp(led_cmd[1],"off"))buf[0] = '1';buf[1] = *(led_cmd[2]);
} int main()
{int fd = -1;char cmd[16];fd = open(FILE, O_RDWR);if (fd < 0){printf("open %s error.\n", FILE);return -1;}printf("input led cmd :led on|off 1|2|3\n");while(1){memset(cmd,'\0',sizeof(cmd));printf(">>>>");fgets(cmd,16,stdin);if(cmd[0] == '.' && cmd[1] == 'q'){break;}div_cmd(cmd);write_buf();write(fd,buf,strlen(buf));}close(fd);return 0;
}
led_dynamic_module.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h>
#include <linux/string.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/cdev.h>
#include <linux/device.h>dev_t led_dev;
static struct cdev *led_cdev;
static struct class *led_class;
static struct device *led_device;//#define MAJOR 227 /*定义主设备号*/
#define BAEMINOR 0
#define DEV_COUNT 1
#define NAME "led"#define GPJ0_BASE_PA 0xe0200240/*
*动态映射结构体方式操作寄存器
typedef struct GPJ0REG
{volatile unsigned int gpj0con;volatile unsigned int gpj0dat;
} gpj0_reg_t;gpj0_reg_t *pGPJ0_BASE;
*///内核io接口读写寄存器
unsigned int led_tmp;
#define S5P_GPJ0REG(x) (x)
#define S5P_GPJ0CON S5P_GPJ0REG(0)
#define S5P_GPJ0DAT S5P_GPJ0REG(4)
static void __iomem *baseaddr;char kbuf[16];static ssize_t led_open(struct inode *inode, struct file *file)
{printk(KERN_INFO,"open led module\n");return 0;
}ssize_t led_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{int ret = -1;copy_to_user(buf,kbuf,size);if(ret){printk(KERN_ERR,"copy to user error\n");return ret;}printk(KERN_INFO,"copy to user success\n");return 0;
}static ssize_t led_write(struct file *file, const char __user *ubuf,size_t count, loff_t *ppos)
{int ret = -1;int led;memset(kbuf, 0, sizeof(kbuf));ret = copy_from_user(kbuf,ubuf,count);if(ret){printk(KERN_ERR,"copy from user fail\n");return ret;}led = kbuf[1] - '0' + 2;if (kbuf[0] == '0'){//pGPJ0_BASE->gpj0con = 0x1111111;//pGPJ0_BASE->gpj0dat &= ~(1<<led);led_tmp &= ~(1<<led);writel(led_tmp,baseaddr + S5P_GPJ0DAT);}else if (kbuf[0] == '1'){//pGPJ0_BASE->gpj0con = 0x1111111;//pGPJ0_BASE->gpj0dat |= (1<<led);led_tmp |= (1<<led);writel(led_tmp,baseaddr + S5P_GPJ0DAT);}printk(KERN_INFO,"copy from user success\n");return 0;
}static int led_close(struct inode *inode, struct file *file)
{//pGPJ0_BASE->gpj0dat = (1<<3)|(1<<4)|(1<<5);led_tmp = (1<<3)|(1<<4)|(1<<5);writel(led_tmp,baseaddr + S5P_GPJ0DAT);printk(KERN_INFO,"close led module\n");return 0;
}static const struct file_operations led_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_close
};static int __init led_char_dev_init()
{int ret = -1;//MKDEV(MAJOR, 0); /*定义主次设备号(dev_t led_dev)*///ret = register_chrdev_region(led_dev,DEV_COUNT,NAME); /*指定设备号注册方式*/ret = alloc_chrdev_region(&led_dev,BAEMINOR,DEV_COUNT,NAME);if(ret < 0){printk(KERN_ERR,"register led device fail\n");goto flag_1;}led_cdev = cdev_alloc();if(led_cdev == NULL){printk(KERN_ERR,"apply cdev memory fail\n");goto flag_2;}cdev_init(led_cdev,&led_fops);//类同cdev_init//led_cdev->owner = THIS_MODULE;//led_cdev->ops = &led_fops;ret = cdev_add(led_cdev,led_dev,DEV_COUNT);if(ret){printk(KERN_ERR,"device num bind fail\n");goto flag_3;}printk(KERN_INFO,"device num bind sucess\n");led_class = class_create(THIS_MODULE,"led_class");if(IS_ERR(led_class)){printk(KERN_ERR,"led class create fail\n");goto flag_4;}printk(KERN_INFO,"led class create success\n");led_device = device_create(led_class,NULL,led_dev,NULL,"led");if(led_device == NULL){printk(KERN_ERR,"device num bind fail\n");goto flag_5;}printk(KERN_INFO,"device num bind sucess\n");if(!request_mem_region(GPJ0_BASE_PA,8,"GPJ0_BASE"))goto flag_6;//pGPJ0_BASE = ioremap(GPJ0_BASE_PA,sizeof(gpj0_reg_t));//pGPJ0_BASE->gpj0con = 0x1111111;baseaddr = ioremap(GPJ0_BASE_PA, 8);writel(0x11111111,baseaddr + S5P_GPJ0CON);led_tmp = (1<<3)|(1<<4)|(1<<5);writel(led_tmp,baseaddr + S5P_GPJ0DAT);return 0;flag_6:device_destroy(led_class,led_dev);flag_5:class_destroy(led_class);flag_4://cdev_put(led_cdev);flag_3:cdev_del(led_cdev);flag_2:unregister_chrdev_region(led_dev,DEV_COUNT);flag_1:return -EINVAL;
}static void __exit led_char_dev_exit()
{//pGPJ0_BASE->gpj0dat = (1<<3)|(1<<4)|(1<<5);//iounmap(pGPJ0_BASE);//release_mem_region(GPJ0_BASE_PA,sizeof(gpj0_reg_t));led_tmp = (1<<3)|(1<<4)|(1<<5);writel(led_tmp,baseaddr + S5P_GPJ0DAT);iounmap(baseaddr);release_mem_region(GPJ0_BASE_PA,8);device_destroy(led_class,led_dev);class_destroy(led_class);//cdev_put(led_cdev);cdev_del(led_cdev);unregister_chrdev_region(led_dev,DEV_COUNT);
}module_init(led_char_dev_init);
module_exit(led_char_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cxb");
MODULE_DESCRIPTION("led dynamic moudle");
MODULE_ALIAS("led");
Makefile
KERN_DIR = /root/kernelobj-m += led_dynamic_module.oall:make -C $(KERN_DIR) M=`pwd` modules arm-linux-gcc led.c -o ledcp:cp *.ko /root/rootfs/drivercp led /root/rootfs/driver.PHONY: clean
clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf ./led
结果示例:

相关文章:
linux驱动(二):led补
本文主要探讨s5pv210的led驱动相关知识,包括驱动主次设备注册和取消,udev(mdev)机制,静态和动态映射操作寄存器。 字符设备驱动注册 老接口(register_chrdev) static inline int register_chrdev(unsigned int major, const char *n…...
性能测试-jmeter:安装 / 基础使用
一、理解jmeter 官网-Apache JMeter-Apache JMeter™ JMeter是一款开源的性能测试工具,主要用于模拟大量用户并发访问目标服务器,以评估服务器的性能和稳定性。 JMeter可以执行以下任务序号用途描述1性能测试通过模拟多个用户在同一时间对服务器进行请…...
数据仓库-数仓优化小厂实践
一、背景 由于公司规模较小,大数据相关没有实现平台化,相关的架构都是原生的Apache组件,所以集群的维护和优化都需要人工的参与。根据自己的实践整理一些数仓相关的优化。 二、优化 1、简易架构图 2、ODS层优化 2.1 分段式解析 随着业务增长…...
uniapp中uview组件丰富的Code 验证码输入框的使用方法
目录 基本使用 #自定义提示语 #保持倒计时 API #Props #Methods #Event 基本使用 通过ref获取组件对象,再执行后面的操作,见下方示例。 通过seconds设置需要倒计的秒数(默认60)通过ref调用组件内部的start方法,开始倒计时通过监听cha…...
md文件图片上传方案:Github+PicGo 搭建图床
文章目录 1. PicGo 下载2. 配置Github3. 配置PicGo4. PicGo集成Typora4.1 picGo监听端口设置 5. 测试 1. PicGo 下载 下载地址:https://molunerfinn.com/PicGo/ 尽量下载稳定版本 2. 配置Github 1. 创建一个新仓库,用于存放图片 2. 生成一个token&a…...
从零开始 - 在Python中构建和训练生成对抗网络(GAN)模型
生成对抗网络(GANs)是一种强大的生成模型,可以合成新的逼真图像。通过完整的实现过程,读者将对GANs在幕后的工作原理有深刻的理解。本教程首先导入必要的库并加载将用于训练GAN的Fashion-MNIST数据集。然后,提供了构建…...
OfficeWeb365 Indexs 任意文件读取漏洞复现
0x01 产品简介 OfficeWeb365 是专注于 Office 文档在线预览及PDF文档在线预览云服务,包括 Microsoft Word 文档在线预览、Excel 表格在线预览、Powerpoint 演示文档在线预览,WPS 文字处理、WPS 表格、WPS 演示及 Adobe PDF 文档在线预览。 0x02 漏洞概述 OfficeWeb365 /Pi…...
Crypto的简单应用-前后端加密传输
最近遇到一个数据脱敏处理的需求,想要用一种轻量级的技术实现,必须足够简单并且适用于所有场合如前后端加密传输、路由加密、数据脱敏等。抽时间研究了一下Crypto加密库的一些API,发现完全符合上述需求,扩展也比较容易。 1、前端加…...
Vue3-32-路由-重定向路由
什么是重定向 路由的重定向 :将匹配到的路由 【替换】 为另一个路由。 redirect : 重定向的关键字。 重定向的特点 1、重定向是路由的直接替换,路由的地址是直接改变的; 2、在没有子路由配置的情况下,重定向的路由可以省略 component 属性的配…...
如何用js动态修改字体大小
在项目中,我们常常会遇到使用v-html渲染文本的情况。 如果需要点击大中小三个字号按钮,需要修改字体的大小。那我们应该怎么做呢 function fontSize(element, type) {let size {big: 22,middle: 16,small: 12};var result element.innerHTML.replac…...
【BIG_FG_CSDN】C++ 数组与指针 (个人向——学习笔记)
一维数组 在内存占用连续存储单元的相同类型数据序列的存储。 数组是静态存储器的块;在编译时确定大小后才能使用; 其声明格式如下: 元素类型 数组名[常量];元素类型:数组中元素的数据类型; 常量&#…...
桌面天气预报软件 Weather Widget free mac特点介绍
Weather Widget free for Mac多种吸引人的小部件设计可供选择,可以随时了解天气!还可以在Dock和菜单栏中为您提供简短的天气预报或当前状况的概述。 Weather Widget free for Mac软件介绍 始终在桌面上使用时尚的天气小部件来随时了解天气!多…...
HarmonyOS应用开发-搭建开发环境
本文介绍如何搭建 HarmonyOS 应用的开发环境,介绍下载安装 DevEco Studio 开发工具和 SDK 的详细流程。华为鸿蒙 DevEco Studio 是面向全场景的一站式集成开发环境,面向全场景多设备,提供一站式的分布式应用开发平台,支持分布式多…...
<JavaEE> TCP 的通信机制(五) -- 延时应答、捎带应答、面向字节流
目录 TCP的通信机制的核心特性 七、延时应答 1)什么是延时应答? 2)延时应答的作用 八、捎带应答 1)什么是捎带应答? 2)捎带应答的作用 九、面向字节流 1)沾包问题 2)“沾包…...
电脑怎么设置代理IP上网?如何隐藏自己电脑的真实IP?
在现代互联网中,代理IP已成为许多用户保护隐私和上网安全的重要手段。通过设置代理IP,用户可以隐藏自己的真实IP地址,提高上网的安全性,同时保护个人信息不被泄露。本文将详细介绍如何设置代理IP上网以及如何隐藏电脑的真实IP地址…...
Django信号机制源码分析(观察者模式)
Django信号的实现原理本质是设计模式中的观察者模式,浅谈Python设计模式 -- 观察者模式,也可以叫做发布-订阅模式,信号对象维护一个订阅者列表,当信号被触发时,它会遍历订阅者,依次通知它们。 先来回顾一下…...
MyBatis-config.xml配置文件
1、基本介绍: mybatis的核心配置文件(mybatis-config.xml),比如配置jdbc连接信息,注册mapper等等,我们需要对这个配置文件有详细的了解。 官网地址有详细介绍 mybatis – MyBatis 3 | 配置 2、properties属性 在通常的情况下&am…...
【Spring实战】17 REST服务介绍
文章目录 1. 为什么出现2. 拥有哪些优势3. Spring中的应用4. spring-boot-starter-data-rest总结 REST(Representational State Transfer)是一种软件架构风格,通常用于设计网络应用程序的服务接口。RESTful 服务是基于 REST 原则构建的网络服…...
java struts2教务管理系统Myeclipse开发mysql数据库struts2结构java编程计算机网页项目
一、源码特点 java struts2 教务管理系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助 struts2 框架开发,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境 为TOMCAT7.0,Myeclipse8.5开发,数据库…...
跟着cherno手搓游戏引擎【3】事件系统和预编译头文件
不多说了直接上代码,课程中的架构讲的比较宽泛,而且有些方法写完之后并未测试。所以先把代码写完。理解其原理,未来使用时候会再此完善此博客。 文件架构: Event.h:核心基类 #pragma once #include"../Core.h" #inclu…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
