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

RK3568平台(显示篇)DRM vop驱动程序分析

一.设备树配置

vopb: vop@ff900000 {compatible = "rockchip,rk3399-vop-big";reg = <0x0 0xff900000 0x0 0x2000>, <0x0 0xff902000 0x0 0x1000>;interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH 0>;assigned-clocks = <&cru ACLK_VOP0>, <&cru HCLK_VOP0>;assigned-clock-rates = <400000000>, <100000000>;clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;clock-names = "aclk_vop", "dclk_vop", "hclk_vop";iommus = <&vopb_mmu>;power-domains = <&power RK3399_PD_VOPB>;resets = <&cru SRST_A_VOP0>, <&cru SRST_H_VOP0>, <&cru SRST_D_VOP0>;reset-names = "axi", "ahb", "dclk";status = "disabled";vopb_out: port {#address-cells = <1>;#size-cells = <0>;vopb_out_edp: endpoint@0 {reg = <0>;remote-endpoint = <&edp_in_vopb>;};vopb_out_mipi: endpoint@1 {reg = <1>;remote-endpoint = <&mipi_in_vopb>;};vopb_out_hdmi: endpoint@2 {reg = <2>;remote-endpoint = <&hdmi_in_vopb>;};vopb_out_mipi1: endpoint@3 {reg = <3>;remote-endpoint = <&mipi1_in_vopb>;};vopb_out_dp: endpoint@4 {reg = <4>;remote-endpoint = <&dp_in_vopb>;};};
};

vop具体实现文件:

drivers/gpu/drm/rockchip/rockchip_drm_vop.c;
drivers/gpu/drm/rockchip/rockchip_vop_reg.c;
drivers/gpu/drm/rockchip/rockchip_drm_vop.h;
drivers/gpu/drm/rockchip/rockchip_vop_reg.h;

二.驱动分析

const struct component_ops vop_component_ops = {.bind = vop_bind,.unbind = vop_unbind,
};

vop的驱动程序主要是从vop_bind开始,其定义在:drivers/gpu/drm/rockchip/rockchip_drm_vop.c

vop_bind函数涉及到对vop设备节点的解析,咱们以vopb设备节点为例进行分析;

static int vop_bind(struct device *dev, struct device *master, void *data)
{// 1. 获取platform_devicestruct platform_device *pdev = to_platform_device(dev);const struct vop_data *vop_data;struct drm_device *drm_dev = data;struct vop *vop;struct resource *res;int ret, irq;// 2. 得到rk3399_vop_bigvop_data = of_device_get_match_data(dev);if (!vop_data)return -ENODEV;/* Allocate vop struct and its vop_win array,初始化vop win */vop = devm_kzalloc(dev, struct_size(vop, win, vop_data->win_size),GFP_KERNEL);if (!vop)return -ENOMEM;vop->dev = dev;vop->data = vop_data;vop->drm_dev = drm_dev;// 设置驱动数据为vopdev_set_drvdata(dev, vop);// 3. 初始化vop winvop_win_init(vop);// 4. 获取第一个内存资源,即<0x0 0xff900000 0x0 0x2000>; VOP_BIG相关寄存器基地址res = platform_get_resource(pdev, IORESOURCE_MEM, 0);// 将VOP_BIG相关寄存器起始物理地址映射到虚拟地址,并返回虚拟地址vop->regs = devm_ioremap_resource(dev, res);if (IS_ERR(vop->regs))return PTR_ERR(vop->regs);vop->len = resource_size(res);// 5. 获取第二个内存资源,即<0x0 0xff902000 0x0 0x1000>; LUT相关寄存器基地址res = platform_get_resource(pdev, IORESOURCE_MEM, 1);if (res) {if (vop_data->lut_size != 1024 && vop_data->lut_size != 256) {DRM_DEV_ERROR(dev, "unsupported gamma LUT size %d\n", vop_data->lut_size);return -EINVAL;}// LUT相关寄存器起始物理地址映射到虚拟地址,并返回虚拟地址vop->lut_regs = devm_ioremap_resource(dev, res);if (IS_ERR(vop->lut_regs))return PTR_ERR(vop->lut_regs);}vop->regsbak = devm_kzalloc(dev, vop->len, GFP_KERNEL);if (!vop->regsbak)return -ENOMEM;// 6. 获取第1个IRQ编号 interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH 0>;irq = platform_get_irq(pdev, 0);if (irq < 0) {DRM_DEV_ERROR(dev, "cannot find irq for vop\n");return irq;}vop->irq = (unsigned int)irq;// 初始化自旋锁和互斥锁spin_lock_init(&vop->reg_lock);spin_lock_init(&vop->irq_lock);mutex_init(&vop->vop_lock);// 7. 创建crtc对象,并和plane关联在一起ret = vop_create_crtc(vop);if (ret)return ret;// 电源管理相关pm_runtime_enable(&pdev->dev);// 8. vop初始化ret = vop_initial(vop);if (ret < 0) {DRM_DEV_ERROR(&pdev->dev,"cannot initial vop dev - err %d\n", ret);goto err_disable_pm_runtime;}// 9. 申请中断,中断处理函数设置为vop_isrret = devm_request_irq(dev, vop->irq, vop_isr,IRQF_SHARED, dev_name(dev), vop);if (ret)goto err_disable_pm_runtime;// 未设置if (vop->data->feature & VOP_FEATURE_INTERNAL_RGB) {vop->rgb = rockchip_rgb_init(dev, &vop->crtc, vop->drm_dev);if (IS_ERR(vop->rgb)) {ret = PTR_ERR(vop->rgb);goto err_disable_pm_runtime;}}// 10. dma初始化rockchip_drm_dma_init_device(drm_dev, dev);return 0;err_disable_pm_runtime:pm_runtime_disable(&pdev->dev);vop_destroy_crtc(vop);return ret;
}

这里我们以设备节点vopb为例,对这段代码进行分析,主要流程如下:

(1) 调用to_platform_device获取platform device,设备节点为vopb

(2) 调用of_device_get_match_data获取与特定设备匹配的数据,这里获取到的数据为rk3399_vop_big;

(3) 调用vop_win_init初始化vop win

(4) 首先调用platform_get_resource(pdev, IORESOURCE_MEM, 0)获取第一个内存资源,即:

<0x0 0xff900000 0x0 0x2000>

0xff900000VOP_BIG相关寄存器基地址;

接着调用devm_ioremap_resource(dev, res)VOP_BIG相关寄存器起始物理地址映射到虚拟地址,并返回虚拟地址;

(5) 调用platform_get_resource(pdev, IORESOURCE_MEM, 1)获取第二个内存资源,即:

<0x0 0xff902000 0x0 0x1000>

0xff902000LUT相关寄存器基地址;

接着调用devm_ioremap_resource(dev, res)LUT相关寄存器起始物理地址映射到虚拟地址,并返回虚拟地址;

(6) 调用platform_get_irq(pdev, 0) 获取第1个IRQ编号:

 interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH 0>

(7) 调用vop_create_crtc(vop)初始化crtc对象,并和plane关联在一起;

(8) 调用vop_initial(vop)进行vop初始化;

(9) 调用devm_request_irq(dev, vop->irq, vop_isr, IRQF_SHARED, dev_name(dev), vop)申请中断,中断处理函数设置为vop_isr

(10) 调用rockchip_drm_dma_init_device(drm_dev, dev)进行dma相关的初始化工作;

vop_bind函数里面比较重要的几个函数:

vo_win_init用于初始化vop win,那么什么是vop win,指定就是vop图层。

vop_create_crtc用于初始化crtc对象,crtcFramebuffer中读取待显示的图像。

vop_initial用户vop初始化。

vo_win_init:初始化vop win。

/** Initialize the vop->win array elements.*/
static void vop_win_init(struct vop *vop)
{const struct vop_data *vop_data = vop->data;unsigned int i;// 遍历每一个图层for (i = 0; i < vop_data->win_size; i++) {// 获取第i个vop winstruct vop_win *vop_win = &vop->win[i];// 获取第i个vop win配置相关寄存器信息const struct vop_win_data *win_data = &vop_data->win[i];// 初始化成员vop_win->data = win_data;vop_win->vop = vop;// rk3399定义了win_yuv2yuv,因此初始化yuv2yuv_dataif (vop_data->win_yuv2yuv)vop_win->yuv2yuv_data = &vop_data->win_yuv2yuv[i];}
}

vop_create_crtc:用于初始化crtc对象。

static int vop_create_crtc(struct vop *vop)
{// 获取vop dataconst struct vop_data *vop_data = vop->data;// 获取device,对应的设备节点为vopbstruct device *dev = vop->dev;// 获取drm devicestruct drm_device *drm_dev = vop->drm_dev;struct drm_plane *primary = NULL, *cursor = NULL, *plane, *tmp;// 获取drm crtcstruct drm_crtc *crtc = &vop->crtc;struct device_node *port;int ret;int i;/** Create drm_plane for primary and cursor planes first, since we need* to pass them to drm_crtc_init_with_planes, which sets the* "possible_crtcs" to the newly initialized crtc.         * 1. 遍历每一个vop win,每个vop win内部包含一个drm_plane,对类型为primary和cursor plane* 进行初始化*/for (i = 0; i < vop_data->win_size; i++) {// 获取第i个vop winstruct vop_win *vop_win = &vop->win[i];// 获取第i个vop win dataconst struct vop_win_data *win_data = vop_win->data;// 只处理primary和cursor planeif (win_data->type != DRM_PLANE_TYPE_PRIMARY &&win_data->type != DRM_PLANE_TYPE_CURSOR)continue;// 进行plane的初始化,其中funcs被设置为vop_plane_funcsret = drm_universal_plane_init(vop->drm_dev,    // drm设备&vop_win->base,  // 要初始化的plane对象0,  // 可能的CRTCs的位掩码&vop_plane_funcs,  // plane的控制函数集合win_data->phy->data_formats,  // 支持的格式数组(DRM_FORMAT_*)win_data->phy->nformats,   // formats数组的长度win_data->phy->format_modifiers, win_data->type, // plane的类型NULL);if (ret) {DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n",ret);goto err_cleanup_planes;}// 获取当前planeplane = &vop_win->base;// 设置plane的辅助函数helper_private为plane_helper_funcsdrm_plane_helper_add(plane, &plane_helper_funcs);// 如果vop win data配置了x_mir_en/y_mir_en,则调用drm_plane_create_rotation_property为plane附加rotation propertyvop_plane_add_properties(plane, win_data);// 保存primary planeif (plane->type == DRM_PLANE_TYPE_PRIMARY)primary = plane;// 保存cursor planeelse if (plane->type == DRM_PLANE_TYPE_CURSOR)cursor = plane;}// 2. 使用指定的primary and cursor planes初始化的crtc对象,其中crtc回调函数funcs设置为vop_crtc_funcsret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,&vop_crtc_funcs, NULL);if (ret)goto err_cleanup_planes;// 3. 设置crtc的辅助函数helper_private为vop_crtc_helper_funcsdrm_crtc_helper_add(crtc, &vop_crtc_helper_funcs);// 进入if (vop->lut_regs) {drm_mode_crtc_set_gamma_size(crtc, vop_data->lut_size);drm_crtc_enable_color_mgmt(crtc, 0, false, vop_data->lut_size);}/** Create drm_planes for overlay windows with possible_crtcs restricted* to the newly created crtc.* 4. 遍历每一个vop win,每个vop win内部包含一个drm_plane,对类型为overlay plane* 进行初始化*/for (i = 0; i < vop_data->win_size; i++) {// 获取第i个vop winstruct vop_win *vop_win = &vop->win[i];// 获取第i个vop win dataconst struct vop_win_data *win_data = vop_win->data;unsigned long possible_crtcs = drm_crtc_mask(crtc);// 只处理overlay planeif (win_data->type != DRM_PLANE_TYPE_OVERLAY)continue;// 进行plane的初始化,其中funcs被设置为vop_plane_funcsret = drm_universal_plane_init(vop->drm_dev, &vop_win->base,possible_crtcs,&vop_plane_funcs,win_data->phy->data_formats,win_data->phy->nformats,win_data->phy->format_modifiers,win_data->type, NULL);if (ret) {DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n",ret);goto err_cleanup_crtc;}// 设置plane的辅助函数helper_private为plane_helper_funcsdrm_plane_helper_add(&vop_win->base, &plane_helper_funcs);// 如果vop win data配置了x_mir_en/y_mir_en,则调用drm_plane_create_rotation_property为plane附加rotation propertyvop_plane_add_properties(&vop_win->base, win_data);}// 5. 从vopb节点的子节点列表中查找名为port的子节点,也就是vopb_out节点port = of_get_child_by_name(dev->of_node, "port");if (!port) {DRM_DEV_ERROR(vop->dev, "no port node found in %pOF\n",dev->of_node);ret = -ENOENT;goto err_cleanup_crtc;}// 6. 初始化工作队列drm_flip_work_init(&vop->fb_unref_work, "fb_unref",vop_fb_unref_worker);// 初始化完成量,init_completion(&vop->dsp_hold_completion);init_completion(&vop->line_flag_completion);// 设置port节点crtc->port = port;// 7. 对crtc进行自刷新相关的辅助函数初始化ret = drm_self_refresh_helper_init(crtc);if (ret)DRM_DEV_DEBUG_KMS(vop->dev,"Failed to init %s with SR helpers %d, ignoring\n",crtc->name, ret);return 0;err_cleanup_crtc:drm_crtc_cleanup(crtc);
err_cleanup_planes:list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list,head)drm_plane_cleanup(plane);return ret;err_cleanup_crtc:drm_crtc_cleanup(crtc);
err_cleanup_planes:list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list,head)drm_plane_cleanup(plane);return ret;
}

