【C语言】Infiniband驱动mlx4_reset

一、注释

这个 mlx4_reset 函数负责重置 Mellanox 设备。它保存了设备的 PCI 头信息,然后重置了设备,之后还原保存的 PCI 头信息。请注意,该函数是用英文注释的,下面提供中文注释的版本。以下是该函数的流程:
1. 为保存 PCI 头信息分配内存。
2. 如果存在 PCI Express 能力结构,则保存 PCI 头信息。
3. 映射硬件重置寄存器地址空间。
4. 获取硬件信号量以防止闪存更新期间冲突。
5. 实际执行硬件重置操作。
6. 等待一段时间以确保设备重置完成。
7. 检查设备是否恢复到操作状态。
8. 如果设备已经恢复操作状态,则还原 PCI 头信息。
9. 清理和释放所有分配的资源。
以下是注释翻译成中文后的代码片段:

int mlx4_reset(struct mlx4_dev *dev) {// ...之前的代码略.../* 实际执行硬件重置 */writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET);iounmap(reset);/* 文档称重置后应等待一秒钟才能访问设备 */msleep(1000);// ...之后的代码略.../* 现在恢复 PCI 头信息 */if (pcie_cap) {// 恢复 PCI Express Device Control 寄存器devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4];if (pcie_capability_write_word(dev->persist->pdev,PCI_EXP_DEVCTL,devctl)) {err = -ENODEV;mlx4_err(dev, "无法恢复 HCA PCI Express 设备控制寄存器,中止操作\n");goto out;}// 恢复 PCI Express Link Control 寄存器linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4];if (pcie_capability_write_word(dev->persist->pdev,PCI_EXP_LNKCTL,linkctl)) {err = -ENODEV;mlx4_err(dev, "无法恢复 HCA PCI Express 链接控制寄存器,中止操作\n");goto out;}}// ...之后的清理代码略...return err;
}

请注意,这些注释更确切地描述了代码中的每个重要步骤,并对原开发者的注释进行翻译以更好地帮助中文读者理解代码。在 Linux 内核代码中,通常不鼓励添加太多注释,而是倾向于通过代码清晰表达意图。不过,如果在维护的项目中需要用中文注释,可以按照实际情况将代码中的关键部分翻译成中文。

注释,对关键代码部分进行解释:

