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

多核异构核间通信-mailbox/RPMsg 介绍及实验

1. 多核异构核间通信

由于MP157是一款多核异构的芯片,其中既包含的高性能的A7核及实时性强的M4内核,那么这两种处理器在工作时,怎么互相协调配合呢? 这就涉及到了核间通信的概念了。

IPCC (inter-processor communication controller)用于处理器间的数据交换的通知。 它提供了一种非阻塞的信号机制,并提供原子的方式进行信号发布和信息检索。 注意,核间通信的共享内存缓冲区是在MCU的SRAM中分配的,它不是IPCC外设的一部分。

1.1. 外设简述

IPCC外设提供了硬件支持,来管理两个处理器实例之间的处理器间通信。每个处理器拥有特定的寄存器区域和中断。 有点像硬件信号量的功能。

IPCC提供了六个双向通道信号。每个通道分为两个子通道,每个子通道提供从“发送方”处理器到“接收方”处理器的单向信号:

  • P1_TO_P2子通道(从P1发到P2)

  • P2_TO_P1子通道(从P2发到P1)

子通道中包括如下功能:

  • 一个标志位,用于标识通道正在被占用和空闲的两种状态,这个标志被“发送方”处理器设置为被占用,并被“接收方”处理器清除。

  • 两个相关的中断(所有通道都共享):

    • RXO: RX通道被占用,连接到“接收器”处理器。

    • TXF: TX通道空闲,连接到“发送”处理器。

  • 带多路复用的中断掩码功能。

IPCC支持以下信道的操作模式:

  • 单工通信方式:

    • 仅使用一个子信道。

    • 单向消息:“发送者”处理器将通信数据发布到内存中后,它将通道状态标志设置为已占用。当消息被处理时,“接收者”处理器清除该标志。

  • 半双工通讯方式:

    • 仅使用一个子信道。

    • 双向消息:“发送者”处理器将通信数据发布到内存中后,它将通道状态标志设置为已占用。当消息被处理并且响应在共享内存中可用时,“接收器”处理器将清除该标志。

  • 全双工通讯方式:

    • 子通道用于异步模式。

    • 通过将子通道状态标志设置为占用,任何处理器都可以异步发布消息。当消息被处理时,“接收者”处理器清除该标志。可以将这种模式视为给定通道上两个单工模式的组合。

核间通信的模型如下:

1.2. 框架简述

IPCC作为核间通信的桥梁,它仅承担着通知的角色,负责消息的分发、中断的处理等。

实际上,IPCC外设这个角色只是多核异构核间通信中的一块,在我们使用多核异构核间通信时,往往不仅希望使用到核间的消息通知,还希望能在不同的核心中进行数据的交互(比如M4核进行实时的AD数据采集处理,完成后,M4核可通过异构的框架将数据呈递给A7核,A7核再进行更复杂的应用)。那么在这个需求的驱动下,就出现了一些框架相互配合使用的情况了,下面我们就给大家介绍这些内核框架。

1.2.1. RemoteProc framework

远程处理器框架(RPROC、RemoteProc)允许不同的平台/体系结构控制(打开电源,加载固件,关闭电源)远程处理器,同时抽象出硬件差异。此外,它还提供监视和调试远程协处理器的服务。

以MP157为例,其RemoteProc可分为两块,分别是A7核端、M4核端:

remoteproc:这是远程处理器框架的通用部分(在MP157中为A7核端)。

它的作用是:

  • 将ELF固件加载到远程处理器内存中。

  • 解析固件资源表以设置关联的资源(例如IPC,内存分割和跟踪)。

  • 控制远程处理器的执行(启动,停止…)。

  • 提供监视和调试远程固件的服务。

stm32_rproc:这是远程处理器平台驱动程序(在MP157中为M4核端)。

它的作用是:

  • 将stm32特定的功能(回调)注册到RPROC框架。

  • 处理与远程处理器关联的平台资源(例如寄存器,看门狗,复位,时钟和存储器)。

  • 通过邮箱框架将通知(通知)转发到远程处理器。

ST官方参考资料:

Linux RPMsg framework overview - stm32mpu

1.2.2. RPMsg framework

