一、 设备节点、模块、拓扑结构关系

拓扑结构是我们了解MIPI-CSI内部模块以及与摄像头连接关系的最直观最便捷的方法。

1. 如何表示拓扑结构?

  • file视角

  • v4l2视角

来自:

参考文档《RKISP_Driver_User_Manual_v1.3.pdf》

  • 模块之间相互独立,通过struct media_entity来进行抽象,通常会将struct media_entity嵌入到其他结构中,以支持media framework功能;
  • entity模块包含struct media_pad,pad可以认为是端口,与其他模块进行联系的媒介,针对特定模块来说它是确定的;
  • pad通过struct media_link来建立连接,指定source和sink,即可将通路建立起来;
  • 各个模块之间最终建立一条数据流,便是一条pipeline了,同一条pipeline中的模块,可以根据前一个模块查找到下一个模块,因此也可以很方便进行遍历,并做进一步的设置操作;

2. 设备节点-------少media的

在/sys/class/video4linux/下可以找到v4l2相关的设备节点:

rk3568_r:/ # ls sys/class/video4linux
ls sys/class/video4linux
v4l-subdev0 v4l-subdev2 video1 video3 video5 video7
v4l-subdev1 video0 video2 video4 video6 video8 rk3568_r:/ # cat sys/class/video4linux/video0/dev
cat sys/class/video4linux/video0/dev
81:0
rk3568_r:/ # cat sys/class/video4linux/video0/name
cat sys/class/video4linux/video0/name
rkisp_mainpath

udev文件系统会为我们在dev/目录下创建一个video0节点,即dev/video0

用户可以打开dev/video0节点,通过IOCTL命令和内核空间进行通信。

rk3568_r:/ # ls /dev/video* -l
ls /dev/video* -l
crw-rw---- 1 media camera 81, 0 2022-11-09 17:06 /dev/video0
crw-rw---- 1 media camera 81, 1 2022-11-09 17:06 /dev/video1
crw-rw---- 1 media camera 81, 2 2022-11-09 17:06 /dev/video2
crw-rw---- 1 media camera 81, 3 2022-11-09 17:06 /dev/video3
crw-rw---- 1 media camera 81, 4 2022-11-09 17:06 /dev/video4
crw-rw---- 1 media camera 81, 5 2022-11-09 17:06 /dev/video5
crw-rw---- 1 media camera 81, 6 2022-11-09 17:06 /dev/video6
crw-rw---- 1 media camera 81, 7 2022-11-09 17:06 /dev/video7
crw-rw---- 1 media camera 81, 8 2022-11-09 17:06 /dev/video8 rk3568_r:/ # ls /dev/v4l-sub* -l
ls /dev/v4l-sub* -l
crw-rw-rw- 1 media camera 81, 9 2022-11-09 17:06 /dev/v4l-subdev0
crw-rw-rw- 1 media camera 81, 10 2022-11-09 17:06 /dev/v4l-subdev1
crw-rw-rw- 1 media camera 81, 11 2022-11-09 17:06 /dev/v4l-subdev2

3. 拓扑结构图

命令media-ctl可以查看拓扑结构图

