当前位置: 首页 > news >正文

Linux RN6752 驱动编写

一、概述

关于 RN6752V1 这个芯片这里就不做介绍了,看到这篇笔记的小伙伴应该都明白,虽然说 RN6752V1 芯片是 AHD 信号的解码芯片,但是也可以把芯片当做是一个 YUV 信号的 MIPI 摄像头,所以驱动的编写和 MIPI 摄像头无太大的区别。这里主要是介绍具体的函数,关于 MIPI 驱动的框架程序看我之前的笔记:Linux MIPI 摄像头驱动框架编写(RN6752解码芯片)

二、RN6752 帧格式

RN6752 支持 DVP 和 MIPI 信号,这里我主要是对 MIPI 信号的使用,当然 DVP 通信的操作也可以做参考。

  1. 寄存地配置通过代理商提供的头文件中可以获取到相关寄存器的配置,如下所示:

static const struct sensor_register rn6752_fhd_1080P25_video[] = {{ 0x19, 0x0A }, // 视频格式检测滞后控制{ 0x81, 0x01 }, // 打开视频解码器{ 0xDF, 0xFE }, // 启用HD格式{ 0xF0, 0xC0 },	// 使能 FIFO 和 144 MHz 解码器输出{ 0xA3, 0x04 }, // 启用 HD 输出{ 0x88, 0x40 }, // 禁用 SCLK1 输出{ 0xF6, 0x40 }, // 禁用 SCLK3A 输出/* 切换到ch0(默认;可选) */{ 0xFF, 0x00 },	// 寄存器集选择{ 0x33, 0x10 }, // 检测中的视频{ 0x4A, 0xA8 }, // 检测中的视频{ 0x00, 0x20 }, // internal use*{ 0x06, 0x08 }, // internal use*{ 0x07, 0x63 }, // 高清格式{ 0x2A, 0x01 }, // 滤波器控制{ 0x3A, 0x24 }, // 在SAV/EAV代码中插入通道ID{ 0x3F, 0x10 }, // 通道ID{ 0x4C, 0x37 }, // 均衡器{ 0x4F, 0x03 }, // 同步控制{ 0x50, 0x03 }, // 1080p分辨率{ 0x56, 0x02 }, // 144M 和 BT656模式{ 0x5F, 0x44 }, // 消隐电平{ 0x63, 0xF8 }, // 滤波器控制{ 0x59, 0x00 }, // 扩展寄存器存取{ 0x5A, 0x48 }, // 扩展寄存器的数据{ 0x58, 0x01 }, // 启用扩展寄存器写入{ 0x59, 0x33 }, // 扩展寄存器存取{ 0x5A, 0x23 }, // 扩展寄存器的数据{ 0x58, 0x01 }, // 启用扩展寄存器写入{ 0x51, 0xF4 }, // 比例因子1{ 0x52, 0x29 }, // 比例因子2{ 0x53, 0x15 }, // 比例因子3{ 0x5B, 0x01 }, // H-标度控制{ 0x5E, 0x08 }, // 启用H缩放控制{ 0x6A, 0x87 }, // H-标度控制{ 0x28, 0x92 }, // 剪裁{ 0x03, 0x80 }, // 饱和{ 0x04, 0x80 }, // 颜色{ 0x05, 0x04 }, // 尖锐{ 0x57, 0x23 }, // 黑色/白色拉伸{ 0x68, 0x00 }, // coring{ 0x37, 0x33 }, // { 0x61, 0x6C }, //
#ifdef USE_BLUE_SCREEN{ 0x3A, 0x24 }, // AHD 断开链接时,屏幕为蓝色
#else{ 0x3A, 0x2C }, // AHD 断开链接时,屏幕为黑色{ 0x3B, 0x00 }, //{ 0x3C, 0x80 }, //{ 0x3D, 0x80 }, //
#endif{ 0x2E, 0x30 }, // 强制不播放视频{ 0x2E, 0x00 }, // 回归平常/* mipi 连接 */{ 0xFF, 0x09 }, // 切换到 mipi tx1{ 0x00, 0x03 }, // enable bias{ 0xFF, 0x08 }, // 切换到 mipi csi1{ 0x04, 0x03 }, // csi1 和 tx1 重置{ 0x6C, 0x11 }, // 禁用 ch 输出,打开 ch0
#ifdef USE_MIPI_4LANES{ 0x06, 0x7C }, // mipi 4 线
#else{ 0x06, 0x4C }, // mipi 2 线
#endif{ 0x21, 0x01 }, // 启用 hs 时钟{ 0x34, 0x06 }, //{ 0x35, 0x0B }, // { 0x78, 0xC0 }, // ch0 的 Y/C 计数{ 0x79, 0x03 }, // ch0 的 Y/C 计数{ 0x6C, 0x01 }, // 启用 ch 输出{ 0x04, 0x00 }, // csi1 和 tx1 重置完成{ 0x20, 0xAA }, // 
#ifdef USE_MIPI_NON_CONTINUOUS_CLOCK{ 0x07, 0x05 }, // 启用非连续时钟
#else{ 0x07, 0x04 }, // 启用连续时钟
#endif{ 0xFF, 0x0A }, // 切换到 mipi csi3{ 0x6C, 0x10 }, // 禁用 ch 输出;关闭 ch0~3{REG_NULL, 0x00},
};