此小节为大家简述有关Linux RPMsg框架的内容。RPMsg框架是一个基于virtio的消息总线,它允许本地处理器与系统上可用的远程处理器通信。

此框架在多核异构中承担的角色如下图:

Linux RPMsg框架是在virtio框架顶层上实现的消息传送框架,其用于主机和远程处理器进行通信。它基于virtio vring,可通过共享内存向远程CPU发送消息或从远程CPU接收消息。

这些vring是单向的,一个vring专用于发送到远程处理器的消息,另一个vring用于从远程处理器接收的消息。此外,共享缓冲区需要在两个处理器都可见的内存空间中创建。

当新消息在共享缓冲区中等待时,会使用到另一个框架 Linux Mailbox framework ,该框架将用于通知对应的Core。

依靠这些框架,RPMsg框架实现了基于不同通道的通信。通道可被文本名称标识,并有一个本地(“源”)的RPMsg地址和一个远程(“目的”)的RPMsg地址。

在远程处理器端(MP157则为M4核),也必须使用RPMSG框架。RPMSG框架的实现存在几种解决方案,ST建议使用OpenAMP方案,并在SDK中给出了示例。

Github OpenAMP框架 .

简单来说,MP157的A7核与M4核,通过一个标准的RPMsg框架来建立起联系,完成数据传递。

具体原理可以参考:

RPMsg-Messaging-Protocol .

RPMsg-Communication-Flow .

Linux内核源码目录给出的rpmsg client的示例代码位置如下:

samples/rpmsg/rpmsg_client_sample.c

rpmsg框架Linux内核驱动源码位于:

drivers/rpmsg

ST官方参考资料:

Linux remoteproc framework overview - stm32mpu

1.2.3. Mailbox framework

此小节为大家简述有关Linux邮箱框架的内容。邮箱框架涉及异构多核系统的处理器间通信。

此框架的结构如下图:

邮箱框架被用于内核间进行消息或信号的交换,常用于主机和协处理器间。邮箱由以下模块组成:

  • 一个邮箱控制器(mailbox controller),依赖于硬件平台实现,比如MP157的IPCC外设:

    • 它负责配置和处理来自IPCC外围设备的IRQ。

    • 它为邮箱客户端提供了通用API。

  • 一个邮箱客户端(mailbox client),负责发送或接收消息。

关于此框架的权威描述,在内核文档中的如下目录:

Documentation/mailbox.txt

一般而言mailbox controller和client都由芯片厂商来负责实现,因为这依赖于外设。 我们更常关注的,则是mailbox client的创建和使用。

ST实现的mailbox client代码位置如下:

drivers/remoteproc/stm32_rproc.c

在内核中还给出了一份mailbox client的示例驱动代码, 代码通过debugfs子系统,将mailbox的操作暴露给了用户空间, 用户可以直接通过debugfs来使用mailbox,进行消息在不同内核中的传递。

mailbox框架的设备树描述可参考内核源码文档:

Documentation/devicetree/bindings/mailbox/mailbox.txt

一个简单的mailbox client设备树节点,可以参考内核源码目录:

Documentation/devicetree/bindings/mailbox/sti-mailbox.txt

内核源码目录给出的mailbox client的示例代码位置如下:

drivers/mailbox/mailbox-test.c

ST官方参考资料:

Linux Mailbox framework overview - stm32mpu

1.2.4. 框架小结

前面介绍了三个框架,它们并不是独立工作的,而是相互协调的,彼此关联。 我们可以通过两张图来查看它们之间的关系。

以RemoteProc框架为主视角出发:

可以理清三个框架的关系,RemoteProc可以说是骨架,关联到了RPMsg框架、Mailbox框架。

1.3. 设备树插件描述

1.3.1. IPCC设备树节点

设备树节点位于arch/arm/boot/dts/stm32mp157c.dtsi

IPCC设备树节点

 123456789
10
11
12
13
14
15
ipcc: mailbox@4c001000 {compatible = "st,stm32mp1-ipcc";#mbox-cells = <1>;reg = <0x4c001000 0x400>;st,proc-id = <0>;interrupts-extended =<&intc GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,<&intc GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,<&exti 61 1>;interrupt-names = "rx", "tx", "wakeup";clocks = <&rcc IPCC>;wakeup-source;power-domains = <&pd_core>;status = "disabled";
};

