android 電容屏(四):驅動調試之驅動程式分析篇 -- FocalTech

来源:https://www.cnblogs.com/linhaostudy/archive/2019/08/13/11345758.html
-Advertisement-
Play Games

本人用的觸摸屏IC是FocalTech公司的ft5306,是一款i2c的電容屏多點觸控晶元。對於它的整體驅動官方已經給了,我們就觸摸屏和按鍵部分的代碼做相關說明。說明其中應該註意的地方。 對於所有的input設備,報告input事件時候都分這麼幾部分,首先在probe文件中設置設備發送的事件類型、按 ...


本人用的觸摸屏IC是FocalTech公司的ft5306,是一款i2c的電容屏多點觸控晶元。對於它的整體驅動官方已經給了,我們就觸摸屏和按鍵部分的代碼做相關說明。說明其中應該註意的地方。

對於所有的input設備,報告input事件時候都分這麼幾部分,首先在probe文件中設置設備發送的事件類型、按鍵類型、設置設備一些屬性信息。然後在發送事件時候要根據probe的設置來發送事件,否則就會被判為無效忽略掉。

一、觸摸屏部分

1.設備配置

對於觸摸屏,必須支持的事件類型有以下這麼三個:

__set_bit(EV_SYN, input_dev->evbit);  //設備同步,每次觸摸完成以後都要發送一個同步事件,來表明這次觸摸已經完成
__set_bit(EV_ABS, input_dev->evbit); //絕對坐標事件,觸摸屏每次發送的坐標都是絕對坐標,不同於滑鼠的相對坐標
__set_bit(EV_KEY, input_dev->evbit); //按鍵事件,每次觸摸都有一個BTN_TOUCH的按鍵事件

觸摸屏必須支持的按鍵類型

__set_bit(BTN_TOUCH, input_dev->keybit);//touch類型按鍵

觸摸屏屬性設置

input_mt_init_slots(input_dev, CFG_MAX_TOUCH_POINTS);//報告最大支持的點數
input_set_abs_params(input_dev,ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);//將觸摸點看成一個橢圓,它的長軸長度。這個是可選項,並不影響正常使用。
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, ft5x0x_ts->x_max, 0, 0);//x坐標取值範圍
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, ft5x0x_ts->y_max, 0, 0);//y坐標取值範圍

2.事件發送

我們知道每次觸摸完成後都必鬚髮送一個同步事件(EV_SYN)來表明這次觸摸的完成。 那麼對於多點觸控的屏幕事件發送分為兩種方法,一是每次事件同步前包括多個點,一是每次事件同步前僅包含一個點。

先來看包含多個點的

static void ft5x0x_report_value(struct ft5x0x_ts_data *data)  
{  
    struct ts_event *event = &data->event;  
    int i;  
    int uppoint = 0;    //已經抬起的點數  
  
    for (i = 0; i < event->touch_point; i++)  //迴圈處理 緩存中的所有點  
    {  
        input_mt_slot(data->input_dev, event->au8_finger_id[i]);  //發送點的ID  
          
        if (event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2)  //如果點按下  
        {  
            input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER,  true);  //手指按下  
            input_report_abs(data->input_dev,ABS_MT_POSITION_X,event->au16_x[i]); //x坐標     
            input_report_abs(data->input_dev, ABS_MT_POSITION_Y,event->au16_y[i]);    //y坐標  
            input_report_abs(data->input_dev,ABS_MT_TOUCH_MAJOR,event->pressure); //觸摸點長軸長度  
        }  
        else  
        {  
            uppoint++;                              //沒有按下,則表明這個手指已經抬起  
            input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER,false);   //報告手指抬起  
        }  
          
  
    }  
  
        if(event->touch_point == uppoint)              
        {  
            input_report_key(data->input_dev, BTN_TOUCH, 0); //所有手指都抬起了 發送BTN_TOUCH 抬起事件  
  
        }  
        else  
        {  
            input_report_key(data->input_dev, BTN_TOUCH, event->touch_point > 0);//還有手指沒抬起,發送BTN_TOUCH 按下的事件   
  
        }  
        input_sync(data->input_dev); //sync 設備同步  
          
}  

然後是每次同步僅發送一個點

static ft5x0x_report_value(struct ft5x0x_ts_data *data)  
  