注意: 其他格式的寄存器我这里就不附上了,可以参考代理商提供的头文件

  1. 将配置信息存入帧列表中

static const struct rn6752_framesize rn6752_mipi_framesizes[] = {{.width		= 1280,.height		= 720,.max_fps = {.numerator = 10000,.denominator = 250000,},.regs		= rn6752_fhd_720P25_video,}, {.width		= 1280,.height		= 720,.max_fps = {.numerator = 10000,.denominator = 300000,},.regs		= rn6752_fhd_720P30_video,}, {.width		= 1920,.height		= 1080,.max_fps = {.numerator = 10000,.denominator = 250000,},.regs		= rn6752_fhd_1080P25_video,}, {.width		= 1920,.height		= 1080,.max_fps = {.numerator = 10000,.denominator = 300000,},.regs		= rn6752_fhd_1080P30_video,}, {.width		= 1280,.height		= 960,.max_fps = {.numerator = 10000,.denominator = 250000,},.regs		= rn6752_fhd_960P25_video,}, {.width		= 1280,.height		= 960,.max_fps = {.numerator = 10000,.denominator = 300000,},.regs		= rn6752_fhd_960P30_video,}
};

  1. 配置默认帧在 rn6752_probe 函数中存入默认支持的帧列表,如下所示

static void rn6752_get_default_format(struct rn6752 *rn6752,struct v4l2_mbus_framefmt *format)
{format->width = rn6752->framesize_cfg[2].width; 	/* 设置默认宽度 */format->height = rn6752->framesize_cfg[2].height; 	/* 设置默认高度 */format->colorspace = V4L2_COLORSPACE_SRGB; 			/* 设置默认色彩空间为标准的 sRGB 色彩空间 */format->code = rn6752_formats[0].code; 				/* 设置默认编码格式 */format->field = V4L2_FIELD_NONE; 					/* 设置默认场模式 */
}/* rn6752_mipi_framesizes 是 rn6752 mipi 通信支持的所有帧格式 */
rn6752->framesize_cfg = rn6752_mipi_framesizes;
rn6752->cfg_num = ARRAY_SIZE(rn6752_mipi_framesizes);
/* 获取摄像头传感器支持的图像帧格式 */
rn6752_get_default_format(rn6752, &rn6752->format);
rn6752->frame_size = &rn6752->framesize_cfg[2]; 			/* 设置帧大小 */
rn6752->format.width = rn6752->framesize_cfg[2].width; 		/* 设置宽度 */
rn6752->format.height = rn6752->framesize_cfg[2].height; 	/* 设置高度 */
rn6752->fps = DIV_ROUND_CLOSEST(rn6752->framesize_cfg[2].max_fps.denominator,rn6752->framesize_cfg[2].max_fps.numerator); 			/* 设置最大帧速率 */