rk3568_r:/ # media-ctl -d /dev/media0 -p
media-ctl -d /dev/media0 -p
Opening media device /dev/media0
Enumerating entities
Found 13 entities
Enumerating pads and links
Media controller API version 0.0.255 Media device information
------------------------
driver rkisp-vir0
model rkisp0
serial
bus info
hw revision 0x0
driver version 0.0.255 Device topology
- entity 1: rkisp-isp-subdev (4 pads, 7 links)
type V4L2 subdev subtype Unknown
device node name /dev/v4l-subdev0
pad0: Sink
[fmt:SBGGR10/4224x3136
crop.bounds:(0,0)/4096x3072
crop:(0,0)/4096x3072]
<- "rkisp-csi-subdev":1 []
<- "rkisp_rawrd0_m":0 []
<- "rkisp_rawrd2_s":0 []
pad1: Sink
<- "rkisp-input-params":0 []
pad2: Source
[fmt:YUYV2X8/4096x3072
crop.bounds:(0,0)/4096x3072
crop:(0,0)/4096x3072]
-> "rkisp_mainpath":0 []
-> "rkisp_selfpath":0 []
pad3: Source
-> "rkisp-statistics":0 [] - entity 6: rkisp-csi-subdev (6 pads, 5 links)
type V4L2 subdev subtype Unknown
device node name /dev/v4l-subdev1
pad0: Sink
<- "rockchip-csi2-dphy0":1 []
pad1: Source
-> "rkisp-isp-subdev":0 []
pad2: Source
-> "rkisp_rawwr0":0 []
pad3: Source
pad4: Source
-> "rkisp_rawwr2":0 []
pad5: Source
-> "rkisp_rawwr3":0 [] - entity 13: rkisp_mainpath (1 pad, 1 link)
type Node subtype V4L
device node name /dev/video0
pad0: Sink
<- "rkisp-isp-subdev":2 [] - entity 19: rkisp_selfpath (1 pad, 1 link)
type Node subtype V4L
device node name /dev/video1
pad0: Sink
<- "rkisp-isp-subdev":2 [] - entity 25: rkisp_rawwr0 (1 pad, 1 link)
type Node subtype V4L
device node name /dev/video2
pad0: Sink
<- "rkisp-csi-subdev":2 [] - entity 31: rkisp_rawwr2 (1 pad, 1 link)
type Node subtype V4L
device node name /dev/video3
pad0: Sink
<- "rkisp-csi-subdev":4 [] - entity 37: rkisp_rawwr3 (1 pad, 1 link)
type Node subtype V4L
device node name /dev/video4
pad0: Sink
<- "rkisp-csi-subdev":5 [] - entity 43: rkisp_rawrd0_m (1 pad, 1 link)
type Node subtype V4L
device node name /dev/video5
pad0: Source
-> "rkisp-isp-subdev":0 [] - entity 49: rkisp_rawrd2_s (1 pad, 1 link)
type Node subtype V4L
device node name /dev/video6
pad0: Source
-> "rkisp-isp-subdev":0 [] - entity 55: rkisp-statistics (1 pad, 1 link)
type Node subtype V4L
device node name /dev/video7
pad0: Sink
<- "rkisp-isp-subdev":3 [] - entity 61: rkisp-input-params (1 pad, 1 link)
type Node subtype V4L
device node name /dev/video8
pad0: Source
-> "rkisp-isp-subdev":1 [] - entity 67: rockchip-csi2-dphy0 (2 pads, 2 links)
type V4L2 subdev subtype Unknown
device node name /dev/v4l-subdev2
pad0: Sink
<- "m00_b_ov13850 4-0010":0 []
pad1: Source
-> "rkisp-csi-subdev":0 [] - entity 70: m00_b_ov13850 4-0010 (1 pad, 1 link)
type V4L2 subdev subtype Sensor
device node name /dev/v4l-subdev3
pad0: Source
[fmt:SBGGR10/4224x3136]
-> "rockchip-csi2-dphy0":0 []

下面是根据显示内容绘制的拓扑图:

该图中各个entity对应的设备节点名称已经标注。

模块的上方的黄色pad默认是source pad,下方的黄色pad是sink pad

字符设备类型主要有两种(只考虑摄像头):

  • /dev/videox (x取值0~8) (所有设备共用主设备号81,次设备号区分)
  • /dev/v4l-subdevx (x取值0~3)

video设备主要用于图像操作,必须创建结构体struct video_device变量,

v4l-subdev设备主要对应sensor等具体从设备,必须创建struct v4l2_subdev变量,

内部的isp和csi、csi-dphy也都需要注册为subdev

这些entity由media_entity模块负责维护,将他们连接起来。

4. 模块功能

这些entity瑞芯微已经设定了他们各自的功能:



这些entity我们可以理解为一个个功能模块。

这些功能模块有的用于驱动csi、有的驱动isp、有的用于预览图像、有的用于统计视频信息、有的用于配置参数。

这些功能模块,并不是都一定每个camera控制器都有的,有一些是通用的,比如,mainpath、selfpath,有一些要完全看SoC设计,即使瑞芯微的SoC,不同型号,差别也不小。所以具体问题要具体分析,不可教条。

v4l2只定义了基本架构,定义好了回调函数接口,要实现模块具体功能只需要填充好对应的回调函数即可,应用层通过这些字符设备文件和对应的ioctrl命令,就可以实现相应的功能。

二、 如何描述拓扑?

1. struct rkisp_device

rk3568的camera控制器使用结构体struct rkisp_device管理所有的资源。