{  
    struct ts_event *event = &data->event;  
    int i;  
  
    for (i = 0; i < event->touch_point; i++)  //迴圈處理 緩存中的所有點  
    {  
        input_mt_slot(data->input_dev, event->au8_finger_id[i]);  //發送點的ID  
        if (event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2)  //如果點按下  
        {  
            input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER,  true);  //手指按下  
            input_report_abs(data->input_dev,ABS_MT_POSITION_X,event->au16_x[i]); //x坐標     
            input_report_abs(data->input_dev, ABS_MT_POSITION_Y,event->au16_y[i]);    //y坐標  
            input_report_abs(data->input_dev,ABS_MT_TOUCH_MAJOR,event->pressure); //觸摸點長軸長度  
        }  
        else  
        {  
            input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER,false);   //手指抬起  
        }  
          
  
        input_mt_report_pointer_emulation(input_dev, true);//用模擬點的方法,來告知此次觸摸已經完成。  
        input_sync(data->input_dev); //sync 設備同步  
          
    }  
} 

這兩種方法都可以,但是建議選擇上面那種,效率比較高。

二、觸摸按鍵部分

對於觸摸按鍵的發送可以分為兩種方法,一是android提供的 virtualkey's 架構方法,一種是直接報告key event的方法。我們一一來看

1.報告key event方法

在probe中添加所支持的按鍵類型,本人用的觸摸屏上有三個按鍵因此

報告支持事件類型

__set_bit(EV_SYN, input_dev->evbit); 

__set_bit(EV_KEY, input_dev->evbit);

報告支持的按鍵

__set_bit(KEY_HOME, input_dev->keybit);   
__set_bit(KEY_BACK, input_dev->keybit);  
__set_bit(KEY_MENU, input_dev->keybit);

觸摸屏上的三個按鍵對應的坐標

(KEY_BACK)  120:1400   (KEY_HOME) 360:1400(KEY_MENU)  500:1400

key event的報告方法很簡單隻要報告相應的key 和設備同步sync就可以了

