Day5: platformDriver-1
Platform Driver (1)
Linux kernel中大部分设备可以归结为平台设备,因此大部分的驱动是平台驱动(patform driver)
什么是平台设备
平台设备是linux的设备模型中一类设备的抽象。 内核中的描述:
Platform devices are devices that typically appear as autonomous entities in the system. This includes legacy port-based devices and host bridges to peripheral buses, and most controllers integrated into system-on-chip platforms. What they usually have in common is direct addressing from a CPU bus. Rarely, a platform_device will be connected through a segment of some other kind of bus; but its registers will still be directly addressable.
一句话来描述就是: CPU能够直接寻址的SOC上的外设
图1:Platform设备
图1中的uart控制器,I2C控制器,GPIO控制器等,都是平台设备。
可以说,paltform设备对Linux驱动工程师是非常重要的,因为我们编写的大多数设备驱动,都是为了驱动plaftom设备。
Platform设备在内核中的实现主要包括三个部分:
- Platform Bus,基于底层bus模块,抽象出一个虚拟的Platform bus,用于挂载Platform设备;
- Platform Device,基于底层device模块,抽象出Platform Device,用于表示Platform设备;
- Platform Driver,基于底层device_driver模块,抽象出Platform Driver,用于驱动Platform设备
对于图1中的I2C控制器挂载在platform Bus上,因此我们在linux kernel中常说的I2C driver,都是指I2C controller driver,都是以platform driver的形式存在,当然,对应的控制器是platform device。
与此同时,kernel抽象出I2C bus(/sys/bus/i2c),用于挂载和I2C controller通过I2C总线连接的各个I2C slave device。
串口驱动开发
驱动开发框架
得益于设备模型,Linux kernel平台驱动的开发有了一套非常固定的框架
1)模块的入口和出口
用于注册/注销platform driver,这一部分的代码基本固定,包括函数和变量的命名方式也可固定,如下:
/* 驱动模块加载 */static int __init xxxdriver_init(void){return platform_driver_register(&xxx_driver);}/* 驱动模块卸载 */static void __exit xxxdriver_exit(void){platform_driver_unregister(&xxx_driver);}module_init(xxxdriver_init);module_exit(xxxdriver_exit);MODULE_LICENSE("GPL V2");MODULE_AUTHOR("QianRuShi-ABC");
2)platform driver
基本的platform driver包含三要素:struct platform_driver变量、probe/remove函数、用于和device tree匹配的match table,如下:
/** platform 平台驱动结构体*/
static struct platform_driver xxx_driver = {.driver = {.name = "xxx",.of_match_table = xxx_of_match,},.probe = xxx_probe,.remove = xxx_remove,
};/** platform 驱动的 probe 函数* 驱动与设备匹配成功以后此函数就会执行*/static int xxx_probe(struct platform_device *dev){match = of_match_device(xxx_of_match, &pdev->dev);if (!match) {dev_err(&pdev->dev, "Error: No device match found\n");return -ENODEV;}return 0;}static int xxx_remove(struct platform_device *dev){....../* 函数具体内容 */return 0;}/* 匹配列表 */static const struct of_device_id xxx_of_match[] = {{ .compatible = "xxx-xxx" },{ /* Sentinel */ }};
注意,xxx_of_match中的.compatible需要和DTS文件中的compatible对应,一般格式是“厂商名称,芯片系列-模块名”,例如“actions,s900-serial”
##串口驱动
串口设备(serial or uart,后面不再区分)是TTY设备的一种,Linux kernel为了方便串口驱动的开发,在TTY framework的基础上,封装了一层串口框架(serial framework)。该框架尽可能的屏蔽了TTY有关的技术细节(比较难懂),驱动工程师在编写串口驱动的时候,只需要把精力放在串口以及串口控制器本身即可。
Linux kernel serial framework位于“drivers/tty/serial”目录中,其软件架构(如下面图2所示)比较简单:
图2: serialFramework
Serial core是Serial framework的核心实现,对上封装、屏蔽TTY的技术细节,对下为具体的串口驱动提供简单、统一的编程API。
Serial drivers就是具体的串口驱动。
Serial Core
serial core主要实现如下三类功能
1)将串口设备有关的物理对象(及其操作方法)封装成一个一个的数据结构,以达到用软件语言描述硬件的目的。
2)向底层driver提供串口驱动的编程接口。
3)基于TTY framework所提供的TTY driver的编写规则,将底层driver看到的serial driver,转换为TTY driver,并将所有的serial操作,转换为对应的tty操作。
关键数据结构
struct uart_port
struct uart_state
struct uart_ops
struct uart_driver
API:
int uart_register_driver(struct uart_driver *uart);
void uart_unregister_driver(struct uart_driver *uart);int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_match_port(struct uart_port *port1, struct uart_port *port2);int uart_suspend_port(struct uart_driver *reg, struct uart_port *port);
int uart_resume_port(struct uart_driver *reg, struct uart_port *port);static inline int uart_tx_stopped(struct uart_port *port)extern void uart_insert_char(struct uart_port *port, unsigned int status,unsigned int overrun, unsigned int ch, unsigned int flag);
串口驱动的移植步骤
- 定义并注册uart driver
- 注册uart port
- 定义并实现uart ops
定义并注册uart driver
static struct uart_driver imx_reg = {.owner = THIS_MODULE,.driver_name = DRIVER_NAME,.dev_name = DEV_NAME,.major = SERIAL_IMX_MAJOR,.minor = MINOR_START,.nr = ARRAY_SIZE(imx_ports),.cons = IMX_CONSOLE,
};
注册uart port
platform device代表uart控制器,是实体抽象。对应的,uart port代表“串口”. 因此,我们需要在platform device probe的时候(platform driver的probe接口),动态分配并注册一个uart port(struct uart_port)。在后续的串口操作中,都是以uart port指针为对象. 见下一章节代码中i.mx6的驱动代码。
定义并实现uart ops
struct uart_ops结构包含了各式各样的uart端口的操作函数,需要在添加uart port的时候提供.见下一章节代码中i.mx6的驱动代码
完整代码
对应驱动开发框架中,1)模块的入口和出口
static int __init imx_serial_init(void)
{int ret = uart_register_driver(&imx_reg);if (ret)return ret;ret = platform_driver_register(&serial_imx_driver);if (ret != 0)uart_unregister_driver(&imx_reg);return ret;
}static void __exit imx_serial_exit(void)
{platform_driver_unregister(&serial_imx_driver);uart_unregister_driver(&imx_reg);
}module_init(imx_serial_init);
module_exit(imx_serial_exit);MODULE_AUTHOR("Sascha Hauer");
MODULE_DESCRIPTION("IMX generic serial port driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:imx-uart");
对应驱动开发框架中,2)platform driver
基本的platform driver包含三要素:struct platform_driver变量、probe/remove函数、用于和device tree匹配的match table
- struct platform_driver变量
static struct platform_driver serial_imx_driver = {.probe = serial_imx_probe,.remove = serial_imx_remove,.suspend = serial_imx_suspend,.resume = serial_imx_resume,.id_table = imx_uart_devtype,.driver = {.name = "imx-uart",.of_match_table = imx_uart_dt_ids,},
};
- robe/remove函数
static int serial_imx_probe(struct platform_device *pdev) {struct imx_port *sport;void __iomem *base;int ret = 0;struct resource *res;int txirq, rxirq, rtsirq;sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);if (!sport)return -ENOMEM;ret = serial_imx_probe_dt(sport, pdev);if (ret > 0)serial_imx_probe_pdata(sport, pdev);else if (ret < 0)return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base))return PTR_ERR(base);rxirq = platform_get_irq(pdev, 0); txirq = platform_get_irq(pdev, 1); rtsirq = platform_get_irq(pdev, 2);sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; sport->port.membase = base; sport->port.type = PORT_IMX, sport->port.iotype = UPIO_MEM; sport->port.irq = rxirq; sport->port.fifosize = 32; sport->port.ops = &imx_pops; sport->port.rs485_config = imx_rs485_config; sport->port.rs485.flags =SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX; sport->port.flags = UPF_BOOT_AUTOCONF; init_timer(&sport->timer); sport->timer.function = imx_timeout; sport->timer.data = (unsigned long)sport;sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk_ipg)) {ret = PTR_ERR(sport->clk_ipg);dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);return ret; }sport->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(sport->clk_per)) {ret = PTR_ERR(sport->clk_per);dev_err(&pdev->dev, "failed to get per clk: %d\n", ret);return ret; }sport->port.uartclk = clk_get_rate(sport->clk_per); if (sport->port.uartclk > IMX_MODULE_MAX_CLK_RATE) {ret = clk_set_rate(sport->clk_per, IMX_MODULE_MAX_CLK_RATE);if (ret < 0) {dev_err(&pdev->dev, "clk_set_rate() failed\n");return ret;} } sport->port.uartclk = clk_get_rate(sport->clk_per);/** Allocate the IRQ(s) i.MX1 has three interrupts whereas later* chips only have one interrupt.*/ if (txirq > 0) {ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0,dev_name(&pdev->dev), sport);if (ret)return ret;ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0,dev_name(&pdev->dev), sport);if (ret)return ret; } else {ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0,dev_name(&pdev->dev), sport);if (ret)return ret; } imx_ports[sport->port.line] = sport; platform_set_drvdata(pdev, sport); return uart_add_one_port(&imx_reg, &sport->port);
}
static int serial_imx_remove(struct platform_device *pdev)
{struct imx_port *sport = platform_get_drvdata(pdev);return uart_remove_one_port(&imx_reg, &sport->port);
}
- 用于和device tree匹配的match table
static const struct of_device_id imx_uart_dt_ids[] = {{ .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], },{ .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },{ .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
对应串口驱动的移植步骤中,定义并注册uart driver
在驱动init函数中注册了uart driver
int ret = uart_register_driver(&imx_reg);
在linux serial framework中,uart driver是一个平行于platform driver的概念,用于驱动“虚拟”的“串口”设备。
#define DRIVER_NAME "IMX-uart"static struct uart_driver imx_reg = {.owner = THIS_MODULE,.driver_name = DRIVER_NAME,.dev_name = DEV_NAME,.major = SERIAL_IMX_MAJOR,.minor = MINOR_START,.nr = ARRAY_SIZE(imx_ports),.cons = IMX_CONSOLE,
};
对应串口驱动的移植步骤中,注册uart port
假如一个soc中有5个串口控制器(也可称作uart控制器,后面我们不再区分),每个uart控制器都可引出一个串口(uart port)。那么:
每个uart控制器,都是一个platform device,由dts文件的一个node描述。而这5个platform device,可由同一个driver驱动,即platform driver。
相对于uart控制器实实在在的存在,我们更为熟悉的串口(uart port),则是虚拟的设备,它们由“struct uart_port”描述(后面会介绍),并在platform driver的probe接口中,注册到kernel。它们可由同一个driver驱动,即这里所说的uart driver。
struct imx_port {struct uart_port port;struct timer_list timer;unsigned int old_status;unsigned int have_rtscts:1;unsigned int dte_mode:1;unsigned int irda_inv_rx:1;unsigned int irda_inv_tx:1;unsigned short trcv_delay; /* transceiver delay */struct clk *clk_ipg;struct clk *clk_per;const struct imx_uart_data *devdata;/* DMA fields */unsigned int dma_is_inited:1;unsigned int dma_is_enabled:1;unsigned int dma_is_rxing:1;unsigned int dma_is_txing:1;struct dma_chan *dma_chan_rx, *dma_chan_tx;struct scatterlist tx_sgl[2];struct imx_dma_rxbuf rx_buf;unsigned int tx_bytes;unsigned int dma_tx_nents;struct delayed_work tsk_dma_tx;wait_queue_head_t dma_wait;unsigned int saved_reg[10];
#define DMA_TX_IS_WORKING 1unsigned long flags;
};
在platform driver的probe函数中会动态分配并注册一个uart port(struct uart_port)然后初始化并注册其中的port变量。初始化完之后,直接调用uart_add_one_port接口,将该port添加到kernel serial core
再返回上面的static int serial_imx_probe(struct platform_device *pdev)
展开看到
//分配struct xxx_port类型的指针
struct imx_port *sport;
sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
//获取中断号,该串口对应的中断号, 一般是从DTS中解析得到的;rxirq = platform_get_irq(pdev, 0);txirq = platform_get_irq(pdev, 1);rtsirq = platform_get_irq(pdev, 2);
//初始化并注册其中的port变量sport->port.dev = &pdev->dev;sport->port.mapbase = res->start;sport->port.membase = base;sport->port.type = PORT_IMX,sport->port.iotype = UPIO_MEM;sport->port.irq = rxirq;sport->port.fifosize = 32;sport->port.ops = &imx_pops;sport->port.rs485_config = imx_rs485_config;sport->port.rs485.flags =SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX;sport->port.flags = UPF_BOOT_AUTOCONF;init_timer(&sport->timer);sport->timer.function = imx_timeout;sport->timer.data = (unsigned long)sport;
在proble函数的最后,调用uart_add_one_port接口,将该port添加到kernel serial core
return uart_add_one_port(&imx_reg, &sport->port);
对应串口驱动的移植步骤中,定义并实现uart ops
上面platform driver的probe函数serial_imx_probe
,展开中看到
sport->port.ops = &imx_pops;
struct uart_ops结构包含了各式各样的uart端口的操作函数,需要在添加uart port的时候提供。
static struct uart_ops imx_pops = {.tx_empty = imx_tx_empty,.set_mctrl = imx_set_mctrl,.get_mctrl = imx_get_mctrl,.stop_tx = imx_stop_tx,.start_tx = imx_start_tx,.stop_rx = imx_stop_rx,.enable_ms = imx_enable_ms,.break_ctl = imx_break_ctl,.startup = imx_startup,.shutdown = imx_shutdown,.flush_buffer = imx_flush_buffer,.set_termios = imx_set_termios,.type = imx_type,.config_port = imx_config_port,.verify_port = imx_verify_port,
#if defined(CONFIG_CONSOLE_POLL).poll_init = imx_poll_init,.poll_get_char = imx_poll_get_char,.poll_put_char = imx_poll_put_char,
#endif
};
个人公众号交流
#参考
http://www.wowotech.net/x_project/serial_driver_porting_1.html
http://www.wowotech.net/x_project/serial_driver_porting_2.html
http://www.wowotech.net/x_project/serial_driver_porting_3.html
http://www.wowotech.net/x_project/serial_driver_porting_4.html
http://www.wowotech.net/comm/serial_overview.html
相关文章:

Day5: platformDriver-1
Platform Driver (1) Linux kernel中大部分设备可以归结为平台设备,因此大部分的驱动是平台驱动(patform driver) 什么是平台设备 平台设备是linux的设备模型中一类设备的抽象。 内核中的描述: Platform devices are devices t…...

开发手册——一、编程规约_7.控制语句
这篇文章主要梳理了在java的实际开发过程中的编程规范问题。本篇文章主要借鉴于《阿里巴巴java开发手册终极版》 下面我们一起来看一下吧。 1. 【强制】在一个 switch 块内,每个 case 要么通过 break / return 等来终止,要么注释说明程序将继续执行到哪…...

python每日学9 : windows上配置gitee的远程仓库,git的初步使用
在开发中,如果遇到复杂的项目,使用版本控制是非常有必要的,如果涉及到多端开发,那么还需要使用远程仓库。本文作个简单记录,记录下git初步使用。 1 下载与安装 git还有几个ui版本,但是开始使用的话&#…...

精确率与召回率,ROC曲线与PR曲线
精确率与召回率,ROC曲线与PR曲线 在机器学习的算法评估中,尤其是分类算法评估中,我们经常听到精确率(precision)与召回率(recall),ROC曲线与PR曲线这些概念,那这些概念到底有什么用处呢? 首先,…...