#include <linux/errno.h>  // 包含Linux内核的错误号定义
#include <linux/pci.h>    // 包含用于PCI操作的函数和宏定义
#include <linux/delay.h>  // 包含延时函数
#include <linux/slab.h>   // 包含内存分配函数
#include <linux/jiffies.h>// 包含时间管理函数和宏#include "mlx4.h" // 包含mlx4驱动的定义和声明// 定义重置操作需要用到的常量
#define MLX4_RESET_BASE             0xf0000
#define MLX4_RESET_SIZE             0x400
#define MLX4_SEM_OFFSET             0x3fc
#define MLX4_RESET_OFFSET           0x10
#define MLX4_RESET_VALUE            swab32(1)#define MLX4_SEM_TIMEOUT_JIFFIES    (10 * HZ)
#define MLX4_RESET_TIMEOUT_JIFFIES  (2 * HZ)int mlx4_reset(struct mlx4_dev *dev)
{// 变量定义void __iomem *reset;     // 映射重置寄存器的地址u32 *hca_header = NULL;  // 存储设备PCI头信息的缓冲区int pcie_cap;u16 devctl, linkctl, vendor;unsigned long end;u32 sem;int i;int err = 0;// 以下是函数主要逻辑// 动态分配256字节的内存用于存储PCI头信息hca_header = kmalloc(256, GFP_KERNEL); if (!hca_header) {// 分配内存失败的错误处理}// 获取PCIe能力寄存器的偏移量pcie_cap = pci_pcie_cap(dev->persist->pdev);// 备份当前的PCI配置头信息,忽略有特殊含义的配置偏移22和23for (i = 0; i < 64; ++i) {if (i == 22 || i == 23)continue;// 读PCI配置头信息到 hca_header 中}// 映射设备的重置寄存器地址reset = ioremap(pci_resource_start(dev->persist->pdev, 0) + MLX4_RESET_BASE, MLX4_RESET_SIZE);if (!reset) {// 重置寄存器映射失败处理}// 获取硬件信号量以防止在设备复位期间进行闪存更新end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES;do {sem = readl(reset + MLX4_SEM_OFFSET);if (!sem)break;msleep(1);} while (time_before(jiffies, end));// sem仍然有效,则获取信号量失败if (sem) {// 获取信号量失败的错误处理}// 实际执行重置操作writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET);// 释放重置寄存器的映射iounmap(reset);// 根据文档,重置后需要等待一秒钟再访问设备msleep(1000);// 等待设备复位完成并确认PCI设备可被访问end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES;do {// 检查PCI_VENDOR_ID是否有效,如果有效,则设备复位成功} while (time_before(jiffies, end));// 如果vendor无效,代表设备复位失败if (vendor == 0xffff) {// 设备复位失败的错误处理}// 恢复之前保存的PCI配置头信息if (pcie_cap) {// 恢复PCIe设备控制和链接控制寄存器}// 恢复其他PCI配置头信息for (i = 0; i < 16; ++i) {// 写回PCI配置信息}// 最后,确保PCI_COMMAND寄存器被正确恢复if (pci_write_config_dword(dev->persist->pdev, PCI_COMMAND, hca_header[PCI_COMMAND / 4])) {// PCI_COMMAND寄存器恢复失败的错误处理}out:// 释放之前分配的内存kfree(hca_header);return err;
}

这段代码涉及到硬件层面的操作,这其中包括了对PCI设备的配置空间的保存、设备重置以及恢复的过程。遵循Linux内核中的错误处理机制,使用goto语句跳转到错误处理代码段。通过互斥机制和延时确保操作的安全性。大部分详细的注释已经涵盖在代码里。

完整注释:

这段代码相对较长,将注释分成几部分进行讲解,每部分涵盖一个逻辑模块。

请注意:由于代码中使用了很多Linux内核特定的函数和宏定义,某些注释可能需要一定的内核知识才能完全理解。