/*
* struct rkisp_device - ISP platform device
* @base_addr: base register address
* @active_sensor: sensor in-use, set when streaming on
* @isp_sdev: ISP sub-device
* @cap_dev: image capture device
* @stats_vdev: ISP statistics output device
* @params_vdev: ISP input parameters device
* @dmarx_dev: image input device
* @csi_dev: mipi csi device
* @br_dev: bridge of isp and ispp device
*/
struct rkisp_device {
struct list_head list;
void __iomem *base_addr;
struct device *dev;
char name[128];
void *sw_base_addr;
struct rkisp_hw_dev *hw_dev;
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler ctrl_handler;
struct media_device media_dev;
struct v4l2_async_notifier notifier;
struct v4l2_subdev *subdevs[RKISP_SD_MAX];
struct rkisp_sensor_info *active_sensor;
struct rkisp_sensor_info sensors[RKISP_MAX_SENSOR];
int num_sensors;
struct rkisp_isp_subdev isp_sdev;
struct rkisp_capture_device cap_dev;
struct rkisp_isp_stats_vdev stats_vdev;
struct rkisp_isp_params_vdev params_vdev;
struct rkisp_dmarx_device dmarx_dev;
struct rkisp_csi_device csi_dev;
struct rkisp_bridge_device br_dev;
struct rkisp_luma_vdev luma_vdev;
struct proc_dir_entry *procfs;
struct rkisp_pipeline pipe;
enum rkisp_isp_ver isp_ver;
struct rkisp_emd_data emd_data_fifo[RKISP_EMDDATA_FIFO_MAX];
unsigned int emd_data_idx;
unsigned int emd_vc;
unsigned int emd_dt;
int vs_irq;
struct gpio_desc *vs_irq_gpio;
struct rkisp_hdr hdr;
unsigned int isp_state;
unsigned int isp_err_cnt;
unsigned int isp_isr_cnt;
unsigned int isp_inp;
struct mutex apilock; /* mutex to serialize the calls of stream */
struct mutex iqlock; /* mutex to serialize the calls of iq */
wait_queue_head_t sync_onoff;
dma_addr_t resmem_addr;
phys_addr_t resmem_pa;
size_t resmem_size;
int dev_id;
unsigned int skip_frame;
unsigned int irq_ends;
unsigned int irq_ends_mask;
bool send_fbcgain;
struct rkisp_ispp_buf *cur_fbcgain;
struct rkisp_buffer *cur_spbuf;
bool is_thunderboot; struct kfifo rdbk_kfifo;
spinlock_t rdbk_lock;
int rdbk_cnt;
int rdbk_cnt_x1;
int rdbk_cnt_x2;
int rdbk_cnt_x3;
u32 rd_mode;
u8 filt_state[RDBK_F_MAX];
};

其中与isp2.1拓扑结构相关的的几个结构体成员以及他们之间的关系:

成员 含义 拓扑图中的entity 设备名
void __iomem *base_addr 基地址 - -
struct rkisp_sensor_info *active_sensor; 正在使用的sensor - -
struct rkisp_isp_subdev isp_sdev; isp模块 rkisp-isp-subdev v4l-subdev0
struct rkisp_capture_device cap_dev; capture模块, 维护struct vb2_v4l2_buffer 对应拓扑图中的rkisp_mainpath、rkisp_selfpath、rkisp_rawwr0、rkisp_rawwr2、rkisp_rawwr3 video0~video4
struct rkisp_isp_stats_vdev stats_vdev; 数据统计模块 rkisp-statistics video7
struct rkisp_isp_params_vdev params_vdev; 参数配置模块 rkisp-input-params video8
struct rkisp_dmarx_device dmarx_dev; dma数据接收模块 rkisp_rawrd0_m、rkisp_rawrd2_s video5、video6
struct rkisp_csi_device csi_dev; csi的sub device从设备 rkisp-csi-subdev v4l-subdev1
struct rkisp_bridge_device br_dev; 桥接模块备,isp2.0中有 - -
enum rkisp_isp_ver isp_ver; isp版本号,rk3568是2.1 - -

2. 举例1:rkisp-csi-subdev注册到拓扑结构中

要添加到拓扑结构中,表示该模块的结构体中包含成员struct media_pad ,它和struct v4l2_subdev中的 struct media_entity entity;共同生成拓扑结构。

