Regmap API 实验

news2024/11/25 4:41:58

目录

一、Regmap

regmap 结构体

regmap_config 结构体

regmap_config 掩码设置

二、Regmap 操作函数

1、Regmap 申请与初始化

 2、 regmap 设备访问 API 函数

 3、regmap_update_bits 函数

 4、regmap_bulk_read函数

5、regmap_bulk_write

三、修改SPI实验

1、添加regmap结构体

2、probe函数

3、remove函数 

4、读函数

5、写函数​编辑

6、读取ICM20608的数据

代码如下


一、Regmap

        Linux 下大部分设备的驱动开发都是操作其内部寄存器,比如 I2C/SPI 设备的本质都是一样
的,通过 I2C/SPI 接口读写芯片内部寄存器。芯片内部寄存器也是同样的道理,比如 I.MX6ULL
的 PWM、定时器等外设初始化,最终都是要落到寄存器的设置上
        Linux 下使用 i2c_transfer 来读写 I2C 设备中的寄存器, SPI 接口的话使用spi_write/spi_read等。 I2C/SPI 芯片又非常的多,因此 Linux 内核里面就会充斥了大量的 i2c_transfer 这类的冗余代码,再者,代码的复用性也会降低。

        比如 icm20608 这个芯片既支持 I2C 接口,也支持 SPI 接口。假设在产品设计阶段一开始将 icm20608 设计为 SPI 接口,但是后面发现 SPI 接口不够用,或者 SOC 的引脚不够用,我们需要将 icm20608 改为 I2C 接口。这个时候 icm20608 的驱动就要大改,我们需要将 SPI 接口函数换为 I2C 的,工作量比较大。

        基于代码复用的原则, Linux 内核引入了 regmap 模型, regmap 将寄存器访问的共同逻辑抽
象出来,驱动开发人员不需要再去纠结使用 SPI 或者 I2C 接口 API 函数,统一使用 regmap API函数。这样的好处就是统一使用 regmap,降低了代码冗余, 提高了驱动的可以移植性

        通过 regmap 模型提供的统一接口函数来访问器件的寄存器, SOC 内部的寄存器也可以使
用 regmap 接口函数来访问。regmap 是 Linux 内核为了减少慢速 I/O 在驱动上的冗余开销,提供了一种通用的接口来操作硬件寄存器。另外, regmap 在驱动和硬件之间添加了 cache,降低了低速 I/O 的操作次数,提高了访问效率,缺点是实时性会降低。

 什么情况下会使用 regmap:
①、硬件寄存器操作,比如选用通过 I2C/SPI 接口来读写设备的内部寄存器,或者需要读写 SOC 内部的硬件寄存器。
②、提高代码复用性和驱动一致性,简化驱动开发过程。
③、减少底层 I/O 操作次数,提高访问效率。

regmap 框架

 regmap API 抽象层, regmap 向驱动编写人员提供的 API 接口,驱动编写人员使用这些API 接口来操作具体的芯片设备

regmap 结构体

        Linux 内 核 将 regmap 框 架 抽 象 为 regmap 结 构 体 , 这 个 结 构 体 定 义 在 文 件
drivers/base/regmap/internal.h 中,要使用 regmap,肯定要先给驱动分配一个具体的 regmap 结构体实例, regmap 的初始化通过结构体 regmap_config 来完成。

regmap_config 结构体

        regmap_config 结构体就是用来初始化 regmap 的,这个结构体也定义在include/linux/regmap.h 文件中,里面有很多内容,其中reg_bits(寄存器地址位数),val_bits(寄存器值位数)为必填字段,read_flag_mask是读标志掩码,write_flag_mask:写标志掩码。

        一般会在 probe 函数中初始化 regmap_config,然后申请并初始化 regmap。

regmap_config 掩码设置

        结构体 regmap_config 里面有成员变量: read_flag_mask 和 write_flag_mask,这二个掩码非常重要。

        当使用 spi 接口的时候,读取 icm20608 寄存器的时候地址最高位必须置 1,写内部寄存器的是时候地址最高位要设置为 0。使用 regmap 的时候就不需要手动将寄存器地址的 bit7 置 1,在初始化 regmap_config的时候直接将 read_flag_mask 设置为 0X80 即可,这样通过 regmap 读取 SPI 内部寄存器的时候就会将寄存器地址与 read_flag_mask 进行或运算,结果就是将 bit7 置 1,但是整个过程不需要我们来操作,全部由 regmap 框架来完成的,同理 write_flag_mask 用法也一样的,只是 write_flag_mask 用于写寄存器操作