//drivers\net\ethernet\mellanox\mlx4\reset.c
/** 版权所有 (c) 2006, 2007 Cisco Systems, Inc. 保留所有权利。* 版权所有 (c) 2007, 2008 Mellanox Technologies. 保留所有权利。** 这款软件可以在两种许可下的任何一种下提供给您。* 您可以选择被GNU通用公共许可证(GPL)版本2的条款所许可,* 可从该源代码树主目录中的COPYING文件中获取,* 或者选择下面的OpenIB.org BSD许可证:**     源代码和二进制形式的再分发和使用是允许的,*     无论是否进行了修改,只要满足以下条件:**      - 源代码的再分发必须保留上述版权声明、此条件列表和下面的免责声明。**      - 以二进制形式进行的再分发必须在分发的文件和/或材料中复制上述版权声明、*        此条件列表以及随附的文件和/或材料中的免责声明。** 本软件是按“原样”提供的,没有任何形式的保证,* 无论是明示的或暗示的,包括但不限于适销性、* 适用于特定用途的保证和非侵权。在任何情况下,* 作者或版权所有者均不对任何索赔、损害或其他责任承担责任,* 无论是在合同诉讼、侵权行为或其他方面,* 与本软件或本软件的使用或其他交易有关。*/
// 引入一些必要的头文件
#include <linux/errno.h>    // 错误码定义
#include <linux/pci.h>      // PCI总线相关函数和结构体
#include <linux/delay.h>    // 延时相关的函数
#include <linux/slab.h>     // 内核内存分配相关
#include <linux/jiffies.h>  // 内核时间管理相关
#include "mlx4.h"           // Mellanox设备相关头文件
// 定义一个重置函数
int mlx4_reset(struct mlx4_dev *dev)
{void __iomem *reset;           // 映射设备寄存器的指针u32 *hca_header = NULL;        // 指向保存PCI头部数据的内存int pcie_cap;                  // PCI-E能力寄存器的位置u16 devctl, linkctl, vendor;   // 枚举一些PCI相关的变量unsigned long end;             // 用于记录超时时间u32 sem;                       // 记录半导体值int i;                         // 循环计数器int err = 0;                   // 错误码// 定义重置相关的常量
#define MLX4_RESET_BASE        0xf0000               // 重置寄存器的基础地址
#define MLX4_RESET_SIZE        0x400                 // 重置寄存器的大小
#define MLX4_SEM_OFFSET        0x3fc                 // 硬件信号量的偏移量
#define MLX4_RESET_OFFSET    0x10                  // 重置命令的偏移量
#define MLX4_RESET_VALUE    swab32(1)             // 重置命令的值// 定义超时的常数
#define MLX4_SEM_TIMEOUT_JIFFIES    (10 * HZ)  // 获取硬件信号量的超时时长
#define MLX4_RESET_TIMEOUT_JIFFIES    (2 * HZ)   // 重置等待超时的时长/** 重置芯片。这个过程有点不优雅,因为我们必须在重置之前保存PCI头部,* 然后在芯片重启后恢复它。我们跳过配置空间偏移量22和23,因为它们有特殊含义。*/// 是否需要保存完整的4K PCIe头?先分配空间以保存头部信息。hca_header = kmalloc(256, GFP_KERNEL);if (!hca_header) {err = -ENOMEM;  // 内存分配失败设置错误码mlx4_err(dev, "Couldn't allocate memory to save HCA PCI header, aborting\n");goto out;       // 跳转到函数的结束部分}// 获取PCI-E Capability的偏移量。pcie_cap = pci_pcie_cap(dev->persist->pdev);// 保存PCI配置空间的前256字节,跳过22和23偏移量的保存。for (i = 0; i < 64; ++i) {if (i == 22 || i == 23) continue;// 读取PCI配置空间的每一个DWORD,并保存起来if (pci_read_config_dword(dev->persist->pdev, i * 4, hca_header + i)) {err = -ENODEV;  // 读取失败则设定错误码mlx4_err(dev, "Couldn't save HCA PCI header, aborting\n");goto out;}}// 映射重置寄存器的物理地址到虚拟地址空间reset = ioremap(pci_resource_start(dev->persist->pdev, 0) + MLX4_RESET_BASE, MLX4_RESET_SIZE);if (!reset) {err = -ENOMEM;  // 映射失败设置错误码mlx4_err(dev, "Couldn't map HCA reset register, aborting\n");goto out;}// 锁定硬件信号量,以阻止闪存更新end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES;do {sem = readl(reset + MLX4_SEM_OFFSET);if (!sem)break;msleep(1);} while (time_before(jiffies, end));if (sem) {mlx4_err(dev, "Failed to obtain HW semaphore, aborting\n");err = -EAGAIN;  // 获取信号量失败设置错误码iounmap(reset);goto out;}// 实际进行重置操作writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET);iounmap(reset);  // 解除映射// 文档指出在设备访问前等待一秒钟msleep(1000);// 等待设备复位完毕end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES;do {if (!pci_read_config_word(dev->persist->pdev, PCI_VENDOR_ID, &vendor) && vendor != 0xffff)break;msleep(1);} while (time_before(jiffies, end));if (vendor == 0xffff) {err = -ENODEV;  // 设备重置后未恢复,则设置错误码mlx4_err(dev, "PCI device did not come back after reset, aborting\n");goto out;}// 恢复PCI头部信息if (pcie_cap) {devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4];if (pcie_capability_write_word(dev->persist->pdev, PCI_EXP_DEVCTL, devctl)) {err = -ENODEV;  // 恢复失败则设置错误码mlx4_err(dev, "Couldn't restore HCA PCI Express Device Control register, aborting\n");goto out;}linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4];if (pcie_capability_write_word(dev->persist->pdev, PCI_EXP_LNKCTL, linkctl)) {err = -ENODEV;  // 恢复失败则设置错误码mlx4_err(dev, "Couldn't restore HCA PCI Express Link control register, aborting\n");goto out;}}for (i = 0; i < 16; ++i) {if (i * 4 == PCI_COMMAND)continue;if (pci_write_config_dword(dev->persist->pdev, i * 4, hca_header[i])) {err = -ENODEV;  // 写入失败则设置错误码mlx4_err(dev, "Couldn't restore HCA reg %x, aborting\n", i);goto out;}}

继续从最后一个`for`循环。

    // 最后恢复PCI_COMMAND寄存器。if (pci_write_config_dword(dev->persist->pdev, PCI_COMMAND, hca_header[PCI_COMMAND / 4])) {err = -ENODEV;  // 写入失败则设置错误码mlx4_err(dev, "Couldn't restore HCA COMMAND, aborting\n");goto out;}out:kfree(hca_header);  // 释放之前保存PCI头部信息的内存空间return err;  // 返回错误码,0代表成功,非0代表失败
}