rkisp-csi-subdev设备结构体定义如下:

struct rkisp_csi_device {
struct rkisp_device *ispdev;
struct v4l2_subdev sd;
struct media_pad pads[CSI_PAD_MAX];
struct sink_info sink[CSI_PAD_MAX - 1];
int max_pad;
u32 err_cnt;
u32 irq_cnt;
u8 mipi_di[CSI_PAD_MAX - 1];
u8 tx_first[HDR_DMA_MAX];
};

参考第二节的拓扑图中 entity6 :

由上图可知,该模块有6个pad,pad属性定义如下

#define MEDIA_PAD_FL_SINK			(1 << 0)
#define MEDIA_PAD_FL_SOURCE (1 << 1)
#define MEDIA_PAD_FL_MUST_CONNECT (1 << 2)

pad的名称定义如下:

enum rkisp_csi_pad {
CSI_SINK = 0,
CSI_SRC_CH0,
CSI_SRC_CH1,
CSI_SRC_CH2,
CSI_SRC_CH3,
CSI_SRC_CH4,
CSI_PAD_MAX
};

isp的in pad

//isp的in pad
enum rkisp_isp_inp {
INP_INVAL = 0,
INP_RAWRD0 = BIT(0),
INP_RAWRD1 = BIT(1),
INP_RAWRD2 = BIT(2),
INP_CSI = BIT(4),
INP_DVP = BIT(5),
INP_DMARX_ISP = BIT(6),
INP_LVDS = BIT(7),
INP_CIF = BIT(8),
};

根据该拓扑图,pads[0]sinkpads[1~5] 均为source

以下是驱动中pad初始化代码:


rkisp_register_csi_subdev()
{
……
v4l2_subdev_init(sd, &rkisp_csi_ops);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; //是否需要子节点
sd->entity.ops = &rkisp_csi_media_ops;
sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
snprintf(sd->name, sizeof(sd->name), CSI_DEV_NAME);//名字前缀,#define CSI_DEV_NAME DRIVER_NAME "-csi-subdev" csi_dev->pads[CSI_SINK].flags =
MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; //pad0属性
csi_dev->pads[CSI_SRC_CH0].flags =
MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; //pad1属性 csi_dev->max_pad = CSI_SRC_CH0 + 1;
if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21) {
csi_dev->max_pad = CSI_PAD_MAX;
csi_dev->pads[CSI_SRC_CH1].flags = MEDIA_PAD_FL_SOURCE;//pad2属性
csi_dev->pads[CSI_SRC_CH2].flags = MEDIA_PAD_FL_SOURCE;//pad3属性
csi_dev->pads[CSI_SRC_CH3].flags = MEDIA_PAD_FL_SOURCE;//pad4属性
csi_dev->pads[CSI_SRC_CH4].flags = MEDIA_PAD_FL_SOURCE;//pad5属性
} ret = media_entity_pads_init(&sd->entity, csi_dev->max_pad,
csi_dev->pads);
……
}

一些关键的宏汇总:

//各个模块对应的名字
【kernel\drivers\media\platform\rockchip\isp\dev.h】
#define DRIVER_NAME "rkisp"
#define ISP_VDEV_NAME DRIVER_NAME "_ispdev"
#define SP_VDEV_NAME DRIVER_NAME "_selfpath"
#define MP_VDEV_NAME DRIVER_NAME "_mainpath"
#define DMA_VDEV_NAME DRIVER_NAME "_dmapath"
#define RAW_VDEV_NAME DRIVER_NAME "_rawpath"
#define DMATX0_VDEV_NAME DRIVER_NAME "_rawwr0"
#define DMATX1_VDEV_NAME DRIVER_NAME "_rawwr1"
#define DMATX2_VDEV_NAME DRIVER_NAME "_rawwr2"
#define DMATX3_VDEV_NAME DRIVER_NAME "_rawwr3"
#define DMARX0_VDEV_NAME DRIVER_NAME "_rawrd0_m"
#define DMARX1_VDEV_NAME DRIVER_NAME "_rawrd1_l"
#define DMARX2_VDEV_NAME DRIVER_NAME "_rawrd2_s" #define GRP_ID_SENSOR BIT(0)
#define GRP_ID_MIPIPHY BIT(1)
#define GRP_ID_ISP BIT(2)
#define GRP_ID_ISP_MP BIT(3)
#define GRP_ID_ISP_SP BIT(4)
#define GRP_ID_ISP_DMARX BIT(5)
#define GRP_ID_ISP_BRIDGE BIT(6)
#define GRP_ID_CSI BIT(7) //pad的属性
[kernel\include\uapi\linux\media.h]
#define MEDIA_PAD_FL_SINK (1 << 0)
#define MEDIA_PAD_FL_SOURCE (1 << 1)
#define MEDIA_PAD_FL_MUST_CONNECT (1 << 2)