(1) 遍历每一个vop win,每个vop win内部包含一个drm_plane,对类型为primarycursor plane进行初始化;具体是调用drm_universal_plane_init来初始化drm_plane,并且添加plane辅助函数、设置属性等;其中funcs被设置为vop_plane_funcs,定义在drivers/gpu/drm/rockchip/rockchip_drm_vop.c

static const struct drm_plane_funcs vop_plane_funcs = {.update_plane   = drm_atomic_helper_update_plane,.disable_plane  = drm_atomic_helper_disable_plane,.destroy = vop_plane_destroy,.reset = drm_atomic_helper_plane_reset,.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,.format_mod_supported = rockchip_mod_supported,
};

(2) 调用drm_crtc_init_with_planes使用指定的primary and cursor planes初始化的crtc对象,其中crtc回调函数funcs设置为vop_crtc_funcs,定义在drivers/gpu/drm/rockchip/rockchip_drm_vop.c

static const struct drm_crtc_funcs vop_crtc_funcs = {.set_config = drm_atomic_helper_set_config,.page_flip = drm_atomic_helper_page_flip,.destroy = vop_crtc_destroy,.reset = vop_crtc_reset,.atomic_duplicate_state = vop_crtc_duplicate_state,.atomic_destroy_state = vop_crtc_destroy_state,.enable_vblank = vop_crtc_enable_vblank,.disable_vblank = vop_crtc_disable_vblank,.set_crc_source = vop_crtc_set_crc_source,.verify_crc_source = vop_crtc_verify_crc_source,
};

