aspeed2600 GPIO分析与适配ipmitool power status, ipmitool power on/off
1.说明
本节以x86-power-control/src/power_control.cpp
为基础,分析整个GPIO
的调用流程,实现简单的ipmitool power on/off
,ipmitool power status
的管理。
- 1.资源:
x86-power-control
:https://github.com/openbmc/x86-power-control - 2.相关文件:
meta-phosphor/recipes-x86/chassis/x86-power-control_git.bb
- 3.本节涉及到的代码可以参考: https://gitee.com/wit_yuan/sdk_v09.01_ast2600/blob/yuan_support_power_status
备注:
为了加速编译过程,在文件build/ast2600-default/conf/local.conf
中添加参数:
BB_NUMBER_THREADS ='16'
PARALLEL_MAKE ='-j 4'
BB_NO_NETWORK="1"
2.分析x86-power-control
在文件:power_control.cpp
中可以看到调用流程:
build/ast2600-default/workspace/sources/x86-power-control/src/power_control.cpp
main()
---> loadConfigValues()---> 读取文件: "/usr/share/x86-power-control/power-config-host" + power_control::node + ".json"---> 读取 tempGpioData->lineName = gpioConfig["LineName"];
---> // Request PS_PWROK GPIO events
---> requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,psPowerOKLine, psPowerOKEvent)---> gpioLine = gpiod::find_line(name);---> gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
因此,需要关注2个函数:
gpioLine = gpiod::find_line(name)
gpioLine.request(...)
3.分析libgpiod
下载好libgpiod
库,实际跟踪文件:build/ast2600-default/workspace/sources/libgpiod/bindings/cxx/line.cpp
中的函数:
line find_line(const ::std::string& name)
{line ret;for (auto& it: make_chip_iter()) {ret = it.find_line(name);if (ret)break;}return ret;
}
调用流程为:
build/ast2600-default/workspace/sources/libgpiod/bindings/cxx/line.cpp
line find_line(const ::std::string& name)---> for (auto& it: make_chip_iter()) {---> ret = it.find_line(name); // = line chip::find_line(const ::std::string& name) const---> ::gpiod_line* handle = ::gpiod_chip_find_line(this->_m_chip.get(), name.c_str());---> return handle ? line(handle, *this) : line();build/ast2600-default/workspace/sources/libgpiod/bindings/cxx/iter.cpp
chip_iter make_chip_iter(void)
---> ::gpiod_chip_iter* iter = ::gpiod_chip_iter_new();
---> return chip_iter(iter);chip_iter::chip_iter(::gpiod_chip_iter *iter) : _m_iter(iter, chip_iter_deleter)
---> ::gpiod_chip* first = ::gpiod_chip_iter_next_noclose(this->_m_iter.get());
---> this->_m_current = chip(first);build/ast2600-default/workspace/sources/libgpiod/lib/iter.c
struct gpiod_chip_iter *gpiod_chip_iter_new(void)
---> num_chips = scandir("/dev", &dirs, dir_filter, alphasort);
---> iter->num_chips = num_chips;
---> iter->offset = 0;
---> iter->chips[i] = gpiod_chip_open_by_name(dirs[i]->d_name);
根据上面的内容,实际上C++
调用到C
,有几个函数:
build/ast2600-default/workspace/sources/libgpiod/lib/helpers.c
struct gpiod_line *gpiod_chip_find_line(struct gpiod_chip *chip, const char *name)
---> iter = gpiod_line_iter_new(chip);---> iter->num_lines = gpiod_chip_num_lines(chip);---> iter->lines[i] = gpiod_chip_get_line(chip, i);build/ast2600-default/workspace/sources/libgpiod/lib/core.c---> gpiod_line_update(line); //!!!!重要!!!---> struct gpioline_info info;---> rv = ioctl(line->chip->fd, GPIO_GET_LINEINFO_IOCTL, &info);---> strncpy(line->name, info.name, sizeof(line->name));---> strncpy(line->consumer, info.consumer, sizeof(line->consumer));
---> gpiod_foreach_line(iter, line) {---> tmp = gpiod_line_name(line);---> if (tmp && strcmp(tmp, name) == 0) { //找到了 line....---> ...
注意留意函数:gpiod_line_update()
里面使用了内核结构体:
build/ast2600-default/workspace/sources/linux-aspeed/include/uapi/linux/gpio.h
struct gpioline_info {__u32 line_offset;__u32 flags;char name[GPIO_MAX_NAME_SIZE];char consumer[GPIO_MAX_NAME_SIZE];
};
应用层用到了line->name
. 这个line_name
又是从驱动/内核传递而来。应用层在build/ast2600-default/workspace/sources/x86-power-control/config/power-config-host0.json
中定义了一个!!LineName!!
.
函数gpiod_chip_open_by_name()
:
build/ast2600-default/workspace/sources/libgpiod/lib/helpers.c
struct gpiod_chip *gpiod_chip_open_by_name(const char *name)
---> rv = asprintf(&path, "/dev/%s", name);
---> chip = gpiod_chip_open(path);
函数gpiod_chip_open()
调用的是:
build/ast2600-default/workspace/sources/libgpiod/lib/core.c
struct gpiod_chip *gpiod_chip_open(const char *path)
---> fd = open(path, O_RDWR | O_CLOEXEC);
---> if (!is_gpiochip_cdev(path)) goto err_close_fd;
---> rv = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &info);
---> chip->fd = fd;
---> chip->num_lines = info.lines;
---> strncpy(chip->name, info.name, sizeof(chip->name));
---> ...
根据ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &info)
需要找到内核层。
4.分析内核层
4.1 分析dts
当前文件build/ast2600-default/workspace/sources/linux-aspeed/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
中写的gpio
为:
gpio0: gpio@1e780000 {#gpio-cells = <2>;gpio-controller;compatible = "aspeed,ast2600-gpio";reg = <0x1e780000 0x400>;interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;gpio-ranges = <&pinctrl 0 0 208>;ngpios = <208>;clocks = <&syscon ASPEED_CLK_APB2>;interrupt-controller;#interrupt-cells = <2>;};
根据aspeed,ast2600-gpio
可以定位到文件build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpio-aspeed.c
.
4.2 gpio
驱动
4.2.1 gpiolib.c
文件:build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpiolib.c
作为实际的入口调用,可以看到函数gpiolib_dev_init()
:
static int __init gpiolib_dev_init(void)
{
...
---> ret = bus_register(&gpio_bus_type);
---> ret = driver_register(&gpio_stub_drv);
---> ret = alloc_chrdev_region(&gpio_devt, 0, GPIO_DEV_MAX, GPIOCHIP_NAME);
---> gpiochip_setup_devs();
}
core_initcall(gpiolib_dev_init);
以及函数static void gpiochip_setup_devs(void)
static void gpiochip_setup_devs(void)
---> ret = gpiochip_setup_dev(gdev);
函数gpiochip_setup_dev()
:
static int gpiochip_setup_dev(struct gpio_device *gdev)
---> ret = gcdev_register(gdev, gpio_devt);
---> ret = gpiochip_sysfs_register(gdev);
比较重要的是一个宏定义:
#ifdef CONFIG_GPIO_CDEV
#define gcdev_register(gdev, devt) gpiolib_cdev_register((gdev), (devt))
#define gcdev_unregister(gdev) gpiolib_cdev_unregister((gdev))
#else
/** gpiolib_cdev_register() indirectly calls device_add(), which is still* required even when cdev is not selected.*/
#define gcdev_register(gdev, devt) device_add(&(gdev)->dev)
#define gcdev_unregister(gdev) device_del(&(gdev)->dev)
#endif
根据该宏定义定义的函数gpiolib_cdev_register()
,实际就跳到文件:build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpiolib-cdev.c
中。
4.2.2 gpiolib-cdev.c
文件build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpiolib-cdev.c
作为整个gpio
字符驱动的核心入口.
函数gpiolib_cdev_register()
:
int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt)
---> cdev_init(&gdev->chrdev, &gpio_fileops);
结构体gpio_fileops
定义如下:
static const struct file_operations gpio_fileops = {.release = gpio_chrdev_release,.open = gpio_chrdev_open,.poll = lineinfo_watch_poll,.read = lineinfo_watch_read,.owner = THIS_MODULE,.llseek = no_llseek,.unlocked_ioctl = gpio_ioctl,
#ifdef CONFIG_COMPAT.compat_ioctl = gpio_ioctl_compat,
#endif
};
对于gpio_ioctl
:
static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
---> call_ioctl_locked(file, cmd, arg, cdev->gdev,gpio_ioctl_unlocked);
实际gpio_ioctl_unlocked()
:
static long gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
---> case GPIO_GET_CHIPINFO_IOCTL:---> return chipinfo_get(cdev, ip);
这就是前面函数struct gpiod_chip *gpiod_chip_open(const char *path)
实际调用的内核函数。
另外,函数chipinfo_get()
内容如:
static int chipinfo_get(struct gpio_chardev_data *cdev, void __user *ip)
---> strscpy(chipinfo.name, dev_name(&gdev->dev), sizeof(chipinfo.name));
---> strscpy(chipinfo.label, gdev->label, sizeof(chipinfo.label));
---> chipinfo.lines = gdev->ngpio;
---> copy_to_user(ip, &chipinfo, sizeof(chipinfo))
如此,可以获取到gpio chip
包含的gpio line
数量。
4.2.3 gpio-aspeed.c
在dts
中配置了:compatible = "aspeed,ast2600-gpio";
之后,会经过一系列流程之后,调用到文件:
build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpio-aspeed.c
中的static int __init aspeed_gpio_probe(struct platform_device *pdev)
:
static int __init aspeed_gpio_probe(struct platform_device *pdev)
---> err = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpio);
---> rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
注意,devm_gpiochip_add_data()
在文件:build/ast2600-default/workspace/sources/linux-aspeed/include/linux/gpio/driver.h
中定义,定义如:
#ifdef CONFIG_LOCKDEP
#define gpiochip_add_data(gc, data) ({ \static struct lock_class_key lock_key; \static struct lock_class_key request_key; \gpiochip_add_data_with_key(gc, data, &lock_key, \&request_key); \})
#define devm_gpiochip_add_data(dev, gc, data) ({ \static struct lock_class_key lock_key; \static struct lock_class_key request_key; \devm_gpiochip_add_data_with_key(dev, gc, data, &lock_key, \&request_key); \})
#else
#define gpiochip_add_data(gc, data) gpiochip_add_data_with_key(gc, data, NULL, NULL)
#define devm_gpiochip_add_data(dev, gc, data) \devm_gpiochip_add_data_with_key(dev, gc, data, NULL, NULL)
#endif /* CONFIG_LOCKDEP */
只需要关注函数devm_gpiochip_add_data_with_key()
:
build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpiolib-devres.c
devm_gpiochip_add_data_with_key()build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpiolib.c
---> gpiochip_add_data_with_key(gc, data, lock_key, request_key);---> ret = dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id);---> ret = gpiochip_get_ngpios(gc, &gdev->dev);---> ret = gpiochip_set_desc_names(gc);---> ret = gpiochip_set_names(gc);---> count = device_property_string_array_count(dev, "gpio-line-names");---> ret = device_property_read_string_array(dev, "gpio-line-names",...---> gdev->descs[i].name = names[chip->offset + i];
---> devm_add_action_or_reset(dev, devm_gpio_chip_release, gc);
对于应用层调用ioctl(line->chip->fd, GPIO_GET_LINEINFO_IOCTL, &info);
,流程如:
build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpiolib-cdev.c
static long gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
---> case GPIO_GET_LINEINFO_IOCTL:---> return lineinfo_get_v1(cdev, ip, false);---> struct gpio_desc *desc;---> desc = gpiochip_get_desc(cdev->gdev->chip, lineinfo.line_offset);---> gpio_desc_to_lineinfo(desc, &lineinfo_v2);//struct gpio_desc *desc---> info->offset = gpio_chip_hwgpio(desc);---> if (desc->name) strscpy(info->name, desc->name, sizeof(info->name));---> gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo);---> memcpy(info_v1->name, info_v2->name, sizeof(info_v1->name));---> memcpy(info_v1->consumer, info_v2->consumer, sizeof(info_v1->consumer));---> copy_to_user(ip, &lineinfo, sizeof(lineinfo)
从以上代码可以看出,应用层用的是LineName
, 驱动用的是:gpio-line-names
。因此,适配的时候,注意将这2个名字匹配好。
因此,文件build/ast2600-default/workspace/sources/x86-power-control/config/power-config-host0.json
中定义如下:
"gpio_configs": [{"Name": "IdButton","LineName": "ID_BUTTON","Type": "GPIO","Polarity": "ActiveLow"},{"Name": "PowerOk","LineName": "PS_PWROK","Type": "GPIO","Polarity": "ActiveLow"},{"Name": "PowerOut","LineName": "POWER_BUTTON","Type": "GPIO","Polarity": "ActiveLow"}],
对应,文件build/ast2600-default/workspace/sources/linux-aspeed/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
内容定义如下:
&gpio0 {status = "okay";gpio-line-names = /*A0~A7*/"A0","A1","A2","","","","ID_BUTTON","",/*B0~B7*/"POWER_BUTTON","B1","B2","","","","","",/*C0~C7*/"C0","C1","C2","","","","","",/*D0~D7*/"D0","D1","D2","","","","","",/*E0~E7*/"E0","E1","E2","","","","","",/*F0~F7*/"F0","F1","PS_PWROK","","","","","",/*G0~G7*/"G0","G1","G2","","","","","",/*H0~H7*/"H0","","","","","","","",/*I0~7*/"I0","","I2","","","","","",/*J0~7*/"J0","J1","","","","","","",/*K0~7*/"K0","K1","","","","","","",/*L0~7*/"","","","","","","","",/*M0~7*/"","","","","","","","",/*N0~7*/"","","","","","","","",/*O0~7*/"","","","","","","","",/*P0~7*/"","","","","","","","",/*Q0~7*/"","","","","","","","",/*R0~7*/"","","","","","","","",/*S0~7*/"","","","","","","","",/*T0~7*/"","","","","","","","",/*U0~7*/"","","","","","","","",/*V0~7*/"","","","","","","","",/*W0~7*/"","","","","","","","",/*X0~7*/"","","","","","","","",/*Y0~7*/"","","","","","","","",/*Z0~7*/"","","","","","","","";
};
注意,将gpio-line-names
的数量控制在208
或者以内即可。
5.适配power status,power on/off
5.1 修改dts
在适配中,发现在文件:build/ast2600-default/workspace/sources/x86-power-control/src/power_control.cpp
中报错,报错点为:gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
,报错内容为:
# journalctl | grep power
Failed to request events for PS_PWROK: error requesting GPIO lines: Invalid argument
实际追踪下来,发现具体是在文件build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpiolib-cdev.c
中的函数lineevent_create()
报错,具体点为函数gpiod_request_user()
:
build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpiolib-cdev.c
static int lineevent_create(struct gpio_device *gdev, void __user *ip)
---> copy_from_user(&eventreq, ip, sizeof(eventreq))
---> desc = gpiochip_get_desc(gdev->chip, offset);
---> ret = gpiod_request_user(desc, le->label);
其中,函数gpiod_request_user()
定义如下:
build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpiolib.h
static inline int gpiod_request_user(struct gpio_desc *desc, const char *label)
---> ret = gpiod_request(desc, label);
其中,函数gpiod_request()
定义如下:
build/ast2600-default/workspace/sources/linux-aspeed/drivers/gpio/gpiolib.c
int gpiod_request(struct gpio_desc *desc, const char *label)
---> int ret = -EPROBE_DEFER;
---> if (try_module_get(desc->gdev->owner)) {---> ret = gpiod_request_commit(desc, label);---> if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {---> desc_set_label(desc, label ? : "?");else---> ret = -EBUSY;---> goto out_free_unlock;---> }---> if (gc->request) {---> if (gpiochip_line_is_valid(gc, offset))---> ret = gc->request(gc, offset); //aspeed_gpio_request---> else----> ...--->}
---> }
再次查看BMC
日志,发现如下内容:
[ 72.729136] aspeed-g6-pinctrl 1e6e2000.syscon:pinctrl: pin D23 already requested by 1e740100.sdhci; cannot claim for 1e780000.gpio:554
[ 72.742714] aspeed-g6-pinctrl 1e6e2000.syscon:pinctrl: pin-42 (1e780000.gpio:554) status -22
对比build/ast2600-default/workspace/sources/linux-aspeed/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
文件,发现是GPIO
被占用了。
以上,设置完成之后,通过ipmitool power status
查看系统状态:
# ipmitool power status
Chassis Power is on
相关文章:

aspeed2600 GPIO分析与适配ipmitool power status, ipmitool power on/off
1.说明 本节以x86-power-control/src/power_control.cpp为基础,分析整个GPIO的调用流程,实现简单的ipmitool power on/off,ipmitool power status的管理。 1.资源:x86-power-control:https://github.com/openbmc/x86-power-control2.相关文件: meta-ph…...
在C#中配置ini文件以及封装ini类
在C#中使用 DllImport 属性从 kernel32.dll 导入函数来写入和读取Windows的INI文件,你可以使用 WritePrivateProfileString 来写入数据,使用 GetPrivateProfileString 来读取数据。 以下是如何使用这些函数的示例: 写入INI文件 using Syst…...

使用git上传代码到github
1、设置用户名及邮箱 git config user.name"你的用户名"git config user.email"xxxxx.com" 2、查看配置 git config -l 3、生成秘钥 ssh-keygen -t rsa 根据上图中红框标出的id_rsa.pub地址,找到它,使用txt文件打开,复…...

滚珠花键:新能源汽车传动系统的核心动力传递者
在日常生活中,汽车已经成为了必不可少的交通工具,尤其是新能源汽车。而滚珠花键作为传动系统中的重要组成部分,在传动系统方面的作用不容忽视。 随着科技的不断发展,汽车行业也在不断进步,滚珠花键作为高精度的机械传动…...
LeetCode 149, 347, 31
文章目录 149. 直线上最多的点数题目链接标签思路总体思路如何判断 一个点 在 由两点确定的直线 上 代码 347. 前 K 个高频元素题目链接标签思路代码 31. 下一个排列题目链接标签思路代码 149. 直线上最多的点数 题目链接 149. 直线上最多的点数 标签 几何 数组 哈希表 数学…...
操作系统(信号处理)
一、信号介绍 什么是中断: 当进程接收到消息后中止当前正在执行的任务,转而执行其它任务,等待其它任务执行完毕后再返回继续执行。这种执行模式称为中断,分为硬件中断和软件中断两种 什么是信号: 信号是UNIX、类UNI…...

[MRCTF2020]Ezpop
[MRCTF2020]Ezpop 题目是pop,考的其实就是pop链,可以自己先学学,啥也不会QAQ php反序列化之pop链_pop3.phpwelcome-CSDN博客 POP 面向属性编程(Property-Oriented Programing) 常用于上层语言构造特定调用链的方法,与二进制利用…...

24暑假算法刷题 | Day27 | 贪心算法 I | LeetCode 455. 分发饼干,376. 摆动序列,53. 最大子数组和
目录 455. 分发饼干题目描述题解 376. 摆动序列题目描述题解 53. 最大子数组和题目描述题解 455. 分发饼干 点此跳转题目链接 题目描述 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i&#x…...
Golang 的空接口有什么用?
空接口在 Go 语言中具有多种重要用途: 实现通用的数据结构 例如,可以创建一个包含空接口类型元素的切片或映射,从而能够存储不同类型的值。这在处理多种未知类型的数据时非常有用。比如,一个日志系统可能会将不同类型的日志消息&a…...

计算机毕业设计选题推荐-课程教学平台-Java/Python项目实战
✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...

健身日记之倒立俯卧撑学习——起始日2024.6.4
文章目录 目录 前言上期预期 昔日计划 新目标计划 瓶颈突破尝试 参考视频及文章 前言 两个月过去了,已经有所突破了,但是比较预期还是有较大差距,忘记更新csdn了,平时抖音视频号记录的多一些。 上期预期 2024.6.4开始尝试突…...

pikachu文件包含漏洞
一:漏洞基础 程序在引用文件的时,引用的文件名存在可控的情况,传入的文件名没有经过合理的校验或校验不严,从而操作了预想之外的文件,就有可能导致文件泄漏和恶意的代码注入; 文件包含漏洞概念 在PHP程序…...

09.FreeRTOS时间片调度与任务相关函数
文章目录 09. FreeRTOS时间片调度与任务相关函数1. FreeRTOS时间片调度2. 任务状态查询API函数3. 任务时间统计API函数 09. FreeRTOS时间片调度与任务相关函数 1. FreeRTOS时间片调度 时间片调度简介: 时间片调度实验流程: 核心代码: 开…...

git分支介绍
git branch 查看当前分支情况 可以看见当前只有一个分支叫main,也就是默认分支,可以理解为树的主干,git早期版本中默认分支叫master 命令行创建一个新分支 git branch [分支名]在创建之后,如果需要切换到新分支需要git switc…...

vm虚拟机下安装CentOS7系统
VMware16安装CentOS7 1.启动之前安装的VM 具体VMware安装过程 2.配置Linux(centos7)的镜像文件 选择安装镜像文件 4.开启虚拟机 开始读秒安装 选择安装过程中使用的语言,这里选择英文、键盘选择美式键盘。点击Continue 首先设置时间…...

python-报数(赛氪OJ)
[题目描述] 有 n 人围成一圈,顺序排号。 从第 1 个人开始报数(从 1 到 3 报数),凡是报到 3 的人退出圈子,问最后留下的是原来的第几号的那位。输入格式: 初始人数 n 。输出格式: 最后一人的初始…...

灵办AI:智能插件,办公与编程的得力助手
目录 引言一、灵办AI:智能化的办公伙伴二、编程能力:🔥代码阅读,学习助手🔥1、代码解读2、代码续写3、代码优化 三、插件端对话功能:智能交互,流畅体验四、翻译功能:一键翻译&#x…...

食家巷小程序:传统面点与平凉特产的美味盛宴
在美食的世界里,总有一些角落等待着我们去探索,而食家巷小程序就是这样一个为您开启美食宝藏的钥匙。 一、传统面点,传承千年的美味 食家巷小程序为您呈现了种类丰富的传统面点,每一款都蕴含着深厚的历史和文化底蕴。 平凉锅盔&…...

矢量文件坐标转换:2000坐标系转换为wgs84坐标系,具体代码实现
最近在处理矢量样本的时候,遇到一些shp文件的坐标系为2000坐标,需要统一地把非WGS84坐标系的矢量转换为WGS84坐标系。 本文记录一下如何进行2000坐标系转化为wgs84坐标系的过程。 在处理矢量数据转换的过程中,有几个关键步骤确保了数据的有效…...

MySQL-InnoDB引擎
目录 逻辑存储结构 架构 概述 内存结构 Buffer Pool(缓冲池) Change Buffer(更改缓冲区) Adaptive Hash Index(自适应hash索引) Log Buffer(日志缓冲区) 磁盘结构 System T…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...