由代码可得,拓扑关系由csi_dev->pads描述。

最终调用函数media_entity_pads_init()注册。

rkisp_register_platform_subdevs()
isp_subdev_notifier()
v4l2_async_notifier_parse_fwnode_endpoints()
__v4l2_async_notifier_parse_fwnode_endpoints()
{
for ( fwnode = fwnode_graph_get_next_endpoint())
{
dev_fwnode = fwnode_graph_get_port_parent(fwnode);
is_available = fwnode_device_is_available(dev_fwnode);
fwnode_handle_put(dev_fwnode);
fwnode_graph_parse_endpoint(fwnode, &ep);
}
for ( fwnode = fwnode_graph_get_next_endpoint())
{
dev_fwnode = fwnode_graph_get_port_parent(fwnode);
is_available = fwnode_device_is_available(dev_fwnode);
fwnode_handle_put(dev_fwnode);
fwnode_graph_parse_endpoint(fwnode, &ep);
v4l2_async_notifier_fwnode_parse_endpoint();
}
fwnode_handle_put(fwnode);
}

大家也可以试着去分析其他的模块。

三、设备树如何描述摄像头拓扑结构?

1. 设备树说明文档

瑞芯微MIPI-CSI设备树节点属性说明参考内核说明文档:

[kernel\Documentation\devicetree\bindings\media\]
video-interfaces.txt 关于sensor节点属性的说明,接口类型,
rockchip-isp1.txt isp模块属性说明
rockchip-mipi-dphy.txt dphy模块的说明
kernel\Documentation\devicetree\bindings\media\i2c\ovxxxxxx.txt ov系列的摄像设备树说明

这些文档中有关于port、remote-endpoint等节点的详细说明,如果不是厂家,我们只需要搞懂摄像头拓扑结构即可。

2. ov13850

我们移植的摄像头为ov13850,他的连接关系如下:

  • 数据通道通过mipi接口连接到rk3568的mipi通道0
  • Camera控制器的csi2-dphy0模块负责从mipi通道中接收数据帧

外设摄像头拓扑关系由设备树来描述,内核会自动解析并帮我们自动注册。

千言万语,不如一图:

由上图可得:

  1. 摄像头ov13850设备树只有一个port子节点,所以pad为0,out表示该pad是source pad
  2. remote-endpoint属性表示该pad连接的上游模块的pad名字:mipi_in_ucam0,而模块csi2_dphy0中包含pad:mipi_in_ucam0,所以ov13850连接到该模块
  3. csi2_dphy0 port0节点的mipi_in_ucam0设备,通过remote-endpoint即可知道该pad所连接的是设备ov13850的pad
  4. 综上可得csi2_dphy0的pad0(sink pad)连接的ov13850的pad0(source pad)

文中各种mipi技术文档,后台回复关键字:mipi

后面还会继续更新几篇Camera文章,

建议大家订阅本专题!

也可以后台留言,加一口君好友yikoupeng,

拉你进高质量技术交流群。

