GT928 TP驱动跟读及虚拟按键上报解析

news2025/2/25 9:44:37
  • 目前公司TP常用一套代码。MTK 平台使用.ko形式加载,所以跟读一下加深理解。
static struct i2c_driver tpd_i2c_driver = {
	.driver = {
		.of_match_table = of_match_ptr(gt9xx_dt_match),
	},
	.probe = tpd_i2c_probe,
	.remove = tpd_i2c_remove,
	.detect = tpd_i2c_detect,
	.driver.name = "gt9xx",
	.id_table = tpd_i2c_id,
	.address_list = (const unsigned short *)forces,
};

static int __init tpd_driver_init(void)
{
	print_info("gt9xx touch panel driver init\n");

	if (i2c_add_driver(&tpd_i2c_driver) != 0) {
		print_info("unable to add i2c driver.\n");
		return -1;
	}

	return 0;
}

static void __exit tpd_driver_exit(void)
{
	print_info("gt9xx touch panel driver exit\n");

	i2c_del_driver(&tpd_i2c_driver);
}

使用i2c_add_driver();去加载i2c驱动(由于同一套代码需要兼容很多的屏和TP,导致TP IC需要兼容不同厂商的不同IC)如果i2c地址一样并且使用i2c_add_driver()成功注册了i2c设备并且probe不报错,那么这时候兼容就会有问题(比如gt2xx厂商给的驱动是在module_init调用一个自定义函数去实现goodix_i2c_bus_init,然后注册platform_driver_register(&goodix_ts_driver))。这样就算是给了不同的屏加载驱动的时候platform_driver_register 的probe会报错,但是goodix_i2c_bus_init 调用的i2c_add_driver注册的设备probe就不会报错,那么sys/class/i2c-0/0-005d这个设备就会注册成功,导致后面的驱动i2c_add_driver()失败。)

eg:

static int __init goodix_ts_core_init(void)
{
	int ret;

	ts_info("Core layer init:%s", GOODIX_DRIVER_VERSION);
#ifdef CONFIG_TOUCHSCREEN_GOODIX_BRL_SPI
	ret = goodix_spi_bus_init();
#else
	ret = goodix_i2c_bus_init();
#endif
	if (ret) {
		ts_err("failed add bus driver");
		return ret;
	}
	return platform_driver_register(&goodix_ts_driver);
}
----->
int goodix_i2c_bus_init(void)
{
	ts_info("Goodix i2c driver init");
	return i2c_add_driver(&goodix_i2c_driver);
}

解决办法就是先加载那个i2c probe会失败的那个,但是解决中又遇到了,reset时序的问题,如果先加载i2c probe会失败的那个后面的时序会对不上。(由于是采用.ko形式存在内核中,如果probe失败执行rmmod那么下一个驱动就可以成功这样就可以写一个shell脚本,在驱动使用DEVICE_ATTR(attr*)show 一个全局变量 shell中使用cat 去读对应节点的值,如果为0就是驱动还没加载完的等一下,如果为1 就是这个TP就是我的驱动的你不用rmmod 如果为-1就是执行rmmod 要在init.rc里面去执行这个.sh脚本)

接下来看GT928.c的驱动:

在这里插入图片描述
** 1.gt9xx_get_gpio_info()以及init_powerup();是获取pinctl的gpio并设置gpio状态 **
使用了devm_pinctrl_get(dev);
pinctrl_lookup_state
pinctrl_select_state
正常是要使用devm_pinctrl_put(dev)去释放gpio资源的,也可以不使用因为驱动报错之后会自动回收gpio资源。
** 2. gtp_i2c_read(0x8140寄存器,并将读取的值放在test_buf[3~12里面根据表格就是读的product_ID])
在这里插入图片描述
** 3 tp_init_param(test_data, 16); **
初始话tp参数,这里使用了module_param() 从insmod里面获取参数

insmod /vendor/lib/modules/gt9xx_driver.ko screen_inch=${ro.hw.lcm.inch:-0}

就是获取到TP是多少寸的。