(3) 调用drm_crtc_helper_add设置crtc的辅助函数helper_privatevop_crtc_helper_funcs,定义在drivers/gpu/drm/rockchip/rockchip_drm_vop.c

static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {.mode_fixup = vop_crtc_mode_fixup,.atomic_check = vop_crtc_atomic_check,.atomic_begin = vop_crtc_atomic_begin,.atomic_flush = vop_crtc_atomic_flush,.atomic_enable = vop_crtc_atomic_enable,.atomic_disable = vop_crtc_atomic_disable,
};

(4) 遍历每一个vop win,每个vop win内部包含一个drm_plane,对类型为overlay plane进行初始化;

(5) 调用of_get_child_by_namevopb节点的子节点列表中查找名为port的子节点,也就是vopb_out节点;

(6) 调用drm_flip_work_init(&vop->fb_unref_work, "fb_unref",vop_fb_unref_worker)初始化工作队列;

vop_initial

vop_initial用户vop初始化,定义在drivers/gpu/drm/rockchip/rockchip_drm_vop.c

static int vop_initial(struct vop *vop)
{struct reset_control *ahb_rst;int i, ret;// 根据时钟名称hclk_vop获取时钟,设备节点属性clock-names、clocks,指定了名字为hclk_vop对应的时钟为<&cru HCLK_VOP0>vop->hclk = devm_clk_get(vop->dev, "hclk_vop");if (IS_ERR(vop->hclk)) {DRM_DEV_ERROR(vop->dev, "failed to get hclk source\n");return PTR_ERR(vop->hclk);}// 根据时钟名称aclk_vop获取时钟,设备节点属性clock-names、clocks,指定了名字为aclk_vop对应的时钟为<&cru ACLK_VOP0>vop->aclk = devm_clk_get(vop->dev, "aclk_vop");if (IS_ERR(vop->aclk)) {DRM_DEV_ERROR(vop->dev, "failed to get aclk source\n");return PTR_ERR(vop->aclk);}// 根据时钟名称dclk_vop获取时钟,设备节点属性clock-names、clocks,指定了名字为dclk_vop对应的时钟为<&cru DCLK_VOP0>vop->dclk = devm_clk_get(vop->dev, "dclk_vop");if (IS_ERR(vop->dclk)) {DRM_DEV_ERROR(vop->dev, "failed to get dclk source\n");return PTR_ERR(vop->dclk);}// 电源相关,,使能设备的runtime pm功能 暂且忽略ret = pm_runtime_resume_and_get(vop->dev);if (ret < 0) {DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret);return ret;}// dclk时钟准备,使其处于可用状态,但不启用它ret = clk_prepare(vop->dclk);if (ret < 0) {DRM_DEV_ERROR(vop->dev, "failed to prepare dclk\n");goto err_put_pm_runtime;}/* Enable both the hclk and aclk to setup the vop,hclk时钟准备和使能 */ret = clk_prepare_enable(vop->hclk);if (ret < 0) {DRM_DEV_ERROR(vop->dev, "failed to prepare/enable hclk\n");goto err_unprepare_dclk;}// aclk时钟准备和使能ret = clk_prepare_enable(vop->aclk);if (ret < 0) {DRM_DEV_ERROR(vop->dev, "failed to prepare/enable aclk\n");goto err_disable_hclk;}/** do hclk_reset, reset all vop registers. 获取ahb相应的reset句柄*/ahb_rst = devm_reset_control_get(vop->dev, "ahb");if (IS_ERR(ahb_rst)) {DRM_DEV_ERROR(vop->dev, "failed to get ahb reset\n");ret = PTR_ERR(ahb_rst);goto err_disable_aclk;}// 对传入的reset资源进行复位操作reset_control_assert(ahb_rst);// 睡眠,单位为微妙usleep_range(10, 20);// 对传入的reset资源进行解复位操作reset_control_deassert(ahb_rst);// 设置rk3399_vop_big.intr.clear所描述寄存器相应位的值VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1);       // 设置rk3399_vop_big.intr.enable所描述寄存器相应位的值VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0);// 备份vop相关寄存器的值for (i = 0; i < vop->len; i += sizeof(u32))vop->regsbak[i / 4] = readl_relaxed(vop->regs + i);// 设置rk3399_vop_big.misc.global_regdone_en所描述寄存器相应位的值VOP_REG_SET(vop, misc, global_regdone_en, 1);// 设置rk3399_vop_big.common.dsp_blank所描述寄存器相应位的值VOP_REG_SET(vop, common, dsp_blank, 0);// 遍历每一个vop winfor (i = 0; i < vop->data->win_size; i++) {// 获取第i个vop winstruct vop_win *vop_win = &vop->win[i];// 获取第i个vop win dataconst struct vop_win_data *win = vop_win->data;int channel = i * 2 + 1;// 设置rk3399_vop_big.win[i].phy.channel所描述寄存器相应位的值VOP_WIN_SET(vop, win, channel, (channel + 1) << 4 | channel);// 禁止当前vop winvop_win_disable(vop, vop_win);// 设置rk3399_vop_big.win[i].phy.gate所描述寄存器相应位的值VOP_WIN_SET(vop, win, gate, 1);}// 设置rk3399_vop_big.common.cfg_done所描述寄存器相应位的值,enable reg configvop_cfg_done(vop);/** do dclk_reset, let all config take affect. 获取dclk相应的reset句柄*/vop->dclk_rst = devm_reset_control_get(vop->dev, "dclk");if (IS_ERR(vop->dclk_rst)) {DRM_DEV_ERROR(vop->dev, "failed to get dclk reset\n");ret = PTR_ERR(vop->dclk_rst);goto err_disable_aclk;}// 对传入的reset资源进行复位操作reset_control_assert(vop->dclk_rst);// 睡眠,单位为微妙usleep_range(10, 20);// 对传入的reset资源进行解复位操作reset_control_deassert(vop->dclk_rst);// 禁止时钟hclkclk_disable(vop->hclk);// 禁止时钟aclkclk_disable(vop->aclk);// 使能标志位vop->is_enabled = false;pm_runtime_put_sync(vop->dev);return 0;err_disable_aclk:clk_disable_unprepare(vop->aclk);
err_disable_hclk:clk_disable_unprepare(vop->hclk);
err_unprepare_dclk:clk_unprepare(vop->dclk);
err_put_pm_runtime:pm_runtime_put_sync(vop->dev);return ret;
}