这部分代码主要执行了芯片的重置过程,并且在重置前后操作了PCI头部信息的保存与恢复,以确保设备能够在重置之后正常工作。需要注意的是代码中充满了错误检查和处理的步骤,以保证万一出现不可预见的问题时能够安全退出,并且反馈给调用者相应的错误信息。

二、讲解

这段代码来自Linux内核的Mellanox网络驱动mlx4,位于文件`reset.c`中。这个文件负责处理`mlx4`设备的重置逻辑。以下是代码中各个部分的中文解释:
代码开始于一个版权声明,声明代码属于Cisco Systems, Inc. 和 Mellanox Technologies所有,许可证可选为GPL(GNU通用公共许可证)版本2或OpenIB.org的BSD(伯克利软件许可证)。
接着引入了一些所需的Linux内核头文件。这些文件允许代码访问一些内核提供的功能,如内存分配和时间相关功能。
声明了`mlx4_reset`函数,它负责重置`mlx4_dev`指向的设备。
在函数中,定义了一些宏和它们的值:这些宏用于方便地引用重置流程中所需要的一些硬件寄存器的偏移量和相关的值。
函数`mlx4_reset`的实现分几个步骤:
1. 保存PCI配置头信息:在重置设备之前,需要保存PCI配置头的内容,以便后面可以恢复它。这是因为重置操作会导致这些信息丢失。作者注意到需要略过配置空间偏移量22和23,因为它们有特殊含义。
2. 映射重置寄存器:代码通过`ioremap`函数映射了设备的重置寄存器区域到内核地址空间,以便可以对它们进行读写操作。
3. 获取硬件信号量:在重置前需要获得一个硬件信号量,防止在重置时对闪存发生写操作。这里使用了循环,并通过读取信号量寄存器来判断是否获取成功。
4. 执行重置:通过向某个特定的寄存器写入特定值来触发硬件重置。
5. 等待设备初始化:硬件文档建议在访问设备之前等待一秒钟。
6. 恢复PCI头信息:重置完成后,PCI配置头信息需要从之前保存的内容恢复。
7. 清理:释放分配的内存空间,并返回执行结果。
整个函数的逻辑层次清晰,分为了准备、执行和清理三个主要部分。出错处理(错误标记`err`)也涵盖了各种可能的失败情况,例如内存分配失败、映射失败、信号量获取失败等,并在最后正确地释放资源和返回相应的错误代码。

ChatGPT