void tp_init_param(u8 *buf, int len)
{
	struct fb_info *fb_info = registered_fb[0];
	char *p = virtual_keys;  //指针P指向定义的虚拟按键buf

	p += sprintf(p, "# GT9xx %s' :%02X %02X %02X %02X %02X, %02X %02X, %02X %02X, %02X.\n", screen_inch,
					buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12]);

	if (fb_info) {
		pr_err("GT9xx get LCM size %dx%d\n", fb_info->var.xres, fb_info->var.yres);
	}
	/*
	* 通过之前gtp_i2c_read读取的data[0] data[1] 寄存器里的值判断该TP的信号去设置虚拟按键区域的大小 buf[3~12]
	* __stringify函数的作用是 C 的宏,它在编译时将表达式转换为字符串文本。调试包含变量或常量值的输出
	* 这样就会通过sprintf把数据打印并存储到*P中。
	*/
	if(buf[3] == 0x32 && buf[4] == 0x37 && buf[5] == 0x31 && buf[6] == 0x40 && buf[7] == 0x10 && buf[8] == 0x31 \
		&& buf[9] == 0x4 && buf[10] == 0x58 && buf[11] == 0x2 && buf[12] == 0x0)    //NO 1
	{
		p += sprintf(p, "# build %s at %d\n", __TIME__, __LINE__);
		p += sprintf(p,

		/*
		* 虚拟按键填充规则:当然,在这里tpd keys这个定义key的数组和定义区域的tpd keys dim要准确的填充才可以的。具体的填充的规则如下:
		*	每一个虚拟按键有六个参数:
		*	1、0x01: A version code. Must always be Ox91.
		*	2、<Linux key code>: The Linux key code of the virtual key.
		*	3、<centerx>: The X pixel coordinate of the center of the virtual key.
		*	4、<centerY>: The Y pixel coordinate of the center of the virtual key.
		*	5、<width>: The width of the virtual key in pixels.
		*	6、<height>: The height of the virtual key in pixels.6
		*   EV_KEY:KEY_CLOSECD:1065:107:50:40
		* 	EV_KEY:通过_set_bit去设置input数据类型为按键
		*	KEY_CLOSECD:键值都在内核定义好了,内核上报之后会进入对应的上层进行处理。
		*   centerx: 按键中心X轴坐标  : centerY 按键中心Y轴坐标  : width 按键宽 :height 按键长 (通过这四个值的数据确定一个虚拟按键在TP上的位置)
		*   
		*/
            __stringify(EV_KEY) ":" __stringify(KEY_CLOSECD)    ":1065:107:50:40\n"
            __stringify(EV_KEY) ":" __stringify(KEY_HOMEPAGE)   ":1065:155:50:40\n"
            __stringify(EV_KEY) ":" __stringify(KEY_BACK)       ":1065:238:50:40\n"
            __stringify(EV_KEY) ":" __stringify(KEY_VOLUMEUP)   ":1065:320:50:40\n"
            __stringify(EV_KEY) ":" __stringify(KEY_VOLUMEDOWN) ":1065:380:50:40\n");
	}

这里会设置虚拟按键的区域以及键值

** 4、注册设备以及文件系统 **
kobject_create_and_add()
sysfs_create_group()
input_allocate_device
** 5、设置input 结构体的一些成员 **
gtp_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
这表示这个设备支持SYN KEY ABS设备 同步 键盘 绝对坐标事件

#if GTP_HAVE_TOUCH_KEY
	static const u16 touch_key_array[] = {KEY_F3, KEY_F4, KEY_F5, KEY_F6};
	#define GTP_MAX_KEY_NUM	 (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
#endif

#if GTP_HAVE_TOUCH_KEY
	for (index = 0; index < GTP_MAX_KEY_NUM; index++) {
		input_set_capability(gtp_dev, EV_KEY, touch_key_array[index]);
	}
#endif