该函数主要做了两件事件:

  • vop相关时钟初始化:aclk_vopdclk_vophclk_vop
  • vop相关寄存器配置,底层通过vop_reg_set设置配置寄存器值;

相关文章:

RK3568平台(显示篇)DRM vop驱动程序分析

一.设备树配置 vopb: vopff900000 {compatible "rockchip,rk3399-vop-big";reg <0x0 0xff900000 0x0 0x2000>, <0x0 0xff902000 0x0 0x1000>;interrupts <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH 0>;assigned-clocks <&cru ACLK_VOP0>, &…...

vue3 动态加载组件

//模版调用 <component :is"geticon(item.icon)" />//引入 import { ref, onMounted, markRaw, defineAsyncComponent } from vue;//异步添加icon图标组建 function geticon(params) {const modules import.meta.glob(../components/icons/*.vue);const link …...

Latex on overleaf入门语法

Latex on overleaf入门语法 前言基本结构序言 简单的格式化命令添加注释&#xff1a;%加粗、斜体、下划线有序列表、无序列表 添加图片图片的标题、标签和引用 添加表格一个简单的表格为表格添加边框标题、标签、引用 数学表达式基本的数学命令 基本格式摘要段落、新行章节、分…...

使用Echarts来实现数据可视化

目录 一.什么是ECharts? 二.如何使用Springboot来从后端给Echarts返回响应的数据&#xff1f; eg:折线图&#xff1a; ①Controller层&#xff1a; ②service层&#xff1a; 一.什么是ECharts? ECharts是一款基于JavaScript的数据可视化图标库&#xff0c;提供直观&…...

一文搞懂GIT

文章目录 1. GiT概述1.1 GIT概述1.2 GIT安装 2. GIT组成3. GIT基本命令3.1 基本命令3.2 分支操作3.3 远程操作3.4 标签操作3.5 其他命令 1. GiT概述 1.1 GIT概述 Git 是一个分布式版本控制系统&#xff0c;被广泛应用于软件开发中。 Git 具有众多优点&#xff0c;比如&#…...

jQuery入门(四)案例

jQuery 操作入门案例 一、复选框案例 功能: 列表的全选&#xff0c;反选&#xff0c;全不选功能实现。 实现步骤和分析&#xff1a; - 全选 1. 为全选按钮绑定单击事件。 2. 获取所有的商品项复选框元素&#xff0c;为其添加 checked 属性&#xff0c;属性值为 true。 -…...

揭秘MITM攻击:原理、手法与防范措施

中间人攻击发生时&#xff0c;攻击者会在通讯两端之间插入自己&#xff0c;成为通信链路的一部分。攻击者可以拦截、查看、修改甚至重新定向受害者之间的通信数据&#xff0c;而不被双方察觉。这种攻击常见于未加密的Wi-Fi网络、不安全的HTTP连接或者通过社会工程学手段诱导受害…...

【YOLOv8】一文全解+亮点介绍+训练教程+独家魔改优化技巧

前言 Hello&#xff0c;大家好&#xff0c;我是cv君&#xff0c;最近开始在空闲之余&#xff0c;经常更新文章啦&#xff01;除目标检测、分类、分隔、姿态估计等任务外&#xff0c;还会涵盖图像增强领域&#xff0c;如超分辨率、画质增强、降噪、夜视增强、去雾去雨、ISP、海…...

创建mvp ubo(uniform buffer object)

创建过程&#xff1a; 创建一个uniform buffer查找buffer memory requirements分配、绑定buffer memorymap buffer memory拷贝mvp data to buffer memoryunmap buffer memory 示例代码&#xff1a; glm::mat4 projection glm::perspective(glm::radians(45.0f), 1.0f, 0.1f…...

1.GPIO

理论说明 输入 上拉输入&#xff1a;拉高电平 下拉输入&#xff1a;拉低电平 浮空输入&#xff1a;不拉高也不拉低电平 输出 开漏输出&#xff1a;不能输出高电平&#xff08;P-MOS不可用&#xff0c;则只能低电平&#xff09; 推挽输出&#xff1a;可输出高低电平 输出速率…...

C++必修:STL之vector的了解与使用

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 贝蒂的主页&#xff1a;Betty’s blog 1. C/C中的数组 1.1. C语言中的数组 在 C 语言中&#xff0c;数组是一组相同类型…...

【MySQL】索引 【上】 {没有索引的查询/磁盘/mysql与磁盘IO/初识索引}

文章目录 1.没有索引存在的问题2. 认识磁盘MySQL与存储MySQL与磁盘交互基本单位建立共识图解IO认识索引 在关系数据库中&#xff0c;索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构&#xff0c;它是某个表中一列或若干列值的集合和相应的指向表中物…...

GO goroutine状态流转

Gidle -> Grunnable newproc获取新的goroutine&#xff0c;并放置到P运行队列中 这也是go关键字之后实际编译调用的方法 func newproc(fn *funcval) {// 获取当前正在运行中的goroutinegp : getg()// 获取调用者的程序计数器地址&#xff0c;用于调试和跟踪pc : getcallerp…...

DLMS/COSEM中的信息安全:DLMS/COSEM安全概念(上)

DLMS/COSEM中的信息安全描述并规定: ——DLMS/COSEM安全概念; ——选择加密算法; ——安全密钥; ——使用加密算法进行实体认证、xDLMS APDU保护和COSEM数据保护。 1.综述 DLMS/COSEM服务器的资源(COSEM对象属性和方法)可以由在应用连接内的DLMS/COSEM客户机访问。 在AA…...

C语言第九天笔记

数组的概念 什 么是数组 数组是 相同类型&#xff0c; 有序数据的集合。 数 组的特征 数组中的数据被称为数组的 元素&#xff0c;是同构的 数组中的元素存放在内存空间里 (char player_name[6]&#xff1a;申请在内存中开辟6块连续的基于char类 型的变量空间) 衍生概念&…...

智慧环卫可视化:科技赋能城市清洁管理

图扑智慧环卫可视化通过实时监控、数据分析和智能调度&#xff0c;提高环卫作业效率&#xff0c;优化资源配置&#xff0c;提升城市清洁水平&#xff0c;实现城市管理的精细化和现代化。...

【力扣】SQL题库练习5

高级查询和连接 1341.电影评分 表&#xff1a;Movies ------------------------ | Column Name | Type | ------------------------ | movie_id | int | | title | varchar | ------------------------ movie_id 是这个表的主键(具有唯一值的列)。 ti…...

永结无间Ⅸ--你不需要LLM Agent

人们将目光锁定在下一个闪亮的事物上。FOMO 是人性的一部分。这也适用于企业。就像数据科学成为每个企业分析功能的热潮一样&#xff0c;Agentic Architecture 是大多数 AI 雷达上的热门目标。 但您是否考虑过您是否真的需要它&#xff1f; 实际情况是&#xff0c;您不需要 A…...

Simulink|基于粒子群算法的永磁同步电机多参数辨识

目录 主要内容 模型研究 结果一览 下载链接 主要内容 仿真程序参考文献《改进粒子群算法的永磁同步电机多参数辨识》&#xff0c;采用粒子群算法与simulink模型结合的方式&#xff0c;对永磁同步电机进行多参数辨识。程序以定子绕组电阻、d轴电感、q轴电感和永磁…...

程序如何自动点击亚马逊商户后台的“邀请评论”按钮

要在亚马逊上自动点击“邀请评论”按钮&#xff0c;可以使用自动化脚本来实现。由于你希望自动化操作&#xff0c;我提供一个示例代码&#xff0c;使用 Selenium WebDriver 来执行这个任务。Selenium 是一个流行的浏览器自动化工具&#xff0c;能够模拟用户操作&#xff0c;例如…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

rknn toolkit2搭建和推理

安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...