二、Regmap 操作函数

1、Regmap 申请与初始化

regmap 支持多种物理总线,比如 I2C 和 SPI,我们需要根据所使用的接口来选择合适的 regmap 初始化函数。 Linux 内核提供了针对不同接口的 regmap 初始化函数, SPI 接口初始化函数为 regmap_init_spi,函数原型如下:

struct regmap * regmap_init_spi(struct spi_device *spi,
                                                        const struct regmap_config *config)

spi: 需要使用 regmap 的 spi_device。
config: regmap_config 结构体,需要初始化一个 regmap_config 实例,然后将
其地址赋值给此参数。
返回值:申请到的并进过初始化的 regmap。

在退出驱动的时候需要释放掉申请到的 regmap,不管是什么接口,全部使用 regmap_exit 这
个函数来释放 regmap,函数原型如下

void regmap_exit(struct regmap *map)

map: 需要释放的 regmap

 2、 regmap 设备访问 API 函数

        不管是 I2C 还是 SPI 等接口,还是 SOC 内部的寄存器,对于寄存器的操作就两种:读和
写。 regmap 提供了最核心的两个读写操作: regmap_read 和 regmap_write。这两个函数分别用来读/写寄存器, regmap_read 函数原型如下:

int regmap_read(struct regmap *map,
                                unsigned int reg,
                                 unsigned int *val)

map: 要操作的 regmap。
reg: 要读的寄存器。
val:读到的寄存器值。
返回值: 0,读取成功;其他值,读取失败

regmap_write 函数原型如下

 int regmap_write(struct regmap *map,
                                unsigned int reg,
                                unsigned int val)

map: 要操作的 regmap。
reg: 要写的寄存器。
val:要写的寄存器值。
返回值: 0,写成功;其他值,写失败。

 3、regmap_update_bits 函数

修改寄存器指定的 bit

int regmap_update_bits (struct regmap *map,
                                        unsigned int reg,
                                        unsigned int mask,

                                        unsigned int val)

map: 要操作的 regmap。
reg: 要操作的寄存器。
mask: 掩码,需要更新的位必须在掩码中设置为 1。
val:需要更新的位值。
返回值: 0,写成功;其他值,写失败

比如要将寄存器的 bit1 和 bit2 置 1,那么 mask 应该设置为 0X00000011,此时 val 的 bit1
和 bit2 应该设置为 1,也就是 0Xxxxxxx11
如果要清除寄存器的 bit4 和 bit7,那么 mask 应该设置为 0X10010000, val 的 bit4 和 bit7 设置为 0,也就是 0X0xx0xxxx。

 4、regmap_bulk_read函数

读取多个寄存器的值

int regmap_bulk_read(struct regmap *map,
                                        unsigned int reg,
                                        void *val,
                                        size_t val_count)

map: 要操作的 regmap。
reg: 要读取的第一个寄存器。
val: 读取到的数据缓冲区。
val_count:要读取的寄存器数量。
返回值: 0,写成功;其他值,读失败

5、regmap_bulk_write

多个寄存器写函数

int regmap_bulk_write(struct regmap *map,
                                        unsigned int reg,
                                        const void *val,
                                        size_t val_count)

map: 要操作的 regmap。
reg: 要写的第一个寄存器。
val: 要写的寄存器数据缓冲区。
val_count:要写的寄存器数量。
返回值: 0,写成功;其他值,读失败

三、修改SPI实验

利用之前的spi实验改造

1、添加regmap结构体

 51行,regmap 指针变量, regmap 我们需要使用 regmap_init_spi 函数来申请和初始化,
所以这里是指针类型
52行,regmap_config 结构体成员变量,配置 regmap

2、probe函数

 284-286行,icm20608 的寄存器地址地址长度为 8bit,寄存器值也是 8bit,因此 reg_bits 和 val_bits 都设置为 8。由于 icm20608 通过 SPI 接口读取的时候地址寄存器最高位要设置为 1,因此 read_flag_mask 设置为 0X80。

288行,通过 regmap_init_spi 函数来申请并初始化 SPI 总线的 regmap。

3、remove函数 

在 remove 函数中就要删除 probe 里面申请的 regmap

4、读函数