== 设置输入设备的功能函数。这里有一个疑问?为什么touch_key_array[] = {KEY_F3, KEY_F4, KEY_F5, KEY_F6};写死了为const,而在为什么又在3 tp_init_param()函数中写出KEY_CLOSECD等key值???==
填充dev结构体的一些成员信息

	/* 设置绝对轴输入事件的范围参数: 最小值 最大值 模糊筛选:0 平坦过滤:0 */
	input_set_abs_params(gtp_dev, ABS_X, 0, screen_size[0], 0, 0);
	input_set_abs_params(gtp_dev, ABS_Y, 0, screen_size[1], 0, 0);
	input_set_abs_params(gtp_dev, ABS_PRESSURE, 0, 255, 0, 0);
	input_set_abs_params(gtp_dev, ABS_MT_POSITION_X, 0, screen_size[0], 0, 0);
	input_set_abs_params(gtp_dev, ABS_MT_POSITION_Y, 0, screen_size[1], 0, 0);
	input_set_abs_params(gtp_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
	input_set_abs_params(gtp_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
	//input_set_abs_params(gtp_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
	input_set_abs_params(gtp_dev, ABS_MT_TRACKING_ID, 0, GTP_MAX_TOUCH, 0, 0);

	sprintf(phys, "input/ts");
	gtp_dev->name = "TS_GT9xx";
	gtp_dev->phys = phys;
	gtp_dev->id.bustype = BUS_I2C;
	gtp_dev->id.vendor = 0xDEAD;
	gtp_dev->id.product = 0xBEEF;
	gtp_dev->id.version = 10427;

	ret = input_register_device(gtp_dev);  //注册Input设备
	if (ret) {
		pr_err("Register %s input device failed", gtp_dev->name);
		return -ENODEV;
	}
	fb_register_client(&pm_event_notifier);

** 创建内核线程,监听中断事件 **

	thread = kthread_run(touch_event_handler, 0, TPD_DEVICE);  //开辟内核多线程,用于事件监听上报

	if (IS_ERR(thread)) {
		err = PTR_ERR(thread);
		print_info(TPD_DEVICE " failed to create kernel thread: %d", err);
		return -1; 
	}
	tpd_irq_registration(); //注册中断

首先执行touch_event_handler函数

static int touch_event_handler(void *unused)
{
	struct sched_param param = { .sched_priority = 4 };
	sched_setscheduler(current, SCHED_RR, &param);

	do {
		set_current_state(TASK_INTERRUPTIBLE);
		wait_event_interruptible(waiter, tpd_flag || kthread_should_stop());
		set_current_state(TASK_RUNNING);

		if (tpd_flag)
			report_data_handle();
		tpd_flag = 0;

	} while (!kthread_should_stop());

	return 0;
}

它会阻塞在wait_event_interruptible()函数这里等待又事件上报
参数:等待队列头waiter
tpd_flag || kthread_should_stop() 当这个变为true时开始执行下一步。
一直阻塞在这里直到tpd_irq_registration中断注册函数调用。

static int tpd_irq_registration(void)
{
	struct device_node *node = NULL;
	int ret = 0;
	u32 ints[2] = { 0, 0 };
	const int32_t irqtype = override_irq_type > 0 ? override_irq_type : irq_type;

	node = of_find_compatible_node(NULL, NULL, "mediatek,cap_touch");

	if (node) {
		of_property_read_u32_array(node, "debounce", ints, ARRAY_SIZE(ints));
		print_info("debounce = %d %d\n", ints[0],ints[1]);

		gpio_set_debounce(ints[0], ints[1]);

		/*touch_irq = gpio_to_irq(tpd_int_gpio_number);*/
		touch_irq = irq_of_parse_and_map(node, 0);//40
		print_info("---cgx--#####touch_irq number %d\n", touch_irq);
		if (irqtype == GT_INT_TRIGGER_RISING) {/* EINTF_TRIGGER */
			print_info("GT_INT_TRIGGER_RISING\n");
			ret = request_irq(touch_irq, tpd_interrupt_handler, IRQF_TRIGGER_RISING, TPD_DEVICE, NULL);
			if (ret > 0)
				print_info("tpd request_irq IRQ LINE NOT AVAILABLE!.");
		} else {
			print_info("GT_INT_TRIGGER_FAILING\n");
			ret = request_irq(touch_irq, tpd_interrupt_handler, IRQF_TRIGGER_FALLING, TPD_DEVICE, NULL);
			if (ret > 0)
				print_info("tpd request_irq IRQ LINE NOT AVAILABLE!.");
		}
	} else {
		print_info("tpd request_irq can not find touch eint device node!.");
	}

	return ret;
}

核心使用了request_irq(handle…,rising) 上升沿触发。
看中断处理函数

static irqreturn_t tpd_interrupt_handler(int irq, void *dev_id)
{
	tpd_flag = 1;
	wake_up_interruptible(&waiter);
	return IRQ_HANDLED;
}
wake_up_interruptible是 Linux 内核中的一个函数,用于唤醒在给定等待队列上等待的所有进程,
并将它们标记为中断。此函数通常与 结合使用,使调用进程进入休眠状态,直到满足给定条件。
当满足条件时,内核将调用以唤醒等待该条件的任何进程。wait_event_interruptible  wake_up_interruptible

这时候线程就不阻塞了。然后走到
report_data_handle

static void report_data_handle(void)
{
	u8	end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0};
	u8	point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF};  //触摸数据寄存器0x814E  {0x81,0x4E}
	u8	touch_num = 0;
	u8	finger = 0;
	static u8 pre_touch = 0;
	static u8 pre_key = 0;
	static u8 need_calibrate = 0;
	u8	key_value = 0;
	u8 *coor_data = NULL;
	s32 id = 0;
	s32 i  = 0;
	s32 ret = -1;

	mdelay(5);

	ret = gtp_i2c_read(i2c_client, point_data, 12);  
	if (ret < 0) {
		pr_err("I2C transfer error. errno:%d\n ", ret);
		msleep_interruptible(800);
		init_powerup();
		msleep_interruptible(200);
		return;
	}

	finger = point_data[GTP_ADDR_LENGTH];

	if ((finger & 0x80) == 0) {
		goto exit_work_func;
	}

	touch_num = finger & 0x0f;

	// print_info("====touch_num = %d====\n", touch_num);

	if (touch_num > GTP_MAX_TOUCH) {
		goto exit_work_func;
	}

	if (touch_num > 1) {
		 //如果是多点触摸就 读ponit 2的寄存器值 0x814E +10 =0x8158 8158~815B 存储着xy的坐标值 最多支持5点触摸,即最多有point5的寄存器存储触摸数据
		u8 buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff}; 
		ret = gtp_i2c_read(i2c_client, buf, 2 + 8 * (touch_num - 1));
		memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
	}