static void ft5x0x_report_value(struct ft5x0x_ts_data *data)  
{  
    struct ts_event *event = &data->event;  
    int i;  
    for (i = 0; i < event->touch_point; i++)  
    {  
        if (event->au16_y[i]==1400)  
        {  
            if(event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2)  
            {  
  
                switch(event->au16_x[i])  
                {  
                case 120:  
                    input_report_key(data->input_dev, KEY_BACK, 1);  
                    break;  
                case 360:   
                    input_report_key(data->input_dev, KEY_HOME, 1);  
                    break;  
                case 500:   
                    input_report_key(data->input_dev, KEY_MENU, 1);  
                    break;    
                default: break;  
                }  
                  
            }  
            else  
            {  
  
                switch(event->au16_x[i])  
                {  
                case 120:  
                    input_report_key(data->input_dev, KEY_BACK, 0);  
                    break;  
                case 360:   
                    input_report_key(data->input_dev, KEY_HOME, 0);  
                    break;  
                case 500:   
                    input_report_key(data->input_dev, KEY_MENU, 0);  
                    break;    
                default: break;  
                }  
                  
            }  
            input_sync(data->input_dev);  
            return;  
        }  
}  

對於這種方法有一個bug,就是事件發送上去,系統並不認為是觸摸屏發送的按鍵,系統的 觸屏震動反饋 並不起作用。這並不符合標準的android觸摸設備標準。具體怎麼破本人比較菜沒有找到方法,大神們誰知道 求破。

2.virtualkeys方法

virtualkeys是android提供的架構使用起來簡單方便,推薦大家使用。直接上代碼

static ssize_t ft5x06_virtual_keys_show(struct kobject *kobj,       //按鍵的配置  
                    struct kobj_attribute *attr, char *buf)  
{  
    return sprintf(buf,  
        __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":120:1400:8:8"   //鍵類型:鍵值:按鍵區域中心x坐標:按鍵區域中心y坐標:按鍵區域寬:按鍵區域高  
        ":" __stringify(EV_KEY) ":"  
                    __stringify(KEY_HOME) ":360:1400:8:8"  
        ":" __stringify(EV_KEY) ":"  
                    __stringify(KEY_MENU) ":500:1400:8:8"  
        "\n");  
}  
  
static struct kobj_attribute ft5x06_virtual_keys_attr = {  
    .attr = {  
        .name = "virtualkeys.Ft5x0x_Touch_Screen",  //這裡的名字必須為virtualkeys.設備名字  否則系統不會識別  
        .mode = S_IRUGO,  
    },  
    .show = &ft5x06_virtual_keys_show,  
};  
  
static struct attribute *ft5x06_properties_attrs[] = {  
    &ft5x06_virtual_keys_attr.attr,  
    NULL,  
};  
  
static struct attribute_group ft5x06_properties_attr_group = {  
    .attrs = ft5x06_properties_attrs,  
};  
  
static void ft5x06_virtual_keys_init(void)  
{  
    struct kobject *properties_kobj;  
    int ret;  
  
    properties_kobj = kobject_create_and_add("board_properties", NULL);//添加目錄board_properties  
  
    if (properties_kobj)  
        ret = sysfs_create_group(properties_kobj,//生成/sys/board_properties/virtualkeys.Ft5x0x_Touch_Screen虛擬按鍵配置文件  
            &ft5x06_properties_attr_group); //可以使用 cat /sys/board_properties/virtualkeys.Ft5x0x_Touch_Screen命令來查看配置是否正確  
    if (!properties_kobj || ret)  
        pr_err("failed to create board_properties\n");  
}  

然後將ft5x06_virtual_keys_init()加入到 觸摸屏的init 或者probe 函數中,這樣觸摸鍵就可以使用了。

三、觸摸屏驅動流程

i2c中加入平臺初始化代碼

static struct ft5x0x_platform_data  ft5x0x_platform_i2c_data = {  
    .x_max=540,  
    .y_max=960,  
    .irq= SABRESD_CHARGE_FLT_1_B, //中斷引腳  
    .reset=SABRESD_DISP0_RST_B,  //複位引腳  
};  

觸摸屏驅動初始化

static int __init ft5x0x_ts_init(void)
{
    int ret;
    ret = i2c_add_driver(&ft5x0x_ts_driver);
    if (ret) {
        printk(KERN_WARNING "Adding ft5x0x driver failed "
               "(errno = %d)\n", ret);
    } else {
        pr_info("Successfully added driver %s\n",       
            ft5x0x_ts_driver.driver.name);
    }
    return ret;
}

probe函數

#define VIRTUAL_LI      0
#define EVENT_LI        1
#define TOUCH_KEY       VIRTUAL_LI  
static int ft5x0x_ts_probe(struct i2c_client *client,
               const struct i2c_device_id *id)
{
    。。。。。。。。。。
    ft5x0x_ts = kzalloc(sizeof(struct ft5x0x_ts_data), GFP_KERNEL);//分配參數記憶體
 
    ..........
    i2c_set_clientdata(client, ft5x0x_ts);參數地址傳給i2c 內核
 
    初始化一些參數
    ft5x0x_ts->irq = client->irq;   
    ft5x0x_ts->client = client;
    ft5x0x_ts->pdata = pdata;
    ft5x0x_ts->x_max = pdata->x_max - 1;
    ft5x0x_ts->y_max = pdata->y_max - 1;
    ft5x0x_ts->pdata->reset = FT5X0X_RESET_PIN;
    ft5x0x_ts->pdata->irq = ft5x0x_ts->irq;
.....................
    err = request_threaded_irq(client->irq, NULL, ft5x0x_ts_interrupt,  //註冊讀取數據中斷
                   IRQF_TRIGGER_FALLING, client->dev.driver->name,
                   ft5x0x_ts);
    。、、、、、、、、、、、、
    input_dev = input_allocate_device();//分配設備
...........................................
    __set_bit(EV_SYN, input_dev->evbit);  //註冊設備支持event類型
    __set_bit(EV_ABS, input_dev->evbit);
    __set_bit(EV_KEY, input_dev->evbit);
    __set_bit(BTN_TOUCH, input_dev->keybit);
#if TOUCH_KEY == EVENT_LI               //如果使用event key的方法
    __set_bit(KEY_HOME, input_dev->keybit);   
    __set_bit(KEY_BACK, input_dev->keybit);  
    __set_bit(KEY_MENU, input_dev->keybit);
#endif  
    input_mt_init_slots(input_dev, CFG_MAX_TOUCH_POINTS);   //設備屬性
    input_set_abs_params(input_dev,ABS_MT_TOUCH_MAJOR,
                 0, PRESS_MAX, 0, 0);
    input_set_abs_params(input_dev, ABS_MT_POSITION_X,
                 0, ft5x0x_ts->x_max, 0, 0);
    input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
                 0, ft5x0x_ts->y_max, 0, 0);
 
    
 
    input_dev->name ="Ft5x0x_Touch_Screen";//lijianzhang
    err = input_register_device(input_dev);         //註冊這個input設備
    。。。。。。。。。。。
#if TOUCH_KEY == VIRTUAL_LI     //如果使用虛擬鍵盤設定
 
    ft5x06_virtual_keys_init();     
#endif
。。。。。。。。。。。。。。。。。。。。。
}

