Zynq 裸机 PS + PL 双网口实现之 lwip 库文件修改
基于 xilinx vivado 2017.4 库文件 lwip141_v2_0 的修改:
-
添加对 PHY 芯片 ksz9031 的支持;
-
添加 SDK 中 LWIP 参数设置对话框 emio_options 选项;
-
添加
XPAR_GMII2RGMIICON_0N_ETH0_ADDR和XPAR_GMII2RGMIICON_0N_ETH1_ADDR宏配置; -
支持 Zynq 裸机双网口通信实现
测试环境:
-
Vivado 2017.4
-
黑金 Zynq 7035 板卡,芯片型号:XC7Z035-2FFG676I
-
ETHERNET0 连接 PS 端网口,ETHERNET1 通过 EMIO 连接 PL端网口
修改内容:
1. 修改 lwip141_v2_0\src\contrib\ports\xilinx\netif\xaxiemacif_physpeed.c 文件
添加宏定义:
#define MICREL_PHY_IDENTIFIER 0x22
#define MICREL_PHY_KSZ9031_MODEL 0x220
添加 phy 芯片 ksz9031 速度获取函数:
unsigned int get_phy_speed_ksz9031(XAxiEthernet *xaxiemacp, u32 phy_addr)
{u16 control;u16 status;u16 partner_capabilities;xil_printf("Start PHY autonegotiation \r\n");XAxiEthernet_PhyWrite(xaxiemacp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_MAC, &control);//control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;control &= ~(0x10);XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_MAC, control);XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);control |= IEEE_ASYMMETRIC_PAUSE_MASK;control |= IEEE_PAUSE_MASK;control |= ADVERTISE_100;control |= ADVERTISE_10;XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,&control);control |= ADVERTISE_1000;XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,control);XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,&control);control |= (7 << 12); /* max number of gigabit attempts */control |= (1 << 11); /* enable downshift */XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,control);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;control |= IEEE_STAT_AUTONEGOTIATE_RESTART;XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_RESET_MASK;XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);while (1) {XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);if (control & IEEE_CTRL_RESET_MASK)continue;elsebreak;}xil_printf("Waiting for PHY to complete autonegotiation.\r\n");XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {sleep(1);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_STATUS_REG_OFFSET,&status);}xil_printf("autonegotiation complete \r\n");XAxiEthernet_PhyRead(xaxiemacp, phy_addr, 0x1f, &partner_capabilities);if ( (partner_capabilities & 0x40) == 0x40)/* 1000Mbps */return 1000;else if ( (partner_capabilities & 0x20) == 0x20)/* 100Mbps */return 100;else if ( (partner_capabilities & 0x10) == 0x10)/* 10Mbps */return 10;elsereturn 0;
}
修改 get_IEEE_phy_speed 函数,添加对 ksz9031 的支持:
unsigned get_IEEE_phy_speed(XAxiEthernet *xaxiemacp)
{u16 phy_identifier;u16 phy_model;u8 phytype;#ifdef XPAR_AXIETHERNET_0_BASEADDRu32 phy_addr = detect_phy(xaxiemacp);/* Get the PHY Identifier and Model number */XAxiEthernet_PhyRead(xaxiemacp, phy_addr, PHY_IDENTIFIER_1_REG, &phy_identifier);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, PHY_IDENTIFIER_2_REG, &phy_model);/* Depending upon what manufacturer PHY is connected, a different mask is* needed to determine the specific model number of the PHY. */if (phy_identifier == MARVEL_PHY_IDENTIFIER) {phy_model = phy_model & MARVEL_PHY_MODEL_NUM_MASK;if (phy_model == MARVEL_PHY_88E1116R_MODEL) {return get_phy_speed_88E1116R(xaxiemacp, phy_addr);} else if (phy_model == MARVEL_PHY_88E1111_MODEL) {return get_phy_speed_88E1111(xaxiemacp, phy_addr);}} else if (phy_identifier == TI_PHY_IDENTIFIER) {phy_model = phy_model & TI_PHY_DP83867_MODEL;phytype = XAxiEthernet_GetPhysicalInterface(xaxiemacp);if (phy_model == TI_PHY_DP83867_MODEL && phytype == XAE_PHY_TYPE_SGMII) {return get_phy_speed_TI_DP83867_SGMII(xaxiemacp, phy_addr);}if (phy_model == TI_PHY_DP83867_MODEL) {return get_phy_speed_TI_DP83867(xaxiemacp, phy_addr);}}else if(phy_identifier == MICREL_PHY_IDENTIFIER){xil_printf("Phy %d is KSZ9031\n\r", phy_addr);return get_phy_speed_ksz9031(xaxiemacp, phy_addr);}else {LWIP_DEBUGF(NETIF_DEBUG, ("XAxiEthernet get_IEEE_phy_speed: Detected PHY with unknown identifier/model.\r\n"));}
#endif
#ifdef PCM_PMA_CORE_PRESENTreturn get_phy_negotiated_speed(xaxiemacp, phy_addr);
#endif
}
2. 修改 lwip141_v2_0\src\contrib\ports\xilinx\netif\xemacpsif_physpeed.c 文件
添加宏定义:
#define MICREL_PHY_IDENTIFIER 0x22
#define MICREL_PHY_KSZ9031_MODEL 0x220
添加 phy 芯片 ksz9031 速度获取函数:
static u32_t get_phy_speed_ksz9031(XEmacPs *xemacpsp, u32_t phy_addr)
{u16_t temp;u16_t control;u16_t status;u16_t status_speed;u32_t timeout_counter = 0;u32_t temp_speed;u32_t phyregtemp;xil_printf("Start PHY autonegotiation \r\n");XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);control |= IEEE_ASYMMETRIC_PAUSE_MASK;control |= IEEE_PAUSE_MASK;control |= ADVERTISE_100;control |= ADVERTISE_10;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,&control);control |= ADVERTISE_1000;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,control);XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,&control);control |= (7 << 12); /* max number of gigabit attempts */control |= (1 << 11); /* enable downshift */XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,control);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;control |= IEEE_STAT_AUTONEGOTIATE_RESTART;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_RESET_MASK;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);while (1) {XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);if (control & IEEE_CTRL_RESET_MASK)continue;elsebreak;}XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);xil_printf("Waiting for PHY to complete autonegotiation.\r\n");while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {sleep(1);XEmacPs_PhyRead(xemacpsp, phy_addr,IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp);timeout_counter++;if (timeout_counter == 30) {xil_printf("Auto negotiation error \r\n");return;}XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);}xil_printf("autonegotiation complete \r\n");XEmacPs_PhyRead(xemacpsp, phy_addr,0x1f,&status_speed);if ( (status_speed & 0x40) == 0x40)/* 1000Mbps */return 1000;else if ( (status_speed & 0x20) == 0x20)/* 100Mbps */return 100;else if ( (status_speed & 0x10) == 0x10)/* 10Mbps */return 10;elsereturn 0;return XST_SUCCESS;
}
修改 get_IEEE_phy_speed 函数,添加对 ksz9031 的支持:
static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{u16_t phy_identity;u32_t RetStatus;XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,&phy_identity);if(phy_identity == MICREL_PHY_IDENTIFIER){RetStatus = get_phy_speed_ksz9031(xemacpsp, phy_addr);}else if (phy_identity == PHY_TI_IDENTIFIER) {RetStatus = get_TI_phy_speed(xemacpsp, phy_addr);} else {RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);}return RetStatus;
}
修改 lwip141_v2_0\data\lwip141.mld 文件
添加如下字段:
BEGIN CATEGORY emio_optionsPARAM name = emio_options, desc = "Settings for ETH using EMIO in PL";PARAM name = use_gmii2rgmii_core_on_eth0, desc = "Settings for ETH0 using GMII to RGMII ip core in PL", type = bool, default = false;PARAM name = use_gmii2rgmii_core_on_eth1, desc = "Settings for ETH1 using GMII to RGMII ip core in PL", type = bool, default = false;PARAM name = gmii2rgmii_core_address_on_eth0, desc = "Settings for ETH0's PHY address of GMII to RGMII ip core in PL", type = int, default = 0;PARAM name = gmii2rgmii_core_address_on_eth1, desc = "Settings for ETH1's PHY address of GMII to RGMII ip core in PL", type = int, default = 0;END CATEGORY
SDK Bsp‘s Settins 效果如图所示:

3. 修改 lwip141_v2_0\data\lwip141.tcl 文件
在 proc generate_lwip_opts {libhandle} 所在的大括号内添加如下字段:
# EMIO optionsset use_gmii2rgmii_core_on_eth0 [common::get_property CONFIG.use_gmii2rgmii_core_on_eth0 $libhandle]set use_gmii2rgmii_core_on_eth1 [common::get_property CONFIG.use_gmii2rgmii_core_on_eth1 $libhandle]set gmii2rgmii_core_address_on_eth0 [common::get_property CONFIG.gmii2rgmii_core_address_on_eth0 $libhandle]set gmii2rgmii_core_address_on_eth1 [common::get_property CONFIG.gmii2rgmii_core_address_on_eth1 $libhandle]if { $use_gmii2rgmii_core_on_eth0 == true } {puts $lwipopts_fd "\#define XPAR_GMII2RGMIICON_0N_ETH1_ADDR $gmii2rgmii_core_address_on_eth0"}if { $use_gmii2rgmii_core_on_eth1 == true } {puts $lwipopts_fd "\#define XPAR_GMII2RGMIICON_0N_ETH1_ADDR $gmii2rgmii_core_address_on_eth1"}
GitHub 链接:链接
相关文章:
Zynq 裸机 PS + PL 双网口实现之 lwip 库文件修改
基于 xilinx vivado 2017.4 库文件 lwip141_v2_0 的修改: 添加对 PHY 芯片 ksz9031 的支持; 添加 SDK 中 LWIP 参数设置对话框 emio_options 选项; 添加 XPAR_GMII2RGMIICON_0N_ETH0_ADDR 和 XPAR_GMII2RGMIICON_0N_ETH1_ADDR 宏配置&#…...
金三银四丨黑蛋老师带你剖析-CTF岗
作者丨黑蛋二进制是个庞大的方向,对应着许许多多方向的岗位,除了之前说过的逆向岗位,漏洞岗位,病毒岗位,还有专门打CTF的岗位,CTF是网络安全领域的一种比赛。普遍来讲,大学生学习网络安全都会参…...
Linux find命令
哈喽,大家好,我是有勇气的牛排(全网同名)🐮 有问题的小伙伴欢迎在文末评论,点赞、收藏是对我最大的支持!!!。 1 介绍 find命令用来查找置顶目录下的文件。任何位于参数…...
vue项目实现会议预约(包含某天的某个时间段和某月的某几天)
一、一天的时间段预约 会议预约有以下操作: 1.点击预约按钮,弹窗最近一周的预约时间点(半小时一个点),预约时间为5:00到24:00; 2.超过当前时间的时间点不允许再预约,已经预约的时间不允许再预约,…...
javacv桌面推送 通过推送和拉取udp组播视频流实现
ffmpeg udp 推流拉流命令单播推流E:/工具/ffmpeg/ffmpeg -f gdigrab -r 23 -i desktop -pkt_size 1316 -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f h264 udp://192.168.1.20:5001拉流ffplay -f h264 udp://192.168.1.20:5001 -fflags nobuffer -nofind_strea…...
2022年直播电商成交额,更是达到了24816亿元的成交额
近年来移动网络覆盖率、网速提升,直播行业不在是陌生的行业,直播也诞生了繁多的领域,游戏直播、户外直播等,当然还有今天的主题“直播带货”。直播带货是线上销售模式的一种,由衷是为了更好的把商品展示给用户观看&…...
【学习总结】2023寒假总结
写在前面时光匆匆,白驹过隙,转眼间寒假就过去了,这次寒假可以算的上是最长的一次假期,经历了从疫情到放开,从患病到阳康,在现实与虚幻的世界中玩耍,在痛苦的数据结构中徘徊,在每次早…...
宝塔搭建实战php源码人才求职管理系统后台端thinkphp源码(一)
大家好啊,我是测评君,欢迎来到web测评。 在开源社区里看到了这一套系统,骑士人才系统SE版,搭建测试了,感觉很不错。能够帮助一些想做招聘平台的朋友降低开发成本,就是要注意,想商业使用的话&…...
stk 根据六根数文件生成卫星轨迹(一)
先简单介绍下上面的参数。 Propagator预报轨道模型。 TwoBody为二体(开普勒运动模型)。HPOP为高精度轨道模型。目前只用到这两个。 下图为六根数参数 Orbit Epoch:为根数时间(UTC) Semimajor Axis:长半…...
深度学习算法面试常问问题(一)
博主秋招遇到的面试问题以及整理其他面经相关问题,无偿分享~ 项目叙述: 算法需求及应用场景算法的调研和初步方案的制定数据的准备(包括数据标注和数据增强)算法的介绍(包括输入和输出,loss、backbone、训…...
Spring 底层原理与解析 - 容器接口
Spring 底层原理与解析 - 容器接口 BeanFactory 能做哪些事 BeanFactory 与 ApplicaiotnContext 到底是谁提前做完了对象的加载 在之前的一篇关于 Spring 的文章Spring IoC 与容器的初始化中提到过,BeanFactory 接口与 ApplicationContext 接口之间的关系 可以看…...
Compose-Navigation简单案例上手
Navigation 快速上手 下面案例简要展示使用 Compose 版本的 Navigation 库来实现两个页面之间的跳转 这是完整的结构(忽略掉红线划过的那个包) 安装适用于 kotlin 的 navigation 依赖 dependencies {implementation("androidx.navigation:navigati…...
855. 考场就座
题目 考场就座 在考场里,一排有 N 个座位,分别编号为 0, 1, 2, …, N-1 。 当学生进入考场后,他必须坐在能够使他与离他最近的人之间的距离达到最大化的座位上。如果有多个这样的座位,他会坐在编号最小的座位上。(另外…...
k8s之ingress(二)
文章目录k8s之ingress1.1、Kubernetes 暴露服务的方式:1.2 基本概念1.3为什么需要Ingress资源1.4 Ingress的工作原理1.5ingress 暴露服务的方式总结k8s之ingress 1.1、Kubernetes 暴露服务的方式: Kubernetes暴露服务的方式目前只有三种:LoadBlancer Service、Nod…...
linux下监测串口数据
在编写上下位机通信代码时,需要分阶段测试,确保下位机,线路,上位机都OK. 一.检查设备数据传出 1.确定下位机的串口参数 如果波特率有问题,可能会…...
【面试之闭包】前端面试那些事(2)三分钟深入理解闭包(附详解实例)
目录1、什么是闭包,什么是作用域1.1 变量作用域1.2 闭包是啥?如何改变变量调用格局1.3 闭包的特性2、怎么用闭包,闭包实例应用2.1 常见闭包实例2.2 闭包异步函数的应用2.3 柯里化的应用3、闭包的优缺点3.1 优点3.2 缺点4、片尾彩蛋【写在前面…...
深入浅出带你学习WebSphere中间件漏洞
前言 上一篇文章给大家介绍了中间件glassfish的一些常见漏洞以及利用方法,今天我给大家带来的是WebSphere中间件的常见漏洞以及这些漏洞的利用方法,下面我们首先介绍一下WebSphere中间件是什么,然后展开来讲关于该中间件的漏洞。 WebSphere…...
如何一眼分辨是C还是C++
C语言的历史C语言是由贝尔实验室的Dennis Ritchie在20世纪70年代初开发的一种通用程序设计语言。在早期的计算机时代,许多计算机使用不同的汇编语言编写程序,这导致了程序的可移植性和代码的可重用性很低。因此,Dennis Ritchie在开发C语言时试…...
CMake系列:正确使用多配置编译系统
目录 常见错误 问题现象 正确做法 if指令应该什么时候使用 活学活用 把IF指令用于多配置编译系统是很多初学者容易犯下的错误。这篇文章启示性的教你如何正确理解、使用CMake的多配置编译系统。 常见错误 以Debug和Release配置有不同的宏定义为例,如下所示&a…...
PCB中的HDI板生产中的变化
关键词:HDI概述 HDI发展演变 HDI生产难点如果把一整个电子产业比作浩瀚的宇宙,那些智能电子设备就像宇宙中闪耀的星光,当你以“上帝”的视角手持放大镜去观察时,这些闪烁的星光点点其实都是一个个由精密的“自然规律”所“设计”好…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