使用节点位于arch/arm/boot/dts/stm32mp157a-basic.dts

使用IPCC设备树节点

1
2
3
&ipcc {status = "okay";
};

设备树中的compatible = “st,stm32mp1-ipcc”属性,会匹配到 drivers/mailbox/stm32-ipcc.c 驱动程序,驱动程序中会创建一个mbox controller。

1.3.2. A7<–>M4 rproc设备树节点

设备树节点位于arch/arm/boot/dts/stm32mp157c.dtsi

rproc设备树节点

 123456789
10
11
12
13
14
15
16
17
18
19
20
21
m4_rproc: m4@0 {compatible = "st,stm32mp1-rproc";#address-cells = <1>;#size-cells = <1>;ranges = <0x00000000 0x38000000 0x10000>,<0x30000000 0x30000000 0x60000>,<0x10000000 0x10000000 0x60000>;resets = <&rcc MCU_R>;reset-names = "mcu_rst";st,syscfg-pdds = <&pwr 0x014 0x1>;st,syscfg-holdboot = <&rcc 0x10C 0x1>;st,syscfg-tz = <&rcc 0x000 0x1>;st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>;status = "disabled";m4_system_resources {compatible = "rproc-srm-core";status = "disabled";};
};

使用节点位于arch/arm/boot/dts/stm32mp157a-basic.dts

使用rproc设备树节点

 123456789
10
11
12
&m4_rproc {memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,<&vdev0vring1>, <&vdev0buffer>;mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;mbox-names = "vq0", "vq1", "shutdown";interrupt-parent = <&exti>;interrupts = <68 1>;interrupt-names = "wdg";wakeup-source;recovery;status = "okay";
};

设备树中的compatible = “st,stm32mp1-rproc”属性,会匹配到 drivers/remoteproc/stm32_rproc.c 驱动程序,驱动程序中会创建一个mbox client,并基于RemoteProc、RPMsg框架与mbox client进行关联。

1.4. 实验代码简述

这里我们就简单讲解一下M4核端的代码和一些概念,更详细的内容则需大家自己研究了。

rpmsg框架下有通信端点的概念,数据在两个端点间传输。端点间的数据传输是rpmsg框架下数据传输最原始的形式, 我们可以在原始的数据传输形式上再做一层封装,抽象出一些特定类型的设备。

每个端点注册的底层实现,就是一个内核设备的注册(使用的是平台总线模型),故注册的端点设备, 可以利用到驱动的Probe功能(具体实现详见 drivers/rpmsg/rpmsg_core.c 300行后内容)。

在M4端,通过调用openamp库中的 OPENAMP_create_endpoint 函数,并在调用时指定参数name(即为设备名称), 即可在内核中注册一个对应的rpmsg框架平台设备,该设备最终可以通过name(设备名称)来匹配到相应的A7端内核驱动:

所以Linux rpmsg框架下使用平台总线模型与端点通讯的方式结合,给一些需要有特殊操作的自定设备, 提供了支持的可能。比如异构间的通讯,可以封装成串口通讯模型。

在我们提供的M4内核固件的代码中,注册了两种Linux内核自带的rpmsg框架下, 原生支持的设备模型,这两种设备类型是rpmsg-tty-channel、rpmsg-client-sample:

  • rpmsg-tty-channel: tty终端设备,对应内核驱动源码 drivers/rpmsg/rpmsg_tty.c,此驱动模块默认被编译进内核。

  • rpmsg-client-sample: 框架原生的通讯方式测试设备(放在内核里作为演示该框架的Demo提供的),对应内核驱动源码 samples/rpmsg/rpmsg_client_sample.c,此驱动默认被编译成模块, 并放置在文件系统 /lib/modules/4.19.94-stm-r1/kernel/samples/rpmsg/rpmsg_client_sample.ko 中, 当设备与驱动发生匹配时,系统会自动insmod该驱动模块。

  • 还有一种字符设备模型,rpmsg_chrdev,源码位于 drivers/rpmsg/rpmsg_char.c ,我们的代码中未实验,可自行研究。