中斷處理

static irqreturn_t ft5x0x_ts_interrupt(int irq, void *dev_id)
{
    struct ft5x0x_ts_data *ft5x0x_ts = dev_id;
    int ret = 0;
    disable_irq_nosync(ft5x0x_ts->irq);
    ret = ft5x0x_read_Touchdata(ft5x0x_ts); //讀取數據
    if (ret == 0)
        ft5x0x_report_value(ft5x0x_ts);//報告數據
 
    enable_irq(ft5x0x_ts->irq);
 
    return IRQ_HANDLED;
}

報告事件

static void ft5x0x_report_value(struct ft5x0x_ts_data *data)
{
    struct ts_event *event = &data->event;
    int i;
    int uppoint = 0;
 
    /*protocol B*/  
    for (i = 0; i < event->touch_point; i++)
    {
#if TOUCH_KEY == EVENT_LI       //如果使用 key event方法
        if (event->au16_y[i]==1400)
        {
            if(event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2)
            {
 
                switch(event->au16_x[i])
                {
                case 120:
                    input_report_key(data->input_dev, KEY_BACK, 1);
                    break;
                case 360: 
                    input_report_key(data->input_dev, KEY_HOME, 1);
                    break;
                case 500: 
                    input_report_key(data->input_dev, KEY_MENU, 1);
                    break;  
                default: break;
                }
                
            }
            else
            {
 
                switch(event->au16_x[i])
                {
                case 120:
                    input_report_key(data->input_dev, KEY_BACK, 0);
                    break;
                case 360: 
                    input_report_key(data->input_dev, KEY_HOME, 0);
                    break;
                case 500: 
                    input_report_key(data->input_dev, KEY_MENU, 0);
                    break;  
                default: break;
                }
                uppoint++;
                
            }
            input_sync(data->input_dev);
            return;
        }
 
#endif
    
        input_mt_slot(data->input_dev, event->au8_finger_id[i]);
        
        
        if (event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2)
        {
            input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, true);
            input_report_abs(data->input_dev,ABS_MT_POSITION_X,event->au16_x[i]);       //lijianzhang
            input_report_abs(data->input_dev, ABS_MT_POSITION_Y,event->au16_y[i]);
            input_report_abs(data->input_dev,ABS_MT_TOUCH_MAJOR,event->pressure);
        }
        else
        {
            uppoint++;
            input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, false);
        }
        
 
    }
 
        if(event->touch_point == uppoint)
        {
            input_report_key(data->input_dev, BTN_TOUCH, 0);
        }
        else
        {
            input_report_key(data->input_dev, BTN_TOUCH, event->touch_point > 0);
        }
        input_sync(data->input_dev);
        
}

這裡驅動流程做了簡略的說明,關鍵的代碼都已經貼出來了。與設備相關代碼都是廠商給的沒有太實際參考價值.

從android input的流程分析我們知道,驅動編譯完成以後,要使觸摸屏工作,還需要三個文件:觸摸屏配置文件 (idc文件,用來配置觸摸屏的一些屬性)、keylayout文件(kl文件,安卓層面的按鍵映射文件)、characterMap文件(kcm文件,安卓層面的字元映射文件)
我們一一來看這三個文件

1.觸摸屏配置文件

文件所在目錄訪問順序:

首先ANDROID_ROOT/usr/idc目錄下去找相應名字的文件並返回完整的路徑名,如果找不到就從ANDROID_DATA/system/devices/idc下麵去找,這裡ANDROID_ROOT一般指的是/system目錄,ANDROID_DATA一般指/data目錄.

文件名稱的查找順序首先是Vendor_XXXX_Product_XXXX_Version_XXXX.idc,然後是Vendor_XXXX_Product_XXXX.idc最後是DEVICE_NAME.idc

總結來看安卓為輸入設備打開配置文件依次會訪問

/system/usr/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc
/system/usr/idc/Vendor_XXXX_Product_XXXX.idc
/system/usr/idc/DEVICE_NAME.idc
/data/system/devices/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc
/data/system/devices/idc/Vendor_XXXX_Product_XXXX.idc
/data/system/devices/idc/DEVICE_NAME.idc

我們驅動里並沒有寫版本號等這些信息,因此我們設備訪問的idc文件會是/system/usr/idc/DEVICE_NAME.idc。因此我們在這個目錄下增加文件Ft5x0x_Touch_Screen.idc.對於idc文件的內容,下麵是我使用的idc文件的具體內容,僅供參考