把读写多个寄存器屏蔽了,这里没用到

 147行,用 regmap_read 函数来完成寄存器读取操作

5、写函数

 156行,直接使用 regmap_write 函数来完成写操作

6、读取ICM20608的数据

164行,regmap_bulk_read 函数来显示多个寄存器的读取

其他函数基本不变

代码如下

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/atomic.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include "icm20608reg.h"

#define ICM20608_CNT 1
#define ICM20608_NAME "icm20680"

/*设备结构体*/
struct icm20608_dev
{
    struct spi_device *spi;/*spi设备*/
    dev_t devid;           /* 设备号 	 */
    int major;             /* 主设备号 */
    int minor;             /* 次设备号 */
    struct cdev cdev;      /* cdev 	*/
    struct class *class;   /* 类 		*/
    struct device *device; /* 设备 	 */
    void *private_data; /* private_data */
   
    signed int gyro_x_adc;  /* 陀螺仪X轴原始值 	 */
    signed int gyro_y_adc;  /* 陀螺仪Y轴原始值		*/
    signed int gyro_z_adc;  /* 陀螺仪Z轴原始值 		*/
    signed int accel_x_adc; /* 加速度计X轴原始值 	*/
    signed int accel_y_adc; /* 加速度计Y轴原始值	*/
    signed int accel_z_adc; /* 加速度计Z轴原始值 	*/
    signed int temp_adc;    /* 温度原始值 			*/

    struct regmap *regmap;
    struct regmap_config regmap_config;
};
struct icm20608_dev icm20608dev;

#if 0
static int icm20608_read_regs(struct icm20608_dev *dev, u8 reg, void *buf, int len)
{
    

	int ret = -1;
	unsigned char txdata[1];
	unsigned char * rxdata;
	struct spi_message m;
	struct spi_transfer *t;
	struct spi_device *spi = (struct spi_device *)dev->private_data;
	t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);	/* 申请内存 */
	if(!t) {
		return -ENOMEM;
	}

	rxdata = kzalloc(sizeof(char) * len, GFP_KERNEL);	/* 申请内存 */
	if(!rxdata) {
		goto out1;
	}

	/* 一共发送len+1个字节的数据,第一个字节为
	寄存器首地址,一共要读取len个字节长度的数据,*/
	txdata[0] = reg | 0x80;		/* 写数据的时候首寄存器地址bit8要置1 */			
	t->tx_buf = txdata;			/* 要发送的数据 */
    t->rx_buf = rxdata;			/* 要读取的数据 */
	t->len = len+1;				/* t->len=发送的长度+读取的长度 */
	spi_message_init(&m);		/* 初始化spi_message */
	spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */
	ret = spi_sync(spi, &m);	/* 同步发送 */
	if(ret) {
		goto out2;
	}
	
    memcpy(buf , rxdata+1, len);  /* 只需要读取的数据 */

out2:
	kfree(rxdata);					/* 释放内存 */
out1:	
	kfree(t);						/* 释放内存 */
	
	return ret;
}


static s32 icm20608_write_regs(struct icm20608_dev *dev, u8 reg, u8 *buf, int len)
{
   int ret = -1;
	unsigned char *txdata;
	struct spi_message m;
	struct spi_transfer *t;
	struct spi_device *spi = (struct spi_device *)dev->private_data;
	
	t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);	/* 申请内存 */
	if(!t) {
		return -ENOMEM;
	}
	
	txdata = kzalloc(sizeof(char)+len, GFP_KERNEL);
	if(!txdata) {
		goto out1;
	}
	
	/* 一共发送len+1个字节的数据,第一个字节为
	寄存器首地址,len为要写入的寄存器的集合,*/
	*txdata = reg & ~0x80;	/* 写数据的时候首寄存器地址bit8要清零 */
    memcpy(txdata+1, buf, len);	/* 把len个寄存器拷贝到txdata里,等待发送 */
	t->tx_buf = txdata;			/* 要发送的数据 */
	t->len = len+1;				/* t->len=发送的长度+读取的长度 */
	spi_message_init(&m);		/* 初始化spi_message */
	spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */
	ret = spi_sync(spi, &m);	/* 同步发送 */
    if(ret) {
        goto out2;
    }
	
out2:
	kfree(txdata);				/* 释放内存 */
out1:
	kfree(t);					/* 释放内存 */
	return ret;
}

#endif