注意:

  • 首先将所有支持的帧列表存入了 rn6752->framesize_cfg 中

  • 将支持的列表数量存入 rn6752->cfg_num 中

  • 将默认支持的帧格式和大小存入 rn6752->format 中,这个在用户空间可以查看

  • 将默认支持的帧大小存入 rn6752->frame_size 中

  • 将默认支持的帧率存入 rn6752->fps 中

  • 以上这些默认变量将在后面的函数中经常用到,所以需要特别注意一下,不然很难理解数据从哪里来的

三、Media 设备节点

之前在 Media 子系统中提到过模块之间的关系查看命令media-ctl -p -d /dev/mediaX,通过命令可以得到驱动中的一些信息,如下图所示

  1. Media 帧大小Media 帧大小是在驱动初始化时,通过 rn6752_get_fmt 函数获取的,程序如下

static int rn6752_get_fmt(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_format *fmt)
{struct i2c_client *client = v4l2_get_subdevdata(sd); /* 获取i2c_client指针 */struct rn6752 *rn6752 = to_rn6752(sd);/* 使用dev_dbg打印日志,显示当前函数进入 */// dev_info(&client->dev, "%s enter\n", __func__);/* 条件成立时,表示要获取正在尝试的格式 */if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_APIstruct v4l2_mbus_framefmt *mf;/* 获取正在尝试的格式 */mf = v4l2_subdev_get_try_format(sd, cfg, 0);mutex_lock(&rn6752->lock);fmt->format = *mf;mutex_unlock(&rn6752->lock);return 0;
#elsereturn -ENOTTY;
#endif}/* 条件不成立时,表示要获取当前的格式 */mutex_lock(&rn6752->lock);fmt->format = rn6752->format;mutex_unlock(&rn6752->lock);/* 使用dev_dbg打印日志,显示当前格式的代码值、宽度和高度 */dev_dbg(&client->dev, "%s: %x %dx%d\n", __func__, rn6752->format.code,rn6752->format.width, rn6752->format.height);return 0;
}

  1. 帧格式判断

Media 设备是通过 rn6752_enum_frame_sizes 和 rn6752_enum_frame_interval 函数枚举了帧大小和帧率,这两个函数主要起到判断的作用,确实当前帧率是否是驱动支持的,程序如下

static int rn6752_enum_frame_sizes(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_frame_size_enum *fse)
{struct rn6752 *rn6752 = to_rn6752(sd);struct i2c_client *client = v4l2_get_subdevdata(sd);int i = ARRAY_SIZE(rn6752_formats);printk(KERN_INFO"rn6752_enum_frame_sizes................................................\n");dev_dbg(&client->dev, "%s:\n", __func__);if (fse->index >= rn6752->cfg_num)return -EINVAL;while (--i)if (fse->code == rn6752_formats[i].code)break;fse->code = rn6752_formats[i].code;fse->min_width  = rn6752->framesize_cfg[fse->index].width;fse->max_width  = fse->min_width;fse->max_height = rn6752->framesize_cfg[fse->index].height;fse->min_height = fse->max_height;return 0;
}static int rn6752_enum_frame_interval(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_frame_interval_enum *fie)
{struct rn6752 *rn6752 = to_rn6752(sd);printk(KERN_INFO"rn6752_enum_frame_interval index: %d....................\n", fie->index );/* 检查传入的 fie 结构体中的 index 字段是否超出了 rn6752 所支持的帧间隔配置数量(cfg_num) */if (fie->index >= rn6752->cfg_num)return -EINVAL;/* 检查传入的 fie 结构体中的 code 字段是否与期望的媒体总线格式(MEDIA_BUS_FMT_UYVY8_2X8)匹配 */if (fie->code != MEDIA_BUS_FMT_UYVY8_2X8)return -EINVAL;fie->width = rn6752->framesize_cfg[fie->index].width;           /* 宽 */fie->height = rn6752->framesize_cfg[fie->index].height;         /* 高 */fie->interval = rn6752->framesize_cfg[fie->index].max_fps;      /* 最大帧率 */return 0;
}

  1. 帧大小设置

可以通过 rn6752_set_fmt 函数设置帧的大小,程序如下