mlx4_reset是一种在InfiniBand驱动中遇到的函数,它一般是Mellanox InfiniBand驱动的一部分。这个函数用来将Mellanox InfiniBand硬件设备恢复到其初始状态。在Linux内核中,Mellanox的mlx4驱动负责管理InfiniBand设备。这个驱动通常与某些InfiniBand芯片组一起使用,比如那些被用在高性能计算集群中的芯片组。
由于InfiniBand驱动的代码是专业领域的内容,且通常需要深入了解硬件规格和内核编程,一个典型的`mlx4_reset`函数可能涉及复杂的硬件操作,包括直接与硬件交互的函数调用,内核同步机制,可能还有对硬件寄存器的读写。
在具体的C代码层面上,`mlx4_reset`函数的实现依赖于Mellanox硬件和驱动的具体版本,因此会根据不同的设备模型和驱动版本有所差异。但是,其大致框架可能如下所示:

int mlx4_reset(struct mlx4_dev *dev)
{// 获取设备上下文或设备特定的数据结构的引用struct mlx4_priv *priv = mlx4_priv(dev);// 执行硬件复位序列,可能包括:// - 禁用中断// - 停止设备端口// - 重置设备的某些区域或寄存器// - 将硬件状态置为已知的初始状态/* 示例代码,非真实代码 */mlx4_disable_interrupts(dev);mlx4_stop_device_ports(dev);// 实际的重置操作可以涉及对硬件寄存器的操作writel(value, priv->reset_reg); // 写入复位寄存器以重置设备// 检查设备是否已经重置完毕并且准备好重新初始化if (!mlx4_device_ready(dev)) {// 如果设备未能恢复到初始状态,则返回错误return -EIO;}// 重置成功后的操作,可能会重新初始化设备// 硬件复位后的设备必须重新初始化以便再次使用mlx4_enable_interrupts(dev);mlx4_start_device(dev);// 复位成功,返回0表示成功return 0;
}

请注意,上面的代码只是一个示意性的伪代码。实际的`mlx4_reset`函数包含更详细的步骤,包括对硬件规格的复杂操作,错误处理和设备状态的检查。要获得真实的源代码,您很可能需要访问Linux内核的源代码,具体到drivers/net/ethernet/mellanox/mlx4/目录中,您可以在该目录下找到与mlx4相关的实现。

通义灵码

在InfiniBand驱动程序中,mlx4_reset 函数通常用于复位 Mellanox InfiniBand Host Channel Adapter (HCA) 的硬件状态或某个特定功能模块。这个函数的作用是在遇到硬件错误、超时或其他需要恢复正常操作状态的情况时,重新初始化和同步HCA的硬件资源。

在C语言实现的Mellanox mlx4系列驱动中,mlx4_reset 函数可能执行如下步骤:

  1. 停止活动

    • 暂停所有正在进行的传输操作,包括清理发送和接收队列中的未完成请求(Work Requests, WRs)。
    • 中断任何正在使用的DMA传输。
  2. 硬件复位

    • 向HCA发送复位命令,使其进入已知初始状态。
    • 根据硬件规格书,通过相应的寄存器操作来触发和监控复位过程。
  3. 资源重置

    • 释放之前分配的硬件资源,如队列对、内存窗口、保护域等。
    • 重新初始化这些资源,确保它们处于有效可用的状态。
  4. 重新配置

    • 在硬件复位完成后,根据设备配置重新设置寄存器值和内部参数。
    • 重新建立硬件队列、中断处理机制和其他关键的硬件上下文。
  5. 启动服务

    • 重新启动必要的服务,比如恢复中断服务例程(Interrupt Service Routines, ISRs)。
    • 通知上层协议栈和应用程序复位已完成,可以继续进行新的通信操作。

请注意,上述流程是基于一般理解推测出的,具体实现细节会因不同版本的mlx4驱动而异,查看源代码是最准确的理解方式。

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

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

相关文章