/*读取单个寄存器*/
static unsigned char icm20608_read_onereg(struct icm20608_dev *dev, u8 reg)
{
    u8 ret = 0;
    unsigned int data;
   /*icm20608_read_regs(dev, reg, &data, 1);*/
   ret = regmap_read(dev->regmap,reg,&data);
    return (u8)data;
}

/*icm20608写一个寄存器*/
static void icm20608_write_onereg(struct icm20608_dev *dev, u8 reg, u8 value)
{
   /*  u8 buf = value;
    icm20608_write_regs(dev, reg, &buf, 1); */
    regmap_write(dev->regmap,reg,value);
}

void icm20608_readdata(struct icm20608_dev *dev)
{
    u8 ret;
    unsigned char data[14] = {0};
    /*icm20608_read_regs(dev, ICM20_ACCEL_XOUT_H, data, 14);*/
    ret = regmap_bulk_read(dev->regmap,ICM20_ACCEL_XOUT_H,data,14);

    dev->accel_x_adc   = (signed short)((data[0] << 8)  | data[1]);
    dev->accel_y_adc   = (signed short)((data[2] << 8)  | data[3]);
    dev->accel_z_adc   = (signed short)((data[4] << 8)  | data[5]);
    dev->temp_adc      = (signed short)((data[6] << 8)  | data[7]);
    dev->gyro_x_adc    = (signed short)((data[8] << 8)  | data[9]);
    dev->gyro_y_adc    = (signed short)((data[10] << 8) | data[11]);
    dev->gyro_z_adc    = (signed short)((data[12] << 8) | data[13]);
}

static int icm20608_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &icm20608dev;
    return 0;
}
static ssize_t icm20608_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
    signed int data[7];
    long err = 0;
    struct icm20608_dev *dev = (struct icm20608_dev *)filp->private_data;

    icm20608_readdata(dev);
    data[0] = dev->gyro_x_adc;
    data[1] = dev->gyro_y_adc;
    data[2] = dev->gyro_z_adc;
    data[3] = dev->accel_x_adc;
    data[4] = dev->accel_y_adc;
    data[5] = dev->accel_z_adc;
    data[6] = dev->temp_adc;
    err = copy_to_user(buf, data, sizeof(data));
    return 0;
}
static int icm20608_release(struct inode *inode, struct file *filp)
{
    return 0;
}

/* icm20608操作函数 */
struct file_operations icm20608_fops = {
    .owner = THIS_MODULE,
    .open = icm20608_open,
    .release = icm20608_release,
    .read = icm20608_read,
};