tatic int rn6752_set_fmt(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_format *fmt)
{struct i2c_client *client = v4l2_get_subdevdata(sd);int index = ARRAY_SIZE(rn6752_formats);struct v4l2_mbus_framefmt *mf = &fmt->format;const struct rn6752_framesize *size = NULL;struct rn6752 *rn6752 = to_rn6752(sd);printk(KERN_INFO"rn6752_set_fmt................................................\n");dev_info(&client->dev, "%s enter\n", __func__);/* 根据传入的参数调整帧大小和帧速率,并返回适合的帧大小和帧速率 */__rn6752_try_frame_size_fps(rn6752, mf, &size, rn6752->fps);/* 遍历rn6752_formats数组 */while (--index >= 0)if (rn6752_formats[index].code == mf->code)break;if (index < 0)return -EINVAL;/* 色彩空间为sRGB,场为无 */mf->colorspace = V4L2_COLORSPACE_SRGB;mf->code = rn6752_formats[index].code;mf->field = V4L2_FIELD_NONE;mutex_lock(&rn6752->lock);if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_APImf = v4l2_subdev_get_try_format(sd, cfg,fmt->pad); /* 使用v4l2_subdev_get_try_format函数获取正在尝试的格式 */*mf = fmt->format;
#elsereturn -ENOTTY;
#endif} else {if (rn6752->streaming) {mutex_unlock(&rn6752->lock);return -EBUSY;}/* 分别设置为获取到的帧大小和传入的格式 */rn6752->frame_size = size;rn6752->format = fmt->format;}mutex_unlock(&rn6752->lock);return 0;
}

  1. 帧间隔获取

static int rn6752_g_frame_interval(struct v4l2_subdev *sd,struct v4l2_subdev_frame_interval *fi)
{struct rn6752 *rn6752 = to_rn6752(sd);printk(KERN_INFO"rn6752_g_frame_interval................................................\n");mutex_lock(&rn6752->lock);fi->interval = rn6752->frame_size->max_fps;mutex_unlock(&rn6752->lock);return 0;
}

四、总线编码格式

之前有提到过,RN6752 支持 DVP 和 MIPI 总线格式,所以可以在一个驱动中实现两个功能,这里我就是写了 MIPI 的通信方式,我目前对 DVP 也不了解,以后在补上。

刚好驱动中提供了两个函数可以获取驱动总线的格式,如下所示

  1. 获取当前媒体总线配置的函数

static int rn6752_g_mbus_config(struct v4l2_subdev *sd,struct v4l2_mbus_config *config)
{printk(KERN_INFO"rn6752_g_mbus_config................................................\n");/* 总线类型是CSI-2 */config->type = V4L2_MBUS_CSI2;config->flags = V4L2_MBUS_CSI2_4_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |V4L2_MBUS_CSI2_CHANNEL_1 |V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;return 0;
}

  1. 枚举所有支持的媒体总线编码和格式

static int rn6752_enum_mbus_code(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_mbus_code_enum *code)
{struct i2c_client *client = v4l2_get_subdevdata(sd);printk(KERN_INFO"rn6752_enum_mbus_code................................................\n");dev_dbg(&client->dev, "%s:\n", __func__);if (code->index >= ARRAY_SIZE(rn6752_formats))return -EINVAL;code->code = rn6752_formats[code->index].code;return 0;
}

五、电源管理

摄像头每次开启和关闭时,都需要通过电源管理函数配置摄像头电源

static int rn6752_power(struct v4l2_subdev *sd, int on)
{struct rn6752 *rn6752 = to_rn6752(sd);struct i2c_client *client = rn6752->client;int ret = 0;/* 使用dev_info打印日志,显示当前函数和行号,并打印on参数的值 */dev_dbg(&client->dev, "%s(%d) on(%d)\n", __func__, __LINE__, on);mutex_lock(&rn6752->lock);if (rn6752->power_on == !! on)goto unlock_and_return;if (on) {ret = pm_runtime_get_sync(&client->dev);if (ret < 0) {pm_runtime_put_noidle(&client->dev);goto unlock_and_return;}rn6752->power_on = true;} else {pm_runtime_put(&client->dev);rn6752->power_on = false;}unlock_and_return:mutex_unlock(&rn6752->lock);return ret;
}