#if GTP_HAVE_TOUCH_KEY
	key_value = point_data[3 + 8 * touch_num];

	if (key_value || pre_key)
	{
		for (i = 0; i < GTP_MAX_KEY_NUM; i++)
		{
			input_report_key(gtp_dev, touch_key_array[i], key_value & (0x01<<i));    
		}
		touch_num = 0;
		pre_touch = 0;
	}
#endif

	pre_key = key_value;

	if (pre_touch || touch_num) {
		uint32_t pos = 0;
		uint32_t touch_index = 0;

		coor_data = &point_data[3];
		if (touch_num)
		{
			id = coor_data[pos] & 0x0F;
			touch_index |= (0x01<<id);
		}

		for (i = 0; i < GTP_MAX_TOUCH; i++) {
			if (touch_index & (0x01<<i))
			{
				s32 input_x  = coor_data[pos + 1] | coor_data[pos + 2] << 8;
				s32 input_y  = coor_data[pos + 3] | coor_data[pos + 4] << 8;
				s32 input_w  = coor_data[pos + 5] | coor_data[pos + 6] << 8;

				bool report = true;
				const bool inscreen = (input_x < screen_size[0]) && (input_y < screen_size[1]);
				const bool down = !(pre_touch & (0x01 << i));  // 按下操作



				// 只有按下时才需要判断是否需要校正
				if (down) {
					if (inscreen)
						need_calibrate |= (1 << i);
					else
						need_calibrate &= ~(1 << i);
				}

				if (need_calibrate & (1 << i)) {
					calibrate(&input_x, &input_y);
				} else {
					report = !inscreen;
				}

//

				if (report)
					tpd_down(input_x, input_y, input_w, id);
				pre_touch |= 0x01 << i;

				pos += 8;
				id = coor_data[pos] & 0x0F;
				touch_index |= (0x01<<id);
			}
			else // if (pre_touch & (0x01 << i))
			{
				tpd_up(i);
				pre_touch &= ~(0x01 << i);
				need_calibrate &= ~(1 << i);
			}
		}
	}

	input_sync(gtp_dev);

exit_work_func:

	if (!gtp_rawdiff_mode) {
		ret = gtp_i2c_write(i2c_client, end_cmd, 3);
		if (ret < 0) {
			pr_err("I2C write end_cmd  error!");
		}
	}

}