现代操作系统——Linux架构与学习
小白的疑惑 在我决定从事嵌入式(应用层)方面的工作时,我查询了大量资料该如何学习,几乎所有观点不约而同的都指向了学习好Linux,大部分工作都是在Linux环境下来进行工作的。于是我雄心勃勃的去下载Linux,可…...
中文代码82
PK 嘚釦 docProps/PK 嘚釦羸 r docProps/app.xml潙蚽?勶曻Q顗濔S? 錞礖剅D柍珘m?鳞?ぷ辷f硌?2?upc厭Y樐8 rU y搪m眾&a?珪?紓 玺鶋瑣襚? ?i嘲rN?布倖儇?攊橌??嚗猝)芻矂2吟腊K湞?CK臶>鸘\?ΔF滋齢q旮T?桀?;偉 A軥v蕯朾偤佷3?е…...

顺序表(一篇带你掌握顺序表)
目录 一、顺序表是什么 1.1 概念 1.2 分类 1.3 结构 二、顺序表的基本操作 2.1 前绪准备 2.2 初始化 2.3 扩容 2.5 尾插 2.6 打印 2.7 尾删 2.8 头插 2.9 头删 2.10 在pos位置插入 2.11 删除pos位置的数据 2.12 查找 三、完整代码 3.1 Test.c文件 3.2 SeqList.h…...