六、摄像头控制

由于这里我没有实现太多的控制功能,所以只实现了必要的两个控制,最主要的是复位时执行的 RKMODULE_SET_QUICK_STREAM 功能

static long rn6752_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{struct rn6752 *rn6752 = to_rn6752(sd);// struct rkmodule_hdr_cfg *hdr;long ret = 0;u32 stream = 0;// dev_dbg(KERN_INFO "rn6752_ioctl  0x%x..........\n", cmd);switch (cmd) {case RKMODULE_GET_MODULE_INFO:rn6752_get_module_info(rn6752, (struct rkmodule_inf *)arg);break;case RKMODULE_SET_QUICK_STREAM:stream = *((u32 *)arg);rn6752_set_streaming(rn6752, !!stream);break;default:ret = -ENOIOCTLCMD;break;}return ret;
}#ifdef CONFIG_COMPAT
static long rn6752_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,unsigned long arg)
{void __user *up = compat_ptr(arg);struct rkmodule_inf *inf;struct rkmodule_awb_cfg *cfg;long ret;u32 stream = 0;// dev_dbg(KERN_INFO "rn6752_compat_ioctl32..........\n");switch (cmd) {case RKMODULE_GET_MODULE_INFO:inf = kzalloc(sizeof(*inf), GFP_KERNEL);if (!inf) {ret = -ENOMEM;return ret;}ret = rn6752_ioctl(sd, cmd, inf);if (!ret)ret = copy_to_user(up, inf, sizeof(*inf));kfree(inf);break;case RKMODULE_AWB_CFG:cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);if (!cfg) {ret = -ENOMEM;return ret;}ret = copy_from_user(cfg, up, sizeof(*cfg));if (!ret)ret = rn6752_ioctl(sd, cmd, cfg);kfree(cfg);break;case RKMODULE_SET_QUICK_STREAM:ret = copy_from_user(&stream, up, sizeof(u32));if (!ret)ret = rn6752_ioctl(sd, cmd, &stream);break;default:ret = -ENOIOCTLCMD;break;}return 0;
}
#endif

七、数据流控制

整个驱动最重要的便是流控制函数,通过此函数完成了摄像头的启动和停止

static int rn6752_set_streaming(struct rn6752 *rn6752, int on)
{struct i2c_client *client = rn6752->client;int ret = 0;dev_info(&client->dev, "%s: on: %d\n", __func__, on);if (on){ret = rn6752_write(client, 0x80, 0x31);usleep_range(200, 500);ret |= rn6752_write(client, 0x80, 0x30);if (ret){dev_err(&client->dev, "rn6752 soft reset failed\n");return ret;}ret = rn6752_write_array(client, rn6752->frame_size->regs);if (ret)dev_err(&client->dev, "rn6752 start initialization failed\n");}else{ret = rn6752_write(client, 0x80, 0x00);if (ret)dev_err(&client->dev, "rn6752 soft standby failed\n");}return ret;
}static int rn6752_s_stream(struct v4l2_subdev *sd, int on)
{struct i2c_client *client = v4l2_get_subdevdata(sd);struct rn6752 *rn6752 = to_rn6752(sd);int ret = 0;unsigned int fps;/* 计算帧率和延迟时间 */fps = DIV_ROUND_CLOSEST(rn6752->frame_size->max_fps.denominator,rn6752->frame_size->max_fps.numerator);dev_info(&client->dev, "%s: on: %d, %dx%d@%d\n", __func__, on,rn6752->frame_size->width, rn6752->frame_size->height,DIV_ROUND_CLOSEST(rn6752->frame_size->max_fps.denominator,rn6752->frame_size->max_fps.numerator));mutex_lock(&rn6752->lock);on = !!on;if (rn6752->streaming == on)goto unlock;if (on) {ret = pm_runtime_get_sync(&client->dev);if (ret < 0){pm_runtime_put_noidle(&client->dev);goto unlock;}}rn6752->streaming = on;ret = rn6752_set_streaming(rn6752, on);if (ret)rn6752->streaming = !on;pm_runtime_put(&client->dev);unlock:mutex_unlock(&rn6752->lock);return ret;
}