Camera | 6.v4l2拓扑架构的更多相关文章

  1. Android Camera 通过V4L2与kernel driver的完整交互过程

    http://blog.chinaunix.net/uid-26215986-id-3552456.html 原文地址:Android Camera 通过V4L2与kernel driver的完整交互 ...

  2. 基于Linux的v4l2视频架构驱动编写(转载)

    转自:http://www.linuxidc.com/Linux/2011-03/33022.htm 其实,我刚开始一直都不知道怎么写驱动,什么都不懂的,只知道我需要在做项目的过程中学习,所以,我就自 ...

  3. 基于Linux的v4l2视频架构驱动编写

    其实,我刚开始一直都不知道怎么写驱动,什么都不懂的,只知道我需要在做项目的过程中学习,所以,我就自己找了一个关于编写Linux下的视频采集监控项目做,然后上学期刚开学的时候听师兄说,跟院长做项目,没做 ...

  4. 【Linux开发】Linux V4L2驱动架构解析与开发导引

    Linux V4L2驱动架构解析与开发导引 Andrew按:众所周知,linux中可以采用灵活的多层次的驱动架构来对接口进行统一与抽象,最低层次的驱动总是直接面向硬件的,而最高层次的驱动在linux中 ...

  5. Android : Camera之camx hal架构

    一.camx的代码结构 目前主流的机型都使用camx架构,这个架构和之前架构的主要区别就是 芯片接口层的代码从hardware/qcom 迁移到 vendor/qcom/proprietary/下面, ...

  6. android摄像头(camera)之 v4l2的c测试代码【转】

    转自:https://blog.csdn.net/ldswfun/article/details/8745577 在移植android hal的过程中,移植的首要任务是要确保驱动完好,camera是属 ...

  7. 嵌入式Linux下Camera编程--V4L2【转】

    转自:http://blog.csdn.net/fwqlzz/article/details/51126653 版权声明:本文为博主原创文章,未经博主允许不得转载. USB video class(又 ...

  8. V4L2驱动程序架构

    1 V4L2简介 video4linux2(V4L2)是Linux内核中关于视频设备的内核驱动,它为Linux中视频设备访问提供了通用接口,在Linux系统中,V4L2驱动的Video设备节点路径通常 ...

  9. 9、基于Linux的v4l2视频架构应用编写

    Linux系统中,视频设备被当作一个设备文件来看待,设备文件存放在 /dev目录下,完整路径的设备文件名为: /dev/video0 . 视频采集基本步骤流程如下: 打开视频设备,设置视频设备属性及采 ...

  10. 转: V4L2驱动程序架构

    源地址:http://blog.chinaunix.net/uid-26101960-id-3297657.html 1 V4L2简介 video4linux2(V4L2)是Linux内核中关于视频设 ...

随机推荐

  1. 简单测下C++20 vector array lambda 的常数

    某天打了一下 CF,遇到了一道 https://codeforces.com/contest/1806/problem/E 这里需要卡常. 于是在 C++20(64) 下测出来了一些神奇的结果. 结果 ...

  2. MyBatis xml文件头

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC & ...

  3. .NET 9 预览版6发布

    微软发布了 .NET 9 的第 6 个预览版,此版本包括对运行时.SDK..NET MAUI.ASP.NET Core 和 C# 的更新,预览版没有包含太多新的主要功能或特性,因为已接近 .NET 9 ...

  4. 从基础到高级应用,详解用Python实现容器化和微服务架构

    本文分享自华为云社区<Python微服务与容器化实践详解[从基础到高级应用]>,作者: 柠檬味拥抱. Python中的容器化和微服务架构实践 在现代软件开发中,容器化和微服务架构已经成为主 ...

  5. [oeasy]python021_赛博宝剑铭文大赏_宝剑上的铭文_特殊符号和宝物

    继续运行 回忆上次内容 上次修改了 程序 将 石中剑 变成了 红色 爱之大剑       添加图片注释,不超过 140 字(可选)   可以 让宝剑 具有 更多 铭文符号 和 颜色 吗?   铭文 亚 ...

  6. [oeasy]python0016_在vim中直接运行python程序

    回忆上次内容 上次 置换 esc 和 caps lock 任何操作 都可以在 不移动 手腕的状态下完成了 每次都要 退出vim编辑器 才能 在shell中 运行python程序 有点麻烦 想要 不退出 ...

  7. 阅读翻译Mathematics for Machine Learning之2.6 Generating Set and Basis

    阅读翻译Mathematics for Machine Learning之2.6 Generating Set and Basis 关于: 首次发表日期:2024-07-19 Mathematics ...

  8. TS:菜单数组转树形,支持多级(递归)

    方法一 import {menus} from './menus.ts' function listToTree(list: any = [], options = {}, data = null) ...

  9. 顺序表之单链表(C实现)

    // Code file created by C Code Develop #include "ccd.h"#include "stdio.h"#includ ...

  10. MySQL之DQL

    *****DQL -- 数据查询语言   查询不会修改数据库表记录! 一. 基本查询 1. 字段(列)控制 1) 查询所有列  SELECT * FROM 表名;  SELECT * FROM emp ...