M4核的代码中,创建上述两个rpmsg设备的代码如下:

  • rpmsg-client:rpmsg-client设备的示例,使用的是rpmsg框架下原生的异构通讯方式,调用openamp的原生操作函数,比如OPENAMP_send、receive等即可通讯。 在注册设备时,传入的 RPMSG_SERVICE_NAME 即为 rpmsg-client-sample ,故会在Linux系统中注册一个名为rpmsg-client-sample的设备, 并且会自动匹配对应名称的内核模块(前面有述)。

  • rpmsg-tty:rpmsg-tty的示例,则在原生的通讯方式上,注册成了tty设备的模型,并将rpmsg的通讯封装成了tty的通讯形式, 更符合串口通信的操作、方便使用,比如在M4核端,就有VIRT_UART_Transmit的串口发送函数, rpmsg-tty设备注册的设备文件,会映射到A7核端的Linux文件系统下的 /dev/ttyRPMSGx 。

在M4核的代码中,还初始化了usart3作为M4内核的Log输出串口,我们可以通过串口模块接入开发板上的usart3,来查看M4内核输出的Log。 最终工程代码会被用于生成ELF固件,ELF固件即为程序,会运行在MP157的M4内核上。

综上,通过原生的rpmsg框架设备、 /dev/ttyRPMSGx 节点以及M4内核使用的usart3资源,我们就可以进行简单的实验了。 本实验的代码也比较简单,这里就讲解这么多。

1.5. 实验准备

由于多核异构的框架是与处理器的架构紧密联系在一起的,所以一般这些框架驱动会由芯片厂商为我们提供好。 野火MP157开发板默认开启了这些驱动支持,并且开启了对应的设备树,我们直接进行使用就可以了。

在前面我们提到了,M4内核要与A7内核通讯需要共用一个框架,那么M4内核的运行的程序里, 就需要有对应的框架代码,这个为大家提供的工程中已经包含。 最终我们将代码生成的ELF固件,通过A7内核的remoteproc子系统加载到M4内核上, 即可做好前期的准备工作。

生成ELF固件的工程代码位于 \linux_driver\framework_ipcc\STM32Cube_FW_MP1_V1.2.0\Projects\STM32MP157C-EV1\Applications\OpenAMP\OpenAMP_raw 目录下, 感兴趣可自行研究,工程可用MDK或CubeIDE打开(在工程目录中由对应文件夹)。

MP157-M4内核的使用可参考:

[野火]Cortex-M4内核开发实战指南-基于STM32MP157

重要

在M4核的代码中,还初始化了usart3,实验前请务必将usart3的设备树插件关闭。

1.6. 实验操作

M4核的固件我们已经成功编译并放在了/linux_driver/framework_ipcc目录下, 我们将M4核的固件 OpenAMP_raw_CM4.elf 上传至Linux文件系统的 /lib/firmware/ 目录。此目录存放着Linux系统中会使用到的各种固件。

执行如下命令指定M4内核加载的固件,默认在root用户下操作:

# 进入remoteproc子系统目录
cd /sys/class/remoteproc/remoteproc0
# 导入M4内核固件名称
echo OpenAMP_raw_CM4.elf > firmware

在同一目录下,执行如下命令可启动停止M4内核:

# 启动M4内核
echo start > state
# 停止M4内核
echo stop > state

启动M4内核后信息如下:

M4内核加载固件并启动后,在串口终端中打印出了一些信息,我们通过串口模块接入usart3引脚, 再打开串口调试助手设置波特率为115200,可以看到M4固件初始化的usart3作为串口printf出来的信息, 为 [INFO ]M4 send to A7 : hello world! , 并且A7端的驱动也打印出了 rpmsg_client_sample virtio0.rpmsg-client-sample.-1.0: incoming msg 1 (src: 0x0) 说明M4核及A7核驱动正常工作了。

此外,输入lsmod,我们还可以看到演示设备创建后,对应被动态加载的驱动模块, rpmsg_client_sample :

下面,我们进行第二个设备测试,通过前面现象中的LOG,我们可以看到被枚举出的tty设备节点 /dev/ttyRPMSG0 节点, 我们就通过该节点测试tty设备的功能,输入如下命令:

echo "hello M4 core , i'm A7!" > /dev/ttyRPMSG0

实验现象如下所示:

上图为A7通过虚拟的tty终端设备,转发到M4内核的消息内容, 最终通过M4核固件的串口Log功能打印出来对应信息。

自此,所有实验结束。

相关文章:

多核异构核间通信-mailbox/RPMsg 介绍及实验

1. 多核异构核间通信 由于MP157是一款多核异构的芯片&#xff0c;其中既包含的高性能的A7核及实时性强的M4内核&#xff0c;那么这两种处理器在工作时&#xff0c;怎么互相协调配合呢&#xff1f; 这就涉及到了核间通信的概念了。 IPCC (inter-processor communication contr…...

【Rust日报】2023-02-11 从头开始构建云数据库 RisingWave - 为什么我们从 C++ 转向 Rust...

GTK4发布v0.60gtk4-rs代码库包含GTK4的Rust crates。还有个庞大的GObject库生态系统&#xff0c;其中许多库基于gtk-rs中包含的Rust绑定工具。 特别是&#xff1a;gtk-rs-core&#xff0c;一些核心库的绑定&#xff0c;例如 glib、gio、pango、graphenegstreamer-rs&#xff0c…...

Linux驱动开发(一)

linux驱动学习记录 一、背景 在开始学习我的linux驱动之旅之前&#xff0c;先提一下题外话&#xff0c;我是一个c语言应用层开发工作人员&#xff0c;在工作当中往往会和硬件直接进行数据的交互&#xff0c;往往遇到数据不通的情况&#xff0c;常常难以定位&#xff0c;而恰巧…...

Spring MVC 之返回数据(静态页面、非静态页面、JSON对象、请求转发与请求重定向)

文章目录1. 默认情况下返回静态页面2. 返回一个非静态页面的数据2.1 ResponseBody 返回页面内容2.2 RestController ResponseBody Controller3. 实现登录功能&#xff0c;返回 JSON 对象3.1 前端使⽤ ajax&#xff0c;后端返回 json 给前端3.2 前端发送 JSON 的标准格式4. 请…...

leetcode-每日一题-2335(简单,贪心)

自己打表看一下过程就可以发现&#xff0c;其实就是每次选两个大的进行--之后秒数加1即可现有一台饮水机&#xff0c;可以制备冷水、温水和热水。每秒钟&#xff0c;可以装满 2 杯 不同 类型的水或者 1 杯任意类型的水。给你一个下标从 0 开始、长度为 3 的整数数组 amount &am…...

Verilog语法之数学函数

Verilog-2005支持一些简单的数学函数&#xff0c;其参数的数据类型只能是integer和real型。 Integer型数学函数 $clog2是一个以2为底的对数函数&#xff0c;其结果向上取整&#xff0c;返回值典型的格式&#xff1a; integer result; result $clog2(n); 最典型的应用就是通过…...

【手撕面试题】JavaScript(高频知识点一)

目录 面试官&#xff1a;请你简述 var、let、const 三者之间的区别&#xff1f; 面试官&#xff1a;请你谈谈对深拷贝与浅拷贝的理解 面试官&#xff1a;输入URL的那一瞬间浏览器做了什么&#xff1f; 面试官&#xff1a;说一说cookie sessionStorage localStorage 区别&am…...

如何用PHP实现消息推送