【SpringCloud】SpringCloud教程之Feign实战
目录前言SpringCloud Feign远程服务调用一.需求二.两个服务的yml配置和访问路径三.使用RestTemplate远程调用(order服务内编写)四.构建Feign(order服务内配置)五.自定义Feign配置(order服务内配置)六.Feign配置日志(oder服务内配置)七.Feign调优(order服务内配置)八.抽离Feign前…...

嵌入式linux必备内存泄露检测神器
Valgrind介绍 Valgrind是一个可移植的动态二进制分析工具集,主要用于发现程序中的内存泄漏、不合法内存访问、使用未初始化的内存、不正确的内存释放以及性能问题等,可在Linux和Mac OS X等平台上使用。 Valgrind由多个工具组成,其中最常用的…...

设计模式之行为型模式
四、行为型模式 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在…...
解密 三岁的三岁到底为什么叫做三岁?
机缘 那一年,一次奇奇怪怪的挫折与一次奇奇怪怪的成长。 在学习Python的路上总觉得少了点什么,是心情?是机遇?还是力量? 都不是又都是! 缺少一个实践和记忆的平台 记性不好是硬伤 前一天学的下一秒就忘记了…...
id选择器
id选择器可以为特定的id的标签进行css美化 使用方法: 标签内设好 id值, CSS的id选择器以“#id名”来调用 注意 所有标签都有id值id属性值类似于身份证号码,在一个页面中是唯一的值,不可重复一个标签上只能有一个id属性值一个id属性…...
《科技之巅3》读书笔记
文章目录书籍信息人工智能,“吃一堑长一智”的机器人机交互,为解决“交流障碍”问题而生硬件与算法,好马还需好鞍模式创新,赋予技术新的定义云与数据共享,灵活应对信息的爆发式增长“机器人”,从电影和小说…...