touch.deviceType = touchScreen
touch.orientationAware = 1
 
touch.size.calibration = none
touch.orientation.calibration = none                                    

2.key layout文件

key layout文件是android層面的按鍵映射文件,通過這個文件,用戶可以對kernel發送上來的按鍵功能進行重新定義。也就是說,kernel發送上來一個home鍵,你可以在這裡把它映射成一個back鍵或者其他的。一般情況下不會修改這個文件,因此我麽完全可以使用預設的配置文件

這個文件訪問順序

/system/usr/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl
/system/usr/keylayout/Vendor_XXXX_Product_XXXX.kl
/system/usr/keylayout/DEVICE_NAME.kl
/data/system/devices/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl
/data/system/devices/keylayout/Vendor_XXXX_Product_XXXX.kl
/data/system/devices/keylayout/DEVICE_NAME.kl
/system/usr/keylayout/Generic.kl
/data/system/devices/keylayout/Generic.kl

這裡不用修改因此不用做改變

3.characterMap文件

characterMap文件是android層面的字元映射文件,比如:你摁下了一個'e'鍵,平時代表'e',shift+'e'代表'E',casplk+'e'代表'E',alt+'e'可能代表別的意思,這個配置文件就是,做這些映射的。一般情況下這個文件也不用修改。使用預設的就可以。這個文件的訪問順序:

到了這裡 我們的觸摸屏已經完成了,燒寫以後應該可以正常使用了。

在這裡分享一個小技巧,getevent 這個工具,在/dev/input/目錄下使用這個命令,會首先得到系統中所有input設備的描述,然後會得到,kernel發送的所有input事件,當我們寫完驅動以後,可以用這個命令將發送的事件列印出來,看驅動寫的是否正確。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本篇內容: 冒泡排序 冒泡排序 演算法思想: 冒泡排序的原理是:從左到右,相鄰元素進行比較。 每次比較一輪,就會找到序列中最大的一個或最小的一個。這個數就會從序列的最右邊冒出來。 代碼實現: 運行結果: ...
  • 1.應用背景: 無人監測的設備,常需要設置應用程式開機啟動,程式啟動前需要保證調用的設備先啟動,運行環境先啟動。 2.test.sh部分源碼 2.1 grep 指令: 用於匹配文本字元 用法1:grep 字元串 文件路徑; 用於匹配查找文件中的相同字元串。 用法2:grep -v 字元串;翻轉查找, ...
  • 1、我們打開VM軟體,然後點擊“創建新的虛擬機”,選擇“經典”選項 2、選中“稍後安裝操作系統”單選按鈕,然後單擊“下一步”按鈕 3、將客戶機操作系統的類型選擇為“Linux”,版本為"Red Hat Enterprise Linux 7 64位" 。然後點擊“下一步”按鈕 4、填寫“虛擬機名字”, ...
  • 下麵介紹Windows Server 2008本地用戶和組的管理包括創建用戶、刪除用戶、重設密碼、將用戶添加到組、普通用戶跟管理員的區別 、用戶配置文件包括桌面上文件,桌面背景,桌面上圖標,IE設置,數字證書,我的文檔,存儲網路密碼、公共配置文件、預設的配置文件、管理用戶密碼、更改密碼、重設密碼、密 ...
  • 好久沒有寫過博客了,都是看大牛的文章,略過~~ 突然感覺成長在於總結!廢話不多說,開乾 由於是公司項目,所以不方便給出代碼,看圖操作 在項目util目錄下創建工具類TaskExecutorConfig 並且實現 org.springframework.aop.interceptor.AsyncUnc ...
  • 軟體介紹: netperf是惠普公司開源的一款針對網路性能的測試工具,主要基於TCP或UDP的傳輸。根據應用的不同,可以進行批量數據傳輸(bulk data transfer)模式和請求/應答(request/reponse)模式的性能測試。 netperf以Client/Server方式工作。Se ...
  • #環境 :內核的版本必須大於3.10 #安裝docker #配置文件 #啟動 加入開機啟動 #創建啟動使用容器 ...
  • 什麼是 strace strace是Linux環境下的一款程式調試工具,用來監察一個應用程式所使用的系統調用。 Strace是一個簡單的跟蹤系統調用執行的工具。在其最簡單的形式中,它可以從開始到結束跟蹤二進位的執行,併在進程的生命周期中輸出一行具有系統調用名稱,每個系統調用的參數和返回值的文本行。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...