注意: 摄像头驱动中并没有图像接收之类的关系,而数据流操作函数主要的作用是对芯片进行初始化,使摄像头进入工作模式。从上面的驱动程序可以看出,整个驱动并没有其他特别的功能,就是一个 I2C 控制功能,所以摄像头的驱动其实就是一个 I2C 驱动程序。

由于笔记内容有点多,这里我就不附上完成的驱动程序了,其次是驱动程序也比较简单,看完的小伙伴应该都能明白。主要的难度都在调试摄像头驱动上面,我也折腾了很久,有需要的小伙变可以看我后面的笔记

参考资料

gc2145.c 和 imx335.c 驱动程序

文章转载自:浇筑菜鸟

原文链接:https://www.cnblogs.com/jzcn/p/17825502.html

相关文章:

Linux RN6752 驱动编写

一、概述 关于 RN6752V1 这个芯片这里就不做介绍了&#xff0c;看到这篇笔记的小伙伴应该都明白&#xff0c;虽然说 RN6752V1 芯片是 AHD 信号的解码芯片&#xff0c;但是也可以把芯片当做是一个 YUV 信号的 MIPI 摄像头&#xff0c;所以驱动的编写和 MIPI 摄像头无太大的区别。…...

扩展ACL命令

扩展ACL 语法&#xff1a;access-list access-list-number { permit | deny } protocol { source source-wildcard destination destination-wildcard } [ operator operan ] ------------------------------------------------------------------------------------------…...

多媒体信号处理复习笔记 --脑图版本

多媒体信号处理复习笔记 --脑图版本 依据 [2020多媒体信号处理复习笔记] 考前复习时使用Xmind制作 例图: PDF下载 BaiduYunPan 提取码&#xff1a;jbyw CSDN 下载...

力扣二叉树--第三十五天

前言 二叉搜索树&#xff0c;写了一道题&#xff0c;第二题没写出来。明天再写吧。。。 内容 一、二叉搜索树中的搜索 700. 二叉搜索树中的搜索 给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和一个整数值 val。 你需要在 BST 中找到节点值等于 val 的节点。…...

先喝点水,这期程序员兼职干货没有水分!

钱越来越难挣?程序员找兼职越来越难&#xff1f;结局只能指路美团&#xff1f; 还没看透职场“高薪”骗局&#xff1f;别人早就把精力放在了做副业上。兼职找不到&#xff0c;多半是经验不够、思路没打开&#xff0c;本篇文章&#xff0c;应该能让你茅塞顿开、收获颇丰。先喝…...

vue3通过el-dropdown实现动态菜单切换页面

这是效果图 首先是主页index.vue <template><el-row><el-col :span"20"><!-- 顶部菜单 --><div v-if"showTop"><topmenu /></div><!-- 右侧下方区域动态切换的内容 --><div style"flex: 1;&quo…...

go学习之文件操作与命令行参数

文章目录 一、文件操作1.基本介绍2.常用文件操作函数和方法3.关于文件操作应用实例4.写文件操作应用实例&#xff08;创建文件并写入文件&#xff09;1&#xff09;基本介绍2&#xff09;基本应用实例-方式一 5.判断文件是否存在6.统计英文、数字、空格和其他字符数量 二、命令…...

面试题:海量PDF的OCR处理思路

关键点&#xff1a; 1000wPDF&#xff1a;数据量非常大。3天处理完&#xff1a;有时间限制。一篇PDF1~10s&#xff1a;可能需要以最高10s去做计算&#xff0c;这样时间才能保证留有富余。要求资源最大化利用&#xff1a;也就是尽可能节省服务器资源&#xff0c;能复用尽量复用&…...

[原创][2]探究C#多线程开发细节-“线程的无顺序性“

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX QQ: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、Delph…...

【精选】Spring整合MyBatis,Junit 及Spring 事务Spring AOP面向切面详解

