MB85RC鐵電 FRAM驅動(全志平臺linux)

測試幾天發現一個bug,就是無法一次讀取32個字節的數據,1-31,33,128,512都試過了,唯獨無法讀取32個字節,驅動未報錯,但是讀取的都是0,找不到原因,估計應該是全志iic驅動的問題,暫時沒有折騰,盡量避開32字節讀取吧,32字節寫入是沒問題的。

使用的字符驅動,可以讀寫任意字節(32字節讀取除外),可以使用lseek設置讀寫地址,首先設置內核設備數,在對應的iic節點下添加fram支持。

fram: fram@50 {compatible = "general,iic_fram";reg = <0x50>;};

驅動代碼如下

// SPDX-License-Identifier: GPL-2.0+
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/leds.h>
#include <linux/mutex.h>
#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/uaccess.h>
#include <linux/device.h>			//自動創建/dev設備節點需要
#include <linux/kdev_t.h>           //設備號用到的頭文件和宏函數
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>typedef unsigned int  u32;
typedef unsigned short u16;
typedef unsigned char  u8;typedef volatile unsigned int  vu32;
typedef volatile unsigned short vu16;
typedef volatile unsigned char  vu8;typedef unsigned int  const uc32;  /* Read Only */
typedef unsigned short const uc16;  /* Read Only */
typedef unsigned char  const uc8;   /* Read Only */#define DEVICE_NAME			"iic_fram" 	// 設備名字
#define DTS_COMPATIBLE		"general,iic_fram"	//設備樹中對應的COMPATIBLE信息名稱//注意:fram使用的是 MB85RC16PNF-G-JNERE1 進行測試2KB容量,FRAM的通訊有點不一樣,芯片地址為4bit,然后3bit寄存器高地址,1bit讀寫標識,最終依舊使用的是8bit寄存器模式,但是地址范圍0-7FF//設備驅動私有結構體數據定義
struct fram_type {int fram_init_finished;struct i2c_client* fram_client;struct mutex mutex_lock;//定義互斥鎖struct class* device_class;		//注冊后的設備節點classstruct device* device;	//注冊的設備dev_t devno;			//設備號struct cdev cd;int size;				//容量信息
};
static struct fram_type* sg_fram = NULL;	//再iic設備注冊后進行初始化,非NULL意味著硬件初始化正常,在probe中進行初始化//注冊驅動時傳入參數,參數為farm容量信息,默認為2KB,單位字節
static int SIZE = -1;				//通過注冊驅動的時候傳入參數,如 insmode iic_fram SIZE=4096 實現容量設置
module_param(SIZE, int, S_IRUSR);	//S_IRUSR在include/linux/stat.h/*************************************************************************************************************************
*函數        	:	int fram_read_data(struct i2c_client* client, u16 addr, u16 ByteCount, u8* pData, bool isKernel)
*功能        	:	iic驅動讀取寄存器數據
*參數        	:	client:句柄;addr:寄存器地址;ByteCount:要讀取的數據數量;pData:數據緩沖區;isKernel:是否是內核讀取,如果是內核讀取將不需要進行內核數據與用戶空間數據轉換
*返回        	:	<0 錯誤,其它:讀取的字節數
*依賴			: 	底層宏定義
*作者				:	cp1300@139.com
*時間     		:	2024-03-04
*最后修改時間		:	2024-03-04
*說明        	:	
*************************************************************************************************************************/
int fram_read_data(struct i2c_client* client, u16 addr, u16 ByteCount, u8 __user* pData, bool isKernel)
{int ret;u8 addr_buff[1];u8* pkbuff;struct i2c_msg msgs[] = {//寫命令{.addr = client->addr | ((addr >> 8) & 0x07),.flags = 0,.len = 1,				//數據長度為1字節的地址.buf = addr_buff,		//寄存器地址},//讀取數據{.addr = client->addr | ((addr >> 8) & 0x07),.flags = I2C_M_RD,.len = ByteCount,		//數據長度為n字節的數據.buf = NULL,			//buf-等會設置}};//dev_info(&client->dev, "i2c_smbus_read_16bit_i2c_block_data addr=%d ByteCount=%d client->addr=%d\r\n", addr, ByteCount, client->addr);//申請內核內存,準備讀取數據pkbuff = (u8*)kmalloc(ByteCount, GFP_KERNEL | GFP_DMA | __GFP_ZERO);	//申請內存-iic會用到DMA,內存要連續if (pkbuff == NULL){printk("fram read out of memory! kmalloc(%dB)\r\n", ByteCount);return -1;}msgs[1].buf = pkbuff;	//讀取的數據存放到緩沖區//準備寄存器地址數據addr_buff[0] = addr & 0xFF;					//地址低位ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));	//寫入命令,讀取數據if (ret <= 0){dev_err(&client->dev, "i2c_transfer read addr=%d ByteCount=%d failed!\r\n", addr, ByteCount);ret = -1;}else{if (isKernel == true) //當前處于內核空間{memcpy(pData, pkbuff, ByteCount);ret = ByteCount;	//返回數據長度}else{ret = copy_to_user(pData, pkbuff, ByteCount);  //讀取成功,將數據拷貝到用戶空間if (ret != 0){printk("fram copy_to_user error(%dB)\r\n", ret);ret = -1;}else{ret = ByteCount;	//返回數據長度}}}kfree(pkbuff);	//釋放申請的內存return ret;
}/*************************************************************************************************************************
*函數        	:	int fram_write_data(struct i2c_client* client, u16 addr, u16 ByteCount, u8* pData)
*功能        	:	iic驅動寫入寄存器數據
*參數        	:	client:句柄;addr:寄存器地址;ByteCount:要讀取的數據數量;pData:數據緩沖區
*返回        	:	<0 錯誤,其它:讀取的字節數
*依賴			: 	底層宏定義
*作者				:	cp1300@139.com
*時間     		:	2024-03-04
*最后修改時間		:	2024-03-04
*說明        	:	
*************************************************************************************************************************/
int fram_write_data(struct i2c_client* client, u16 addr, u16 ByteCount, const u8 __user* pData)
{int ret;u8* buf;struct i2c_msg msgs[] = {//寫數據命令{.addr = client->addr | ((addr >> 8) & 0x07),.flags = 0,.len = ByteCount + 1,	//數據長度為2字節的地址,n字節的數據//.buf = &reg,			//buf等會賦值,需要申請內存}};//dev_info(&client->dev, "i2c_smbus_write_16bit_i2c_block_data write addr=%d ByteCount=%d\r\n", addr, ByteCount);buf = (u8*)kmalloc(ByteCount + 1, GFP_KERNEL | GFP_DMA | __GFP_ZERO);	//申請內存-iic會用到DMA,內存要連續if (buf == NULL){dev_err(&client->dev, "i2c_smbus_write_16bit_i2c_block_data out of memory! kmalloc(%dB)\r\n", ByteCount + 1);return -1;}msgs[0].buf = buf;						//記錄申請的內存//準備數據buf[0] = addr & 0xFF;					//地址低位ret = copy_from_user(&buf[1], pData, ByteCount);	//用戶空間數據拷貝到內核空間if (ret != 0) {printk("fram copy_from_user error(%dB)\r\n", ret);ret = -EFAULT;}else{ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));	//寫入數據if (ret == ARRAY_SIZE(msgs)){ret = ByteCount;	//返回寫入的數據長度}else{dev_err(&client->dev, "i2c_transfer write addr=%d ByteCount=%d failed!\r\n", addr, ByteCount);ret = -1;}}kfree(buf);	//釋放申請的內存return ret;
}/*************************************************************************************************************************
*函數        	:	int fram_Init(struct i2c_client* client)
*功能        	:	fram初始化
*參數        	:	client:iic句柄
*返回        	:	0:初始化成功;其它:初始化失敗
*依賴			: 	底層宏定義
*作者				:	cp1300@139.com
*時間     		:	2024-03-03
*最后修改時間		:	2024-03-03
*說明        	:
*************************************************************************************************************************/
int fram_Init(struct i2c_client* client)
{u8 i;struct fram_type* fram = i2c_get_clientdata(client);	//獲取私有數據int ret;u8 temp;if (fram == NULL){dev_err(&client->dev, "i2c_get_clientdata(client) null\r\n");return -1;}//讀取地址0,只要能讀取到就認為初始化成功for (i = 0; i < 3; i++){ret = fram_read_data(client, 0, 1, &temp, true);if (ret < 0){dev_err(&client->dev, "Failed to read 0x00\r\n");msleep(5);}else{dev_info(&client->dev, "addr 0x00:0x%X\r\n", temp);break;}}if (ret < 0) return -1;return 0;
}//===========================================================================================
//標準文件接口相關
/** @description		: 打開設備* @param - inode 	: 傳遞給驅動的inode* @param - filp 	: 設備文件,file結構體有個叫做private_data的成員變量* 					  一般在open的時候將private_data指向設備結構體。* @return 			: 0 成功;其他 失敗*/
static int device_open(struct inode* inode, struct file* filp)
{if (sg_fram == NULL){printk("fram not initialized\r\n");return -1;}//dev_info(&sg_fram->fram_client->dev, "device_open\n");return 0;
}/** @description		: 從設備讀取數據* @param - filp 	: 要打開的設備文件(文件描述符)* @param - buf 	: 返回給用戶空間的數據緩沖區* @param - cnt 	: 要讀取的數據長度* @param - offt 	: 相對于文件首地址的偏移* @return 			: 讀取的字節數,如果為負值,表示讀取失敗*/
static ssize_t device_read(struct file* filp, char __user* buf, size_t cnt, loff_t* offt)
{u32 offset = (u32)*offt;int ret;if (sg_fram == NULL){printk("fram not initialized\r\n");return -1;}if (buf == NULL){printk("buf is NULL!\r\n");return -EFAULT;}if (cnt == 0 || cnt > sg_fram->size || (cnt + offset) > sg_fram->size){printk("fram Read out of range cnt=%d offt=%d(max size:%dB)\r\n", cnt, offset, sg_fram->size);return 0;}//讀取數據mutex_lock(&sg_fram->mutex_lock);	//阻塞式上互斥鎖,搶不到就一直阻塞ret = fram_read_data(sg_fram->fram_client, (u16)offset, (u16)cnt, buf, false);mutex_unlock(&sg_fram->mutex_lock);	//解鎖return ret;
}/** @description		: 向設備寫數據* @param - filp 	: 設備文件,表示打開的文件描述符* @param - buf 	: 要寫給設備寫入的數據* @param - cnt 	: 要寫入的數據長度* @param - offt 	: 相對于文件首地址的偏移* @return 			: 寫入的字節數,如果為負值,表示寫入失敗*/
static ssize_t device_write(struct file* filp, const char __user* buf, size_t cnt, loff_t* offt)
{u32 offset = (u32)*offt;int ret;if (sg_fram == NULL){printk("fram not initialized\r\n");return -1;}if (buf == NULL){printk("buf is NULL!\r\n");return -EFAULT;}if (cnt == 0 || cnt > sg_fram->size || (cnt + offset) > sg_fram->size){printk("fram write out of range cnt=%d offt=%d(max size:%dB)\r\n", cnt, offset, sg_fram->size);return 0;}mutex_lock(&sg_fram->mutex_lock);	//阻塞式上互斥鎖,搶不到就一直阻塞ret = fram_write_data(sg_fram->fram_client, (u16)offset, (u16)cnt, buf);mutex_unlock(&sg_fram->mutex_lock);	//解鎖return ret;
}/** @description		: 設置文件讀寫偏移* @param - filp 	: 設備文件,表示打開的文件描述符* @param - off 	: 讀寫偏移* @param - whence 	: 光標參考位置* @return 			: 當前文件的紙質位置,如果為負值,表示寫入失敗*/
static loff_t device_llseek(struct file* filp, loff_t off, int whence)
{//struct scull_dev* dev = filp->private_data;loff_t newpos;//printk("device_llseek off=%u whence=%d\r\n", (u32)off, whence);switch (whence){case 0: //SEEK_SET 從開始的偏移{newpos = off;if (newpos >= sg_fram->size) newpos = sg_fram->size - 1;	//防止超出范圍}break;case 1:	//SEEK_CUR 在當前位置加上偏移{newpos = filp->f_pos + off;if (newpos >= sg_fram->size) newpos = sg_fram->size - 1;	//防止超出范圍}break;case 2: //SEEK_END 偏移位置文件結尾 之外{newpos = sg_fram->size - 1;	//不允許超出文件}break;default: return -EINVAL;}if (newpos < 0) return -EINVAL;filp->f_pos = newpos;return newpos;
}/** @description		: 關閉/釋放設備* @param - filp 	: 要關閉的設備文件(文件描述符)* @return 			: 0 成功;其他 失敗*/
static int device_release(struct inode* inode, struct file* filp)
{//printk("fram_release\r\n");return 0;
}//申請i2c資源,順便進行初始化
static int device_probe(struct i2c_client *client,const struct i2c_device_id *id)
{int ret;struct fram_type* fram;dev_info(&client->dev, "fram_probe\n");//判斷iic適配器是否正常if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){return -ENODEV;}//申請內核內存資源fram = devm_kzalloc(&client->dev, sizeof(struct fram_type), GFP_KERNEL);if (!fram){return -ENOMEM;}fram->fram_init_finished = 0;			//初始化未完成fram->fram_client = client;			//記錄i2c接口指針fram->device_class = NULL;						//設備節點無效fram->device = NULL;						//設備節點無效//需要提前設置,否則在 fram_Init 中需要調用 i2c_get_clientdata () 將返回空i2c_set_clientdata(client, fram);		// 將fram作為i2c次設備的私有數據區中的設備驅動私有數據if (SIZE > 0){dev_info(&client->dev, "SIZE=%dB\n", SIZE &0xFFFF);}else{SIZE = 2048;	//默認為2KB}if (SIZE < 128) SIZE = 128;if (SIZE > 0x7FF) SIZE = 0x7FF;	//最大大小限制為0x7FFfram->size = SIZE;		//初始化FRAM大小dev_info(&client->dev, "FRAM SIZE:%dB\n", fram->size);//開始芯片硬件探測與初始化ret = fram_Init(client);	//初始化并設置初值,也可以通過注冊驅動的時候傳入參數實現初始化if (ret < 0){dev_err(&client->dev, "invalid init fram\n");return -1;}mutex_init(&fram->mutex_lock);//初始化互斥鎖sg_fram = fram;						//記錄全局設備數據,設備硬件初始化完成了fram->fram_init_finished = 1;			//初始化完成dev_info(&client->dev, "fram probe succeeded\n");return 0;
}//移除iic驅動
static int device_remove(struct i2c_client* client)
{struct fram_type* fram = i2c_get_clientdata(client);	//獲取私有數據dev_info(&client->dev, "fram_remove\n");//釋放互斥鎖信號if (fram != NULL && fram->fram_init_finished){mutex_destroy(&fram->mutex_lock);}return 0;
}//===========================================================================================
//iic接口相關
static const struct of_device_id fram_match_table[] = {{.compatible = DTS_COMPATIBLE,},{},
};
MODULE_DEVICE_TABLE(of, fram_match_table);static const struct i2c_device_id fram_id[] = {{ DTS_COMPATIBLE, 0 },{},
};
MODULE_DEVICE_TABLE(i2c, fram_id);static struct i2c_driver fram_driver = {.driver = {.name		= DEVICE_NAME,.owner		= THIS_MODULE,.of_match_table = fram_match_table,},.probe    = device_probe,	//注冊IIC.remove = device_remove,.id_table	= fram_id,};//module_i2c_driver(fram_driver);	//需要使用 i2c_add_driver 在 init中進行注冊iic適配器,不能直接使用宏//設備驅動操作相關接口結構體
static struct file_operations sg_device_opera_fops = {.owner = THIS_MODULE,.open = device_open,		//打開驅動文件接口.read = device_read,		//讀取接口.write = device_write,		//寫文件接口.release = device_release,	//釋放文件接口.llseek = device_llseek,	//設置文件偏移//.ioctl = device_ioctl,		//參數設置接口
};//驅動接口-驅動入口函數-初始化與申請資源
static int __init device_init(void)
{int retvalue;//printk("device_module_init\n");retvalue = i2c_add_driver(&fram_driver);	//添加iic驅動if (retvalue) {printk("%s i2c_add_driver failed! %d\n", __func__, retvalue);return -ENODEV;}if (sg_fram == NULL) //設備硬件初始化失敗{printk("initialization failed!\r\n");return -EIO;}//注冊字符設備驅動retvalue = alloc_chrdev_region(&sg_fram->devno, 0, 1, DEVICE_NAME);	//自動申請設備號,從0開始,申請1個if (retvalue < 0) {pr_err("alloc_chrdev_region failed!(%d)", retvalue);i2c_del_driver(&fram_driver);				//移除iic設備return retvalue;}printk("MAJOR is %d\n", MAJOR(sg_fram->devno));printk("MINOR is %d\n", MINOR(sg_fram->devno));cdev_init(&sg_fram->cd, &sg_device_opera_fops);			//字符驅動結構體初始化retvalue = cdev_add(&sg_fram->cd, sg_fram->devno, 1);	//注冊字符設備驅動,數量1if (retvalue < 0) {pr_err("cdev_add failed!(%d)", retvalue);i2c_del_driver(&fram_driver);				//移除iic設備unregister_chrdev_region(sg_fram->devno, 1);	//注銷一個范圍的設備號return retvalue;}//自動在/dev目錄下創建設備節點sg_fram->device_class = class_create(THIS_MODULE, DEVICE_NAME);	創建類if (NULL == sg_fram->device_class){printk(KERN_INFO "create calss failed\n");cdev_del(&sg_fram->cd);unregister_chrdev_region(sg_fram->devno, 1);	//注銷一個范圍的設備號i2c_del_driver(&fram_driver);				//移除iic設備return -1;}else{sg_fram->device = device_create(sg_fram->device_class, NULL, sg_fram->devno, NULL, DEVICE_NAME);	//創建設備if (NULL == sg_fram->device){printk(KERN_INFO "create device failed\n");cdev_del(&sg_fram->cd);unregister_chrdev_region(sg_fram->devno, 1);class_destroy(sg_fram->device_class);i2c_del_driver(&fram_driver);				//移除iic設備return -1;}}printk("%s succeeded\n", DEVICE_NAME);return 0;
}//驅動接口-驅動出口函數-注銷資源
static void __exit device_exit(void)
{printk("device_module_exit\n");i2c_del_driver(&fram_driver);				//移除iic設備cdev_del(&sg_fram->cd);						//注銷字符設備驅動unregister_chrdev_region(sg_fram->devno, 1);	//注銷設備號device_del(sg_fram->device);printk(KERN_INFO "delete device /dev/my_char_dev \n");class_destroy(sg_fram->device_class);printk(KERN_INFO "delete device /sys/class/my_char_dev \n");}module_init(device_init);
module_exit(device_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("cp1300@139.com");

測試代碼


void fram_test(void)
{int fd;u8 buff[512];int len;int i;fd = open("/dev/iic_fram", O_RDWR);if(fd < 0){printf("open iic_frame error:%d\r\n", fd);return ;}lseek(fd, 0, SEEK_SET);len = read(fd, buff, 32);if(len <= 0){printf("read iic_frame error:%d\r\n", fd);return ;}for(i = 0;i < len;i ++){printf("0x%02X \t", buff[i]);}printf("\r\n");//lseek(fd, 0, SEEK_SET);/*for(i = 0;i < len;i ++){buff[i] = i+0xF0;}len = write(fd, buff, len);if(len <= 0){printf("write iic_frame error:%d\r\n", fd);return ;}*/close(fd);}

讀取32字節全部是0

試試33字節就正常了

?

仔細看底層驅動的打印信息

?sunxi-i2c sunxi-i2c2: drv-mode: dma read data end

讀取32字節的時候,這個打印都結束了才提示DMA讀取完成,很有可能就是因為數據都沒讀取完成,但是底層已經返回了,原因未知,珍愛生命,遠離linux驅動,湊合著用吧(⊙o⊙)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/718734.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/718734.shtml
英文地址,請注明出處:http://en.pswp.cn/news/718734.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

leetcode - 2095. Delete the Middle Node of a Linked List

Description You are given the head of a linked list. Delete the middle node, and return the head of the modified linked list. The middle node of a linked list of size n is the ?n / 2?th node from the start using 0-based indexing, where ?x? denotes th…

python中的類與對象(3)

目錄 一. 類的多繼承 二. 類的封裝 三. 類的多態 四. 類與對象綜合練習&#xff1a;校園管理系統 一. 類的多繼承 在&#xff08;2&#xff09;第四節中我們介紹了什么是類的繼承&#xff0c;在子類的括號里面寫入要繼承的父類名。上一節我們只在括號內寫了一個父類名&…

新手淘寶開店如何引流

對于新手淘寶賣家來說&#xff0c;引流是開店過程中最為關鍵的一環。如何吸引潛在客戶進入店鋪&#xff0c;提高商品的曝光率和銷量&#xff0c;是每個新手賣家都面臨的挑戰。本文將為你提供新手淘寶開店的引流攻略&#xff0c;幫助你從零開始掌握實用的引流技巧。 一、優化店…

C++的類型轉換

1.C語言中的類型轉換 在C語言中&#xff0c;如果賦值運算符左右兩側類型不同&#xff0c;或者形參與實參類型不匹配&#xff0c;或者返回值類型與接收返回值類型不一致時&#xff0c;就需要發生類型轉化&#xff0c;C語言中總共有兩種形式的類型轉換&#xff1a;隱式類型轉換和…

【機器人最短路徑規劃問題(柵格地圖)】基于模擬退火算法求解

代碼獲取方式&#xff1a;QQ&#xff1a;491052175 或者 私聊博主獲取 基于模擬退火算法求解機器人最短路徑規劃問題&#xff08;柵格地圖&#xff09;的仿真結果 仿真結果&#xff1a; 初始解的路徑規劃圖 收斂曲線&#xff1a; 模擬退火算法求解的路徑規劃圖 結論&#xff…

Ubuntu20安裝zabbix-agent2,對接zabbix 6.4

在Ubuntu 20.04 LTS上安裝Zabbix Agent 2并與Zabbix Server 6.4對接&#xff0c;請按照以下步驟操作&#xff1a; 更新系統&#xff1a; sudo apt update sudo apt upgrade 添加Zabbix官方倉庫&#xff1a; 首先&#xff0c;需要將Zabbix的官方存儲庫添加到你的系統中以獲取Za…

C#面:常用的 異常類 有哪些

異常類是用于處理程序運行時出現的錯誤或異常情況的類。 C# 提供了一些內置的異常類&#xff0c;常用的包括&#xff1a; System.Exception&#xff1a;所有異常類的基類&#xff0c;可以用于捕獲所有類型的異常。System.SystemException&#xff1a;表示系統級別的異常&…

【了解SpringCloud Gateway微服務網關】

曾夢想執劍走天涯&#xff0c;我是程序猿【AK】 目錄 簡述概要知識圖譜什么是SpringCloudGateway功能特征應用場景核心概念配置文件工作原理路由謂詞工廠&#xff08;內置的&#xff09;[After 路由謂詞工廠](https://docs.spring.io/spring-cloud-gateway/docs/current/refere…

Mysql運維篇(七) 部署MHA--完結

一路走來&#xff0c;所有遇到的人&#xff0c;幫助過我的、傷害過我的都是朋友&#xff0c;沒有一個是敵人。如有侵權&#xff0c;請留言&#xff0c;我及時刪除&#xff01; 一、MHA軟件構成 Manager工具包主要包括以下幾個工具&#xff1a; masterha_manger 啟…

【C++】多態深入分析

目錄 一&#xff0c;多態的原理 1&#xff0c;虛函數表與虛函數表指針 2&#xff0c;原理調用 3&#xff0c;動態綁定與靜態綁定 二&#xff0c;抽象類 三&#xff0c;單繼承和多繼承關系的虛函數表 1&#xff0c;單繼承中的虛函數表 2&#xff0c;多繼承中的虛函數表 …

“編碼迷宮中的探險者:探索程序員職業賽道的無限可能“

在這個信息技術飛速發展的時代&#xff0c;程序員的職業賽道就像是一座錯綜復雜的迷宮&#xff0c;它既充滿了挑戰&#xff0c;又蘊藏著無限的機遇。這座迷宮中&#xff0c;有前端的美麗花園&#xff0c;后端的黑暗洞穴&#xff0c;還有數據科學的神秘密室。每一條路徑都有其獨…

內網搭建mysql8.0并搭建主從復制詳細教程!!!

一、安裝mysql 1.1 mysql下載鏈接&#xff1a; https://downloads.mysql.com/archives/community/ 1.2 解壓包并創建相應的數據目錄 tar -xvf mysql-8.2.0-linux-glibc2.28-x86_64.tar.xz -C /usr/local cd /usr/local/ mv mysql-8.2.0-linux-glibc2.28-x86_64/ mysql mkdir…

Python繪圖-9餅圖(上)

餅圖&#xff08;Pie Chart&#xff09;是一種用于表示數據分類和相對大小的可視化圖形。在餅圖中&#xff0c;整個圓形代表數據的總和&#xff0c;而圓形內的各個扇形則代表不同的分類或類別&#xff0c;扇形的面積大小表示該類別在整體中所占的比例。餅圖通常用于展示數據的分…

FW, IPS, IDS

文章目錄 FW (Firewall, 防火墻)IPS (Intrusion Prevention System, 入侵防御系統)IDS (Intrusion Detection System, 入侵檢測系統)IDS vs. FWIPS FW (Firewall, 防火墻) 產品定位&#xff1a; 防火墻的主要作用是進行網絡訪問控制。它充當網絡的門衛&#xff0c;控制進入和離…

《人間值得》讀書筆記

人的一生說短不短&#xff0c;說長不長。蕓蕓眾生&#xff0c;為了生活努力的掙扎&#xff0c;太少的人能衣食無憂&#xff0c;所以我們每天為了碎銀幾兩&#xff0c;為了生活奔波。 《人間值得》的主人公是一個90歲的老奶奶&#xff0c;她的生活經歷很豐富&#xff0c;她的人…

ObjectProvider學習

簡介 ObjectProvider 是 Spring Framework 5.0 之后引入的一個新接口&#xff0c;它提供了一個靈活的方式來訪問由 Spring 容器管理的 Bean。ObjectProvider 提供了一種更加類型安全的方式來查找和注入依賴項&#xff0c;同時還支持 Null 值的處理以及延遲初始化。 ObjectProv…

Window部署Jaeger

參考&#xff1a;windows安裝使用jaeger鏈路追蹤_windows安裝jaeger-CSDN博客 下載&#xff1a;Releases jaegertracing/jaeger GitHub Jaeger – Download Jaeger 目錄 1、安裝nssm 2、安裝運行 elasticsearch 3、安裝運行 3.1部署JaegerAgent 3.2部署JaegerCollec…

【全志D1-H 哪吒開發板】Debian系統安裝調教和點燈指南

全志D1-H開發板【哪吒】使用Deabian系統入門 特別說明&#xff1a; 因為涉及到操作較多&#xff0c;博文可能會導致格式丟失 其中內容&#xff0c;會根據后續使用做優化調整 目錄&#xff1a; 參考資料固件燒錄啟動調教點燈問題 〇、參考資料 官方資料 開發板-D1開發板【…

C++:函數模板整理

函數模板: 找到函數相同的實現思路&#xff0c;區別于函數的參數類型。 使用函數模板使得函數可容納不同類型的參數實現函數功能&#xff0c;而不是當類型不同時便編譯大量類型不同的函數&#xff0c;產生大量重復代碼和內存占用 函數模板格式&#xff1a; template<typ…

[Vulnhub]靶場 Red

kali:192.168.56.104 主機發現 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 …