基于51单片机的鸡蛋孵化环境监测警报系统Proteus仿真

地址&#xff1a;https://pan.baidu.com/s/1-OTZcuPHiZwdfd5KCaG7NA 提取码&#xff1a;1234 仿真图&#xff1a; 1、使用ADC0808测量一路模拟量&#xff08;可以表示温度、湿度、烟雾等等&#xff09; 2、如果测量值低于阀值&#xff0c;启动继电器&#xff1b;高于阀值&…

STM32之HAL开发——RCC外设CubeMX配置时钟

RCC外设介绍 RCC是Reset and Clock Control (复位和时钟控制)的缩写&#xff0c;它是STM32内部的一个重要外设&#xff0c;负责管理各种时钟源和时钟分频&#xff0c;以及为各个外设提供时钟使能。RCC模块可以通过寄存器操作或者库函数来配置。 RCC是复位和时钟控制模块&#…

Motorbike Physics Tool

此软件包适用于任何想要使用他们拥有的摩托车和玩家模型,并快速将其变成可驾驶摩托车而无需编写一行代码的人。 包说明 在这个工具中,它允许您使用您拥有的任何自行车模型,并将其变成可驾驶的摩托车,而无需编写任何代码。对于那些想在游戏中拥有自行车但又不想学习如何制作…

Go第三方框架--gin框架(二)

4. gin框架源码–Engine引擎和压缩前缀树的建立 讲了这么多 到标题4才开始介绍源码&#xff0c;主要原因还是想先在头脑中构建起 一个大体的框架 然后再填肉 这样不容易得脑血栓。标题四主要涉及标题2.3的步骤一 也就是 标题2.3中的 粗线框中的内容 4.1 Engine 引擎的建立 见…

工作记录 3月27日

复现计划&#xff1a; 数据集准备 跑通follow工作的前置代码 准备一个跑通的训练代码&#xff08;不管正确性&#xff09; 准备benchmark 跑一次训练 进一步阅读论文&#xff0c;更正训练代码&#xff0c;迭代 对两个方法的训练过程没有完全理解清楚&#xff0c;花了一天时间一…

43 带 fixed 列的 el-table 不兼容于 sortablejs

前言 这是一个基于 sortablejs 来实现的 el-table 的拖拽功能的基础实现 然后 这个过程中遇到的一个比较特殊的问题是, 关于 el-table-column 的 fixed 的属性, 对于 sortablejs 这边来定位目标选择列 影响的一个问题 在基础的用例中, 使用 “.el-table__body-wrapper tbo…

力扣--931.下降路径最小和

给你一个 n x n 的 方形 整数数组 matrix &#xff0c;请你找出并返回通过 matrix 的下降路径 的 最小和 。 下降路径 可以从第一行中的任何元素开始&#xff0c;并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列&#xff08;即位于正下方或者沿对角…

富格林:更改错误操作正规盈利出金

富格林指出&#xff0c;一些投资者在做单的时候会存在一些不好的交易习惯&#xff0c;这些习惯往往影响到交易的最终结果。想要减少亏损正规盈利出金&#xff0c;投资者需要更改这些不良习惯&#xff0c;才能从根源的接近问题有效提高出金。为帮助投资正规盈利出金&#xff0c;…

2024/3/26 C++作业

定义一个矩形类&#xff08;Rectangle&#xff09;&#xff0c;包含私有成员&#xff1a;长(length)、宽&#xff08;width&#xff09;, 定义成员函数&#xff1a; 设置长度&#xff1a;void set_l(int l) 设置宽度&#xff1a;void set_w(int w) 获取长度&#xff1a;int…

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记11:数字电位器MCP4017

系列文章目录 嵌入式|蓝桥杯STM32G431&#xff08;HAL库开发&#xff09;——CT117E学习笔记01&#xff1a;赛事介绍与硬件平台 嵌入式|蓝桥杯STM32G431&#xff08;HAL库开发&#xff09;——CT117E学习笔记02&#xff1a;开发环境安装 嵌入式|蓝桥杯STM32G431&#xff08;…