18.用于大型程序的工具
文章目录用于大型程序的工具18.1异常处理18.1.1抛出异常栈展开栈展开过程中对象被自动销毁析构函数与异常异常对象18.1.2捕获异常查找匹配的处理代码重新抛出捕获所有异常的处理代码18.1.3函数try语句块与构造函数18.1.4noexcept异常说明违反异常说明异常说明的实参noexcept运算…...

mysql一主键uuid和自增的选择
文章目录 1.自增ID的优缺点1.1 优点1.2 缺点1.3 不适合以自增ID主键作为主键的情况2.UUID作为主键2.1 介绍2.2 优点2.3 缺点3.有序UUID作为主键3.1 介绍3.2 演示使用3.2.1 前提知识3.2.1.1 数据类型 - binary3.2.1.2 函数 - hex()3.2.1.3 函数 - unhex()3.2.2 数据库层3.2.3 JA…...

【EDA工具使用】——VCS和Verdi的联合仿真的简单使用
目录 1.芯片开发所需的工具环境 2.编译仿真工具 3.三步式混合编译仿真(最常用)编辑 4.两步式混合编译仿真编辑 5.VCS的使用 6.verdi的使用 1.产生fsdb文件的两种方法编辑 1.芯片开发所需的工具环境 2.编译仿真工具 3.三步式混合编译仿真…...

【Java学习笔记】4.Java 对象和类
前言 本章介绍Java的对象和类。 Java 对象和类 Java作为一种面向对象语言。支持以下基本概念: 多态继承封装抽象类对象实例方法重载 本节我们重点研究对象和类的概念。 对象:对象是类的一个实例(对象不是找个女朋友)&#x…...

39. 实战:基于api接口实现视频解析播放(32接口,窗口化操作,可导出exe,附源码)
目录 前言 目的 思路 代码实现 需要导入的模块 1. 导入解析网站列表,实现解析过程 2. 设计UI界面 3. 设置窗口居中和循环执行 4. 注意事项 完整源码 运行效果 总结 前言 本节将类似34. 实战:基于某api实现歌曲检索与下载(附完整…...

基于灵动 MM32 微控制器的便携式血氧仪方案
基于灵动 MM32 微控制器的便携式血氧仪: - Cortex-M0() 最高主频 72MHz 可实现血氧饱和度信号采集、算法操作和 LED 显示操作 - 高性能的 1Msps 12b ADC 能对光电采样结果进行大数据量的暂存和处理,提高采样的效率并有助于对结果做高精度的计算 - 100…...

2022秋-2023-中科大-数字图像分析-期末考试试卷回忆版
今天晚上刚考完,心累,在这里继续授人以渔(仅供参考,切勿对着复习不看ppt,ppt一定要过两遍)。 注意:往年的经验贴,到此为止,全部作废,一个没考。千万不要只对着复习,SIFT没考&#x…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...

Unity VR/MR开发-VR开发与传统3D开发的差异
视频讲解链接:【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...

MeshGPT 笔记
[2311.15475] MeshGPT: Generating Triangle Meshes with Decoder-Only Transformers https://library.scholarcy.com/try 真正意义上的AI生成三维模型MESHGPT来袭!_哔哩哔哩_bilibili GitHub - lucidrains/meshgpt-pytorch: Implementation of MeshGPT, SOTA Me…...