/*ICM20608内部寄存器初始化函数*/
void icm20608_reginit(struct icm20608_dev *dev)
{
    u8 value = 0;

    icm20608_write_onereg(&icm20608dev, ICM20_PWR_MGMT_1, 0x80); /* 复位,复位后为0x40,睡眠模式          */
    mdelay(50);
    icm20608_write_onereg(&icm20608dev, ICM20_PWR_MGMT_1, 0x01); /* 关闭睡眠,自动选择时钟                   */
    mdelay(50);

    value = icm20608_read_onereg(&icm20608dev, ICM20_WHO_AM_I);
    printk("ICM20608 ID = %#X\r\n", value);

    value = icm20608_read_onereg(&icm20608dev, ICM20_PWR_MGMT_1);
    printk("ICM20_PWR_MGMT_1 = %#X\r\n", value);

    icm20608_write_onereg(&icm20608dev, ICM20_SMPLRT_DIV,   0x00);    /* 输出速率是内部采样率					*/
    icm20608_write_onereg(&icm20608dev, ICM20_GYRO_CONFIG,  0x18);   /* 陀螺仪±2000dps量程 				*/
    icm20608_write_onereg(&icm20608dev, ICM20_ACCEL_CONFIG, 0x18);  /* 加速度计±16G量程 					*/
    icm20608_write_onereg(&icm20608dev, ICM20_CONFIG,       0x04);        /* 陀螺仪低通滤波BW=20Hz 				*/
    icm20608_write_onereg(&icm20608dev, ICM20_ACCEL_CONFIG2,0x04); /* 加速度计低通滤波BW=21.2Hz 			*/
    icm20608_write_onereg(&icm20608dev, ICM20_PWR_MGMT_2,   0x00);    /* 打开加速度计和陀螺仪所有轴 				*/
    icm20608_write_onereg(&icm20608dev, ICM20_LP_MODE_CFG,  0x00);   /* 关闭低功耗 						*/
    icm20608_write_onereg(&icm20608dev, ICM20_FIFO_EN,      0x00);       /* 关闭FIFO	 */
}
static int icm20608_probe(struct spi_device *spi)
{
    int ret = 0;
    /* 1、构建设备号 */
    icm20608dev.major = 0;
    if (icm20608dev.major)
    {
        icm20608dev.devid = MKDEV(icm20608dev.major, 0);
        ret = register_chrdev_region(icm20608dev.devid, ICM20608_CNT, ICM20608_NAME);
    }
    else
    {
        ret = alloc_chrdev_region(&icm20608dev.devid, 0, ICM20608_CNT, ICM20608_NAME);
        icm20608dev.major = MAJOR(icm20608dev.devid);
        icm20608dev.minor = MINOR(icm20608dev.devid);
    }
    if (ret < 0)
    {
        printk("icm20608 chrdev_region err!\r\n");
        goto fail_devid;
    }
    printk("icm20608dev major = %d, minor = %d\r\n", icm20608dev.major, icm20608dev.minor);
    /* 2、注册设备 */
    icm20608dev.cdev.owner = THIS_MODULE;
    cdev_init(&icm20608dev.cdev, &icm20608_fops);
    ret = cdev_add(&icm20608dev.cdev, icm20608dev.devid, ICM20608_CNT);
    if (ret < 0)
    {
        printk("icm20608 cdev_add err!\r\n");
        goto fail_cdev;
    }
    /* 3、创建类 */
    icm20608dev.class = class_create(THIS_MODULE, ICM20608_NAME);
    if (IS_ERR(icm20608dev.class))
    {
        ret = PTR_ERR(icm20608dev.class);
        printk("icm20608 chrdev_class err!\r\n");
        goto fail_class;
    }
    /* 4、创建设备 */
    icm20608dev.device = device_create(icm20608dev.class, NULL,
                                       icm20608dev.devid, NULL, ICM20608_NAME);
    if (IS_ERR(icm20608dev.device))
    {
        ret = PTR_ERR(icm20608dev.device);
        printk("icm20608 chrdev_device err!\r\n");
        goto fail_device;
    }
       /*regmap申请和初始虾化*/
    icm20608dev.regmap_config.reg_bits = 8;/*寄存器长度8bit*/
    icm20608dev.regmap_config.val_bits = 8;/*值长度为8bit*/
    icm20608dev.regmap_config.read_flag_mask = 0x80;/*读掩码*/

    icm20608dev.regmap = regmap_init_spi(spi,&icm20608dev.regmap_config);
    if(IS_ERR(icm20608dev.regmap))
    {
        return PTR_ERR(icm20608dev.regmap);
    }

    /*初始化spi_device*/
    spi->mode = SPI_MODE_0;
    spi_setup(spi);
    /*设置icm20608私有数据*/
    icm20608dev.private_data = spi;

    /*初始化icm20608*/
    icm20608_reginit(&icm20608dev);

    printk("icm20608_probe\r\n");
    return 0;

fail_device:
    class_destroy(icm20608dev.class);
fail_class:
    cdev_del(&icm20608dev.cdev);
fail_cdev:
    unregister_chrdev_region(icm20608dev.devid, ICM20608_CNT);
fail_devid:
    regmap_exit(icm20608dev.regmap);
    return ret;
}

static int icm20608_remove(struct spi_device *spi)
{
    /* 删除字符设备 */
    cdev_del(&icm20608dev.cdev);
    /*注销设备号*/
    unregister_chrdev_region(icm20608dev.devid, ICM20608_CNT);
    /*摧毁设备*/
    device_destroy(icm20608dev.class, icm20608dev.devid);
    /*摧毁类*/
    class_destroy(icm20608dev.class);
    /*删除regmap*/
    regmap_exit(icm20608dev.regmap);
    
    printk("icm20608_remove\r\n");
    return 0;
}

/*传统匹配*/
struct spi_device_id icm20608_id[] = {
    {"my,icm20608", 0},
    {}
};
/*设备树匹配*/
static const struct of_device_id icm20608_of_match[] = {
    {.compatible = "my,icm20608"},
    {}
};
/* SPI驱动结构体 */
static struct spi_driver icm20608_driver = {
    .probe = icm20608_probe,
    .remove = icm20608_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "icm20608",
        .of_match_table = icm20608_of_match,
    },
    .id_table = icm20608_id,
};