这里核心去读取寄存器里面的值,会判断是否支持多点触摸以及是否又触摸按键。
读的寄存器列表
在这里插入图片描述
这里可以看出这最多支持5点触摸。

		for (i = 0; i < GTP_MAX_TOUCH; i++) {
			if (touch_index & (0x01<<i))
			{
				s32 input_x  = coor_data[pos + 1] | coor_data[pos + 2] << 8;
				s32 input_y  = coor_data[pos + 3] | coor_data[pos + 4] << 8;
				s32 input_w  = coor_data[pos + 5] | coor_data[pos + 6] << 8;

				bool report = true;
				const bool inscreen = (input_x < screen_size[0]) && (input_y < screen_size[1]);
				const bool down = !(pre_touch & (0x01 << i));  // 按下操作

这里把取出来的值给到一个变量,后面进行report_ads(…)
自此TP中断就完了。
还有一个按键上报。

#if GTP_HAVE_TOUCH_KEY
	key_value = point_data[3 + 8 * touch_num];

	if (key_value || pre_key)
	{
		for (i = 0; i < GTP_MAX_KEY_NUM; i++)
		{
			input_report_key(gtp_dev, touch_key_array[i], key_value & (0x01<<i));    
		}
		touch_num = 0;
		pre_touch = 0;
	}
#endif

为什么这里上报的键值为F3~F5 实际应该为 KEY_CLOSECD,KEY_HOMEPAGE,KEY_BACK,KEY_VOLUMEUP,KEY_VOLUMEDOWN吧?
附上android input框架
在这里插入图片描述

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

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

相关文章

万物皆数,算无止境 | 「雪浪算力开发者大赛」圆满收官

时在中春&#xff0c;阳和方起。 4月23日&#xff0c;「雪浪算力开发者大赛」 在雪浪小镇迎来完美收官。 本次大赛吸引了全球超过2422名开发者&#xff0c; 共有624支企业队伍&#xff0c; 288支高校队伍报名参赛&#xff0c; 累计提交作品9895份。 经过三个月激烈的角逐…

Linux shell编程 循环语句for continue break

for循环是编程语言中一种循环语句 示例1&#xff1a;循环读取user.txt中的用户名&#xff0c;创建用户。设置密码。 for i in $(cat /opt/user.txt) douseradd $iecho 123456 | passwd --stdin $i done 示例2&#xff1a;循环读取ipaddr文本文件中地址&#xff0c;执行ping命令…

基于空间矢量脉宽调制(SVPWM)的并网逆变器研究(Simulink)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

day38—选择题

文章目录 1.在计算机网络中&#xff0c;TCP和UDP协议的相似之处是&#xff08;D&#xff09;2.下列哪项最恰当地描述了建立TCP连接时“第一次握手”所做的工作&#xff08;C&#xff09;3.关于以下 URL 的描述错误的是&#xff08;A&#xff09;4.不属于交换机攻击的是&#xf…

LangChain入门指南

LangChain入门 什么是LangChain如何使用 LangChain&#xff1f;LangChain的模型LangChain 的主要特点使用示例构建语言模型应用程序&#xff1a;LLMPrompt Templates: 管理LLMs的Prompts构建语言模型应用程序&#xff1a;Chat Model完整代码 什么是LangChain LangChain是一个强…

【C语言】leetcode每日一题

目录 前言题目描述题目分析代码描述 前言 时间过得真快&#xff0c;马上又要回家了&#xff0c;马上又要开始卷了。不是每朵鲜花都能代表爱情&#xff0c;但是玫瑰做到了&#xff1b;不是每棵树都能耐得住干渴&#xff0c;但是白杨做到了&#xff1b;不是每个人都在追求上进&a…

【算法思维】-- 动态规划(C++)

OJ须知&#xff1a; 一般而言&#xff0c;OJ在1s内能接受的算法时间复杂度&#xff1a;10e8 ~ 10e9之间&#xff08;中值5*10e8&#xff09;。在竞赛中&#xff0c;一般认为计算机1秒能执行 5*10e8 次计算。 时间复杂度取值范围o(log2n)大的离谱O(n)10e8O(nlog(n))10e6O(nsqrt(…

从CI/CD持续集成部署到DevOps研发运维一体化

今天整理下从传统的CI/CD到DevOps研发运维一体化的整个演进过程。类似于每日构建和冒烟测试&#xff0c;实际上在10多年前就已经在实践&#xff0c;比如当前用的笔记多的AntCruiseControl方式来实现自动化的编译构建和持续集成能力。 包括当前DevOps过程实践中的持续集成&…

基于Springboot的班级综合测评管理系统的设计与实现

摘要 随着互联网技术的高速发展&#xff0c;人们生活的各方面都受到互联网技术的影响。现在人们可以通过互联网技术就能实现不出家门就可以通过网络进行系统管理&#xff0c;交易等&#xff0c;而且过程简单、快捷。同样的&#xff0c;在人们的工作生活中&#xff0c;也就需要…

Android内存泄漏问题排查分析及常见解决方案

什么是内存泄漏&#xff1a; 在Android开发过程中&#xff0c;当一个对象已经不需要再使用了&#xff0c;本该被回收时&#xff0c;而另个正在使用的对象持有它引用从而导致它不能被回收&#xff0c;这就导致本该被回收的对象不能被回收而停留在堆内存中&#xff0c;内存泄漏就…

你真的熟悉多线程的程序的编写?快来查漏补缺

目录 一、Thread 类的属性及常用的构造方法 1.1、 Thread 常见构造方法 1.2、Thread 类的常见属性 1.3、启动&#xff08;创建&#xff09;一个线程 1.4、中断一个线程 1.5、等待一个线程 1.6、休眠当前线程 1.7、当前线程让出的 CPU 资源 二、线程状态 一、Thread 类…

华为OD机试真题(Java),整数编码(100%通过+复盘思路)

一、题目描述 实现一个整数编码方法&#xff0c;使得待编码的数字越小&#xff0c;编码后所占用的字节数越小。 编码规则如下&#xff1a; 编码时7位一组&#xff0c;每个字节的低7位用于存储待编码数字的补码&#xff1b;字节的最高位表示后续是否还有字节&#xff0c;置1表…

2023联网公司时薪排行榜出炉,多多排榜首。微软、美团很强

今天分享一个对于选择公司非常有用的参考&#xff1a;“互联网时薪”。 我们在选择一个公司的时候&#xff0c;往往会比较关注总收入package (除了基本的月薪&#xff0c;加上其他的所有的收入&#xff0c;包括但不限于奖金、股票或股份的分红等等)。 然而&#xff0c;总收入…

算力网络安全

算力网络安全 1. 算力网络简介1.1 基本概念1.2 应用场景 2. 算力网络安全需求3. 算力网络安全架构3.1 算力网络参考架构3.2 资源层安全3.3 控制层和编排管理层安全3.4 服务层安全 4. 算力网络安全关键技术4.1 安全计算4.2 安全编排4.3 数据溯源4.4 可信内生4.5 操作审计4.6 安全…

【服务器】Linux搭建我的世界服务器 + 公网远程联机教程

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 前言 1. 安装JAVA 2. MCSManager安装 3.局域网访问MCSM 4.创建我的世界服务器 5.局域网联机测试 6.安装cpolar内网穿透 7. 配置公网访问地址 8.远程联机测试 9. 配置固定…

ICMP 协议详解

文章目录 1 概述2 ICMP 协议2.1 工作原理2.2 报文格式2.3 ICMP 类型 1 概述 #mermaid-svg-6yUB8ZNYSzjbbDDq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6yUB8ZNYSzjbbDDq .error-icon{fill:#552222;}#mermaid-s…

Qt 路径

Qt 路径 Qt中路径问题小结目录与路径的区别路径分隔符Qt 路径与 Windows 路径转换相对路径mkdir 和 mkpath判断目录是否存在修改路径setPath Qt中路径问题小结 原文链接&#xff1a;https://blog.csdn.net/Andy_93/article/details/52831175 在做Qt项目的时候&#xff0c;我们…

【重学c++primer】第二章 深入浅出:变量的类型

文章目录 【重学cprimer】第二章 变量以及变量的基本类型1、从初始化/赋值语句说起2、类型详解一些未定义部分字面值变量以及变量的类型隐式类型转换 3、复合类型&#xff1a;从指针到引用指针的操作void*指针的好处引用指针的引用 4、常量和常量表达式类型const和指针const的赋…

AndroidStudio导入Android AOSP源码

一、生成导入到AS所需的配置文件 1.1、切换到Android源码的目录&#xff0c;执行配置环境脚本 source build/envsetup.sh1.2、执行lunch,选择对应产品 lunch1.3、执行make idegen make idegen编译完成后&#xff0c;就可以在Android源码的根目录下看到android.iml和android…

元宇宙展厅--音乐科技展厅

作为音乐科技领域的先锋&#xff0c;这里是一个展示最新音乐科技的创新空间。我们的元宇宙展厅汇聚了来自世界各地最前沿的音乐创新&#xff0c;将展示最新、具有前瞻性的音乐科技应用。让您可以深入了解这个领域的最新发展。 一、音乐科技展厅概述 让我们来了解一下我们的元宇…