什么是消息推送 通过服务器自动推送消息到客户端(浏览器&#xff0c;APP&#xff0c;微信)的应用技术。 2. 为什么要使用消息推送技术 通常情况下都是用户发送请求浏览器显示用户需要的信息。推送技术通过自动传送信息给用户&#xff0c;来减少用于网络上搜索的时间。它根据…...

电子学会2020年6月青少年软件编程(图形化)等级考试试卷(四级)答案解析

青少年软件编程&#xff08;Scratch&#xff09;等级考试试卷&#xff08;四级A卷&#xff09; 分数&#xff1a;100.00 题数&#xff1a;30 一、单选题&#xff08;共15题&#xff0c;每题2分&#xff0c;共30分&#xff09; 1. 执行下图程序后&#xff0c;“花名…...

DaVinci:调色版本

调色版本 Grade Version记录着片段的全部调色信息。将一种调色风格或效果&#xff0c;保存为一个调色版本&#xff0c;从而可在多个调色版本之间查看、比较、挑选或者渲染输出。调色版本类型本地版本Local Versions在没有创建新的调色版本之前&#xff0c;片段的调色信息默认记…...

【C++初阶】十二、STL---反向迭代器的实现

目录 一、反向迭代器 二、反向迭代器的实现 一、反向迭代器 之前的模拟实现vector、list 的时候&#xff0c;这些都是实现了正向迭代器&#xff0c;反向迭代器都没有实现&#xff0c;这里就要实现反向迭代器 反向迭代器也是适配器&#xff08;配接器&#xff09;的一种&#…...

day 43|● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

1049. 最后一块石头的重量 II 有一堆石头&#xff0c;用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&#xff0c;且 x < y。那么粉碎的可能结果…...

[SSD固态硬盘技术 0] SSD的结构和原理导论

版权声明&#xff1a; 本文禁止转载机械硬盘的存储系统由于内部结构,其IO访问性能无法进一步提高,CPU与存储器之间的性能差距逐渐扩大。以Nand Flash为存储介质的固态硬盘技术的发展&#xff0c;性能瓶颈得到缓解。1. 什么是SSD固态硬盘&#xff08;Solid State Drives&#xf…...

Vue (3)

文章目录1. 数据代理1.1 回顾1.2 开始2. 事件处理2.1 v-on:click 点击事件2.2 事件修饰符2.3 键盘事件3. 计算属性3.1 插值语法实现3.2 methods实现3.3 计算属性实现4. 监视属性4.1 深度监视4.2 监视属性的简写形式4.3 watch 与 computed 对比1. 数据代理 在学习 数据代理 时 先…...

SQL语句,常用的DDL表操作语句

-- ddl sql 语句 -- 创建表 create table user_t( id int primary key auto_increment, -- 自增主键 name varchar(50) ); -- 查看表结构 desc user_t; desc user_test; -- 重命名表 alter table user_t rename to user_test; -- 查询数据库表 show tables; -- 添…...

C 语言 宏定义 :字符串化 stringify 的应用

字符串化 通过C 语言的宏&#xff08;MICRO&#xff09;&#xff0c;可以把数值或者一段字符的组合&#xff0c;转换为字符串。 因为 C语言的宏在【预处理】阶段就展开了&#xff0c;所以可以实现一些比较使用的功能&#xff0c;比如一些数据的初始化操作 比如定义一个宏&…...

代替swagger的api接口神器

自动化API文档-APIFOX 文章作者&#xff1a;老杨 一&#xff1a;概述 大家在后端开发开发过程中&#xff0c;最痛恨的两天事情&#xff1a;1.写文档&#xff0c;2.别人不写文档。而我们后端开发&#xff0c;必定经历的事情就是要和前端&测试对接&#xff0c;我们需要把我…...

2月12日,30秒知全网,精选7个热点

///北京首批29家药店开通异地参保直接结算服务试点药店已覆盖北京市东城区、西城区、朝阳区、海淀区、丰台区和石景山区&#xff0c;为来京就医的外省市参保人员提供便利///杭州召开平台经济健康高质量发展座谈会落实更有针对性的政策供给、提供“店小二”“保姆式”服务、建立…...

HTML img和video object-fit 属性

简介 Css中object-fit主要是应用到img标签和Video标签的&#xff0c;来控制显示缩放效果的。 首先我们存在一张图片&#xff0c;原始图片的尺寸是 1080px x 600px, 展示效果如下&#xff1a; 如果我们的css样式中的img大小设定并不能满足图片的原始大小&#xff0c;比如我们的…...

Pascal版本的 - freopen

参数 filename -- 这是包含要打开的文件的名称的字符串。 mode -- 这是包含文件访问模式的字符串。它包括 - 高级编号模式&说明1个 “r” 打开文件进行读取。该文件必须存在。 2个 “w” 创建一个用于写入的空文件。如果已存在同名文件&#xff0c;则删除其内容并将该文件…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...