/*驱动入口*/
static int __init icm20608_init(void)
{
    return spi_register_driver(&icm20608_driver);
}
/*驱动出口*/
static void __exit icm20608_exit(void)
{
    spi_unregister_driver(&icm20608_driver);
}

module_init(icm20608_init);
module_exit(icm20608_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ba che kai qi lai");

 实现现象是和spi实验是一样的

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

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

相关文章

Kubenates中的日志收集方案ELK(下)

1、rpm安装Logstash wget https://artifacts.elastic.co/downloads/logstash/logstash-6.8.7.rpm yum install -y logstash-6.8.7.rpm2、创建syslog配置 input {beats{port> 5044 } }output {elasticsearch {hosts > ["http://localhost:9200"]index …

【博客632】k8s service ession affinity原理与iptables recent模块

k8s service ession affinity原理与iptables recent模块 1、iptables recent模块 作用&#xff1a; iptables的recent模块用于限制一段时间内的连接数, 是谨防大量请求攻击的必杀绝技! 善加利用该模块可充分保证服务器安全。 recent常用参数&#xff1a; –name 设定列表名称…

Git使用教程:最详细、最傻瓜、最浅显、真正手把手教

GITGIT版本控制版本控制的意义分布式图形化客户端环境搭建仓库的操作分支使用场景命令远程仓库操作生成公钥命令冲突忽略列表的配置时机配置方式版本回退练习&#xff1a;GIT 版本控制 把文件系统中的文件&#xff0c;按照修改的版本进行记录&#xff0c;进行管理的操作。 版…

Spring Cloud ( Consul注册、发现 )

操作步骤&#xff1a; 安装Consul服务端在服务内添加客户端依赖修改配置类&#xff0c;添加注解编写yml文件一、安装Consul服务端 链接&#xff1a;https://www.consul.io/downloads.html&#xff0c;解压 开启cmd&#xff0c;进入你的Consul解压路径&#xff0c;我是在E盘 …

扩展欧几里得算法及其应用

前言 由于数论的板子真的很抽象&#xff0c;也很难背&#xff0c;所以特此记录扩展欧几里得算法的板子和它的用途 本篇文章只涉及应用&#xff0c;不涉及证明&#xff0c;如需理解证明还请各位移步其他优秀的讲解&#xff01; 扩展欧几里得算法 先粘一下板子的代码 typedef lo…

JAVA面向对象特征之——封装

4.封装 private关键字 是一个权限修饰符 可以修饰成员(成员变量和成员方法) 作用是保护成员不被别的类使用&#xff0c;被private修饰的成员只在本类中才能访问 针对private修饰的成员变量&#xff0c;如果需要被其他类使用&#xff0c;提供相应的操作 提供 “get变量名()…

面向数据安全共享的联邦学习研究综述

开放隐私计算 摘 要&#xff1a;跨部门、跨地域、跨系统间的数据共享是充分发挥分布式数据价值的有效途径&#xff0c;但是现阶段日益严峻的数据安全威胁和严格的法律法规对数据共享造成了诸多挑战。联邦学习可以联合多个用户在不传输本地数据的情况下协同训练机器学习模型&am…

【SpringCloud】SpringCloud详解之Feign远程调用

目录前言SpringCloud Feign远程服务调用一.需求二.两个服务的yml配置和访问路径三.使用RestTemplate远程调用(order服务内编写)四.构建Feign(order服务内配置)五.自定义Feign配置(order服务内配置)六.Feign配置日志(oder服务内配置)七.Feign调优(order服务内配置)八.抽离Feign前…

SNS (Simple Notification Service)简介

SNS (Simple Notification Service) 是一种完全托管的发布/订阅消息收发和移动通知服务&#xff0c;用于协调向订阅终端节点和客户端的消息分发。 和SQS (Simple Queue Service)一样&#xff0c;SNS也可以轻松分离和扩展微服务&#xff0c;分布式系统和无服务应用程序&#xf…

九龙证券|直逼1.5万亿!A股融资余额创年内新高,青睐这些行业和个股

2023年以来&#xff0c;A股商场震动重复&#xff0c;商场走势整体先扬后抑&#xff0c;各路资金看法纷歧&#xff0c;但数据显现&#xff0c;融资客在此期间整体持续净买入&#xff0c;未受到商场动摇的明显冲击&#xff0c;融资余额日前已迫临1.5万亿元&#xff0c;创出年内新…

磨金石教育摄影技能干货分享|烟花三月下扬州,是时候安排了!

人间三月最柔情&#xff0c;杨柳依依水波横。三月的风将要吹来&#xff0c;春天的门正式打开。对中国人来说&#xff0c;古往今来&#xff0c;赏春最好的地方是江南。人人都说江南好&#xff0c;可是江南哪里好呢&#xff1f;古人在这方面早就给出了答案&#xff1a;故人西辞黄…

使用高精度秒表StopWatch测试DateTime.Now的精度

StopWatch使用的命名空间&#xff1a;using System.Diagnostics;StopWatch的使用方法&#xff1a;创建Stopwatch对象&#xff1a;stopwatch&#xff1b;stopwatch计时表开启&#xff1a;stopwatch.Start();stopwatch计时表关闭&#xff1a;stopwatch.Stop();计算stopwatch.Stop…

【剧前爆米花--爪哇岛寻宝】进程的调度以及并发和并行,以及PCB中属性的详解。

作者&#xff1a;困了电视剧 专栏&#xff1a;《JavaEE初阶》 文章分布&#xff1a;这是关于进程调度、并发并行以及相关属性详解的文章&#xff0c;我会在之后文章中更新有关线程的相关知识&#xff0c;并将其与进程进行对比&#xff0c;希望对你有所帮助。 目录 什么是进程/…

redis布隆过滤器与四个缓存问题

目录布隆过滤器定义特性使用场景解决缓存穿透的问题黑白名单校验底层原理哈希冲突案例添加key查询key总结四个缓存问题缓存雪崩定义解决方案缓存穿透定义解决方案方案一方案二(guava实现)代码案例源码分析方案三(RedisSon实现)代码实现方案四(直接安装redis插件,应用层解决方案…

港科夜闻|香港科大与中国联通成立联合实验室,推动智慧社会研究发展

关注并星标每周阅读港科夜闻建立新视野 开启新思维1、香港科大与中国联通成立联合实验室&#xff0c;推动智慧社会研究发展。香港科大与中国联通于3月9日签署两份协议以加强战略合作&#xff0c;并成立「香港科技大学 - 中国联通智慧社会联合实验室」&#xff0c;就香港科大建构…

基于支持向量机SVM的风电场NWP数据预测,SVM的详细原理

目录 支持向量机SVM的详细原理 SVM的定义 SVM理论 Libsvm工具箱详解 简介 参数说明 易错及常见问题 SVM应用实例,基于SVM的风电场NWP预测 结果分析 展望 支持向量机SVM的详细原理 SVM的定义 支持向量机(support vector machines, SVM)是一种二分类模型,它的基本模型是定…

江苏专转本转本人后悔排行榜

江苏专转本转本人后悔排行榜 一、复习的太迟&#xff1a; 后悔指数:五颗星。 复习越到最后&#xff0c;时间一天天变少&#xff0c;要复习的内容还有很多&#xff0c;很多人都后悔没有早早开始&#xff0c;总想着多给我两月一定会考上的。 担心时间不够用&#xff0c;那就努力利…

【论文阅读】浏览器扩展危害-Helping or Hindering? How Browser Extensions Undermine Security

本文来源于ACM CCS 2022&#xff1b; https://dl.acm.org/doi/10.1145/3548606.3560685 摘要 “浏览器扩展”是轻量级的浏览器附加组件&#xff0c;使用各个浏览器特定的功能丰富的JavaScript api&#xff0c;为用户提供了额外的Web客户端功能&#xff0c;如改进网站外观和与…

【id:21】【20分】A. DS单链表--类实现

题目描述用C语言和类实现单链表&#xff0c;含头结点属性包括&#xff1a;data数据域、next指针域操作包括&#xff1a;插入、删除、查找注意&#xff1a;单链表不是数组&#xff0c;所以位置从1开始对应首结点&#xff0c;头结点不放数据类定义参考输入n第1行先输入n表示有n个…

Amazon GuardDuty 的新增功能 – Amazon EBS 卷的恶意软件检测

亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、开发案例、技术专栏、培训视频、活动与竞赛等。帮助中国开发者对接世界最前沿技术&#xff0c;观点&#xff0c;和项目&#xff0c;并将中国优秀开发者或技术推荐给全球云社区。如果你还没有关注/收藏…