【Linux】详细分析/dev/loop的基本知识 | 空间满了的解决方法

目录 前言1. 基本知识2. 内存满了2.1 清空2.2 扩增 3. 彩蛋 前言 服务器一直down机&#xff0c;翻找日志文件一直找不到缘由&#xff0c;最终发现是挂载的内存满了&#xff0c;那本身这个文件就什么用呢&#xff1f; 1. 基本知识 /dev/loop是一种特殊的设备文件&#xff0c;…

005 Math类中的常用方法

Math类中包含一些用于执行基本数字运算的方法。 算术运算 方法描述abs(double a)返回 double值的绝对值。sqrt(double a) 返回 double值的正确舍入正平方根。 cbrt(double a)返回 double值的立方根。max(double a, double b)返回两个 double值中较大的 double 。min(double a…

I2C系列(三):软件模拟I2C读写24C02

一.目标 PC 端的串口调试软件通过 RS-485 与单片机通信&#xff0c;控制单片机利用软件模拟 I2C 总线对 EEPROM&#xff08;24C02&#xff09; 进行任意读写。 二.硬件简述 2.1 24C02硬件参数 24C02器件地址为0x50&#xff0c;存储容量为256字节&#xff0c;存储单元地址位数…

【SpringBoot】java.lang.Exception: No tests found matching Method

目录 问题解决 问题 在运行SpringBootMaven工程时&#xff0c;创建了一个新的Test单元测试&#xff0c;在运行时遇到的问题如下&#xff1a; java.lang.Exception: No tests found matching Method test_chatGPT(cn.bugstack.chatbot.api.test.ApiTest) from org.junit.inter…

使用 Docker Swarm(集群) 和Docker Stack(堆栈)部署容器化应用

1、Docker Swarm简介 说到集群&#xff0c;第一个想到的就是k8s&#xff0c;但docker官方也提供了集群和编排解决方案&#xff0c;它允许你将多个 Docker 主机连接在一起&#xff0c;形成一个“群集”&#xff08;Swarm&#xff09;&#xff0c;并可以在这个 Swarm 上运行和管…

题目:输入三个整数x,y,z,请把这三个数由小到大输出。

题目&#xff1a;输入三个整数x,y,z&#xff0c;请把这三个数由小到大输出。 There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worri…

Python与供应链-2预测误差及指数平滑需求预测模型

主要介绍预测误差和指数平滑模型的相关理论,然后再通过Python的statsmodels封装的指数平滑函数预测需求。 1预测误差 预测误差是指预测结果与预测对象发展变化的真实结果之间的差距。这种误差分为绝对误差和相对误差。绝对误差是预测值与实际观测值的绝对差距,而相对误差则…

分期乐(乐信)与银行机构合伙放贷,谁是真正的受益者?

分期乐&#xff08;乐信&#xff09;与银行机构的合作放贷模式&#xff0c;无疑在金融领域引起了广泛关注。这种合作模式似乎为各方都带来了不小的利益&#xff0c;但究竟谁是真正的受益者呢&#xff1f; 银行受益&#xff1a;对于银行机构而言&#xff0c;与分期乐&#xff0…

C是用什么语言写出来的?

C是用什么语言写出来的? C语言的起源和发展是一个迭代过程&#xff1a; 1. 最初的C语言编译器的开发始于对B语言的改进。B语言是由Ken Thompson设计的&#xff0c;它是基于BCPL语言简化而来的。在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「 C语言的…

RocketMQ学习笔记:分布式事务

这是本人学习的总结&#xff0c;主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、分布式事务的难题2、解决方式2.1、半事务消息和事务回查2.2、代码样例2.2.1、TransactionListener2.2.2、TransactionMQProducer2.2.3、MessageListenerConcurrently2.2.4、流程图 1、分布…