Spring整合MyBatis 搭建环境 我们知道使用MyBatis时需要写大量创建SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession等对象的代码&#xff0c;而Spring的作用是帮助我们创建和管理对象&#xff0c;所以我们可以使用Spring整合MyBatis&#xff0c;简化MyBatis开发。 …...

获取Spring容器Bean工具类

获取Spring容器Bean工具类 1、创建SpringUtils工具类2、注册 SpringUtils工具类3、如果打包的是War方式&#xff0c;可能上面两个注册工具类的方法都没用 1、创建SpringUtils工具类 public class SpringUtils implements ApplicationContextAware {private static Application…...

图面试专题

一、概念 和二叉树的区别&#xff1a;图可能有环 常见概念 顶点&#xff08;Vertex&#xff09;&#xff1a; 图中的节点或点。边&#xff08;Edge&#xff09;&#xff1a; 顶点之间的连接线&#xff0c;描述节点之间的关系。有向图&#xff08;Directed Graph&#xff09;&…...

VUE的计算属性

<!DOCTYPE html> <html> <head> <meta charset"UTF-8" /> <title>计算属性</title> </head> <style> table { border: 1px solid #000; text-align: center; width: 240px; } th,td { border: 1px solid #000; …...

uniapp中使用pageScrollTo让页面滚动到固定节点或距离

uniapp中使用pageScrollTo让页面滚动到固定节点或距离 思路&#xff1a;计算当前节点距离顶部的距离滚动距离然后使用pageScrollTo进行滚动&#xff08;要保证页面加载完成之后在执行&#xff09; #topic" id &#xff1a;页面的节点 changeTop(id) {let query uni.c…...

使用机器学习方法进行分析和处理:对高质量图像进行压缩

使用SVD&#xff08;奇异值分解&#xff09;进行图像压缩与普通压缩工具压缩的主要区别在于压缩原理和压缩效果。 压缩原理&#xff1a; 普通图像压缩工具通常采用有损压缩或无损压缩算法&#xff0c;如JPEG、PNG等&#xff0c;它们主要针对图像的像素进行变换和编码。而SVD图像…...

多线程面试总结

1. 创建线程有哪几种方式 创建线程有三种方式&#xff0c;分别是继承Thread类、实现Runnable接口、实现Callable接口。 通过继承Thread类来创建并启动线程的步骤如下&#xff1a; 定义Thread类的子类&#xff0c;并重写该类的run()方法&#xff0c;该run()方法将作为线程执行…...

android11-隐藏状态栏和导航栏

隐藏导航栏 /android11/frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml diff --git a/frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml b/frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml index ba6b6956f1..6db2348…...

血的教训--kail系统免密centos7的坑【高版本ssh免密低版本ssh的坑】

血的教训–kail系统免密centos7的坑【高版本ssh免密低版本ssh的坑】 最近下载了一个2023版本的kail系统&#xff0c;但是经过几次设置免密后&#xff0c;ssh过去一直让提供密码&#xff0c;所以就仔细的分析了一下&#xff0c;果然还是发现了点猫腻 接上一个博客&#xff0c;大…...

javaagent字节码增强浅尝

概述 javaagent 技术广泛应用于对代码的增强&#xff0c;比如统计方法执行时间、GC 信息打印、分布式链路跟踪等&#xff1b;实现方式包括 javassist 和 bytebuddy&#xff0c;bytebuddy 是对 javassist 的改进&#xff1b;类似于 spring 中的 AOP&#xff1b; Instrumentati…...

计算机组成原理-Cache替换算法

文章目录 总览随机算法&#xff08;RAND&#xff09;先进先出算法&#xff08;FIFO&#xff09;近期最少使用算法&#xff08;LRU&#xff09;最不经常使用算法&#xff08;LFU&#xff09;总结 总览 随机算法&#xff08;RAND&#xff09; 没有选择性地考虑替换哪一块Cache&a…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

CSS3相关知识点

CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...

数据库正常,但后端收不到数据原因及解决

从代码和日志来看&#xff0c;后端SQL查询确实返回了数据&#xff0c;但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离&#xff0c;并且ai辅助开发的时候&#xff0c;很容易出现前后端变量名不一致情况&#xff0c;还不报错&#xff0c;只是单…...