Linux Regulator Framework(2)_regulator driver

来源:https://www.cnblogs.com/linhaostudy/archive/2018/03/24/8640107.html
-Advertisement-
Play Games

轉自蝸窩科技:http://www.wowotech.net/pm_subsystem/regulator_driver.html 說實話,這篇好難懂啊。。。 1. 前言 本文從regulator driver的角度,描述怎樣基於regulator framework編寫regulator驅動。同時 ...


轉自蝸窩科技:http://www.wowotech.net/pm_subsystem/regulator_driver.html

說實話,這篇好難懂啊。。。

1. 前言

 本文從regulator driver的角度,描述怎樣基於regulator framework編寫regulator驅動。同時,以此為契機,學習、理解regulator有關的物理特性,以便能夠更好的使用它們。

 

2. regulator driver的實現步驟

 2.1 確定系統中regulator有關的硬體組成

 提起硬體,最好能有個例子,好在有device tree,一個活生生的硬體拓撲結構。這裡以NVIDIA Tegra Dalmore A04開發板為例(regulator有關的device tree位於“arch\arm\boot\dts\tegra114-dalmore.dts”):

 

這裡的regulator結構是相當複雜的,其中彩色框代表最終的regulator抽象,它的前一級表示regulator的載體(可以是PMIC、CPU、等等)。下麵將會詳細說明:

a)CPU通過I2C controller,連接一個降壓控制器(TI tps51632),該控制器輸出名稱為“vdd-cpu”的電壓,就稱作vdd-cpu regulator吧(因此,在kernel中,regulator是一個虛擬設備)。

b)CPU通過I2C controller,連接一個前端電源管理晶元(TI tps65090),該晶元除了具備充電管理功能外,內置了多個regulator,例如dcdc1、dcdc2等等。

c)CPU通過I2C controller,連接另一個電源管理晶元(TI tps65913),該晶元具有兩個功能:GPIO輸出和PMIC。PMIC內置了多個regulator,如vddio-ddr、vdd-core等等。

d)CPU內部也集成了一些regulator,如vdd_ac_bat等等。

這些思考在本文的例子(NVIDIA Tegra Dalmore A04的regulator)中體現尤為突出,它的本質是軟體設計中的模塊劃分,從而決定了regulator在DTS中的呈現方式和層次。

 

2.2 使用DTS,將硬體拓撲呈現出來

1)tps51632(是一種電源管理模塊)

tps51632是一個簡單的器件,位於i2c匯流排下麵,包含一個regulator器件,因此其DTS比較簡單,如下:

   1: /* arch\arm\boot\dts\tegra114-dalmore.dts */
   2: i2c@7000d000 {
   3:         status = "okay";
   4:         clock-frequency = <400000>;
   5:  
   6:         tps51632@43 {
   7:                 compatible = "ti,tps51632";
   8:                 reg = <0x43>;
   9:                 regulator-name = "vdd-cpu";
  10:                 regulator-min-microvolt = <500000>;
  11:                 regulator-max-microvolt = <1520000>;
  12:                 regulator-boot-on;
  13:                 regulator-always-on;
  14:         };
  15:         ...
  16: }

 i2c控制器的node為“i2c@7000d000”,tps51632是其下的一個子node,名稱為“tps51632@43”,compatible為“ti,tps51632”。tps51632下麵以“regulator-”為首碼的欄位,是regulator特有的欄位,後面會統一介紹。

註2:為什麼“i2c@7000d000”中沒有compatible欄位?其實是有的,可參考“arch\arm\boot\dts\tegra114.dtsi”,DTC在編譯DTS時,會將這兩個文件中的node合併。

註3:kernel在初始化時,只會為二級node(即“/”下麵的節點,本文的例子是“i2c@7000d000”)創建platform設備,至於三級node(這裡的“tps51632@43”),則由其bus(i2c)創建。後面我們會遇到其它的情況,到時再介紹。

 

2)tps65090

tps65090相對比較複雜,它位於相同的i2c匯流排下麵,但包含兩個相對複雜的功能實體,charger和PMIC,我們看看其DTS怎麼寫的:

   1: i2c@7000d000 {
   2:         status = "okay";
   3:         ...
   4:  
   5:         tps65090@48 {
   6:                 compatible = "ti,tps65090";
   7:                 reg = <0x48>;
   8:                 ...
   9:  
  10:                 charger: charger {
  11:                         compatible = "ti,tps65090-charger";
  12:                         ti,enable-low-current-chrg;
  13:                 };
  14:                 
  15:                 regulators {
  16:                         tps65090_dcdc1_reg: dcdc1 {
  17:                                 regulator-name = "vdd-sys-5v0";
  18:                                 regulator-always-on;
  19:                                 regulator-boot-on;
  20:                         };
  21:                 
  22:                         tps65090_dcdc2_reg: dcdc2 {
  23:                                 regulator-name = "vdd-sys-3v3";
  24:                                 regulator-always-on;
  25:                                 regulator-boot-on;
  26:                         };
  27:                         ...
  28:                 }
  29:         }
  30: }

 和tps51632類似,但它下麵又包含了兩個子node:charger和regulators。其中charger竟然還有compatible欄位。

 回憶一下上面“註3”,kernel只會為"i2c@7000d000”創建platform device,“tps65090@48”則由i2c core創建,那麼它下麵的子node呢?一定是tps65090 driver處理了,感興趣的讀者可以閱讀“drivers/mfd/tps65090.c”、“drivers/power/tps65090-charger.c”和“drivers/regulator/tps65090-regulator.c”,這裡面還涉及了MFD(multi-function device,多功能設備),很有意思。

 回到本文的主題上,雖然這裡的regulators沒有compatible欄位,也會創建相應的platform device(具體可參考“drivers/mfd/tps65090.c”),這從側面回答了上面的一個思考:從物理範疇,tps65090是一個獨立的設備,但它內部有兩個功能模塊,因此會存在兩個platform device

 

3)tps65913,和tps65090類似,不再介紹。

4)CPU中的regulator

這一類regulator比較特殊,直接集成在CPU內部,DTS如下:

   1: regulators {
   2:         compatible = "simple-bus";
   3:         #address-cells = <1>;
   4:         #size-cells = <0>;
   5:  
   6:         vdd_ac_bat_reg: regulator@0 {
   7:                 compatible = "regulator-fixed";
   8:                 reg = <0>;
   9:                 regulator-name = "vdd_ac_bat";
  10:                 regulator-min-microvolt = <5000000>;
  11:                 regulator-max-microvolt = <5000000>;
  12:                 regulator-always-on;
  13:         };
  14:  
  15:         dvdd_ts_reg: regulator@1 {
  16:                 compatible = "regulator-fixed";
  17:                 reg = <1>;
  18:                 regulator-name = "dvdd_ts";
  19:                 regulator-min-microvolt = <1800000>;
  20:                 regulator-max-microvolt = <1800000>;
  21:                 enable-active-high;
  22:                 gpio = <&gpio TEGRA_GPIO(H, 5) GPIO_ACTIVE_HIGH>;
  23:         };
  24:         ...
  25: };

 

在回到剛纔的話題上,kernel只為二級node創建platform device(這裡的“regulators”),那三級node(一個個的regulator)呢?沒有相對標準的bus幫它們創建怎麼辦?藉助“simple-bus”,具體可以參考of_platform_bus_create(“Device Tree(三):代碼分析”)。

另外,這裡的例子比較簡單,都是fixed regulator,regulator framework core可以幫忙實現fixed類型的regulator的驅動,後面會說明。

 

2.3 編寫與DTS節點對應的driver

 這些driver的存在形式是多種多樣的,但所做的工作基本類似:

1)初始化regulator的宿主(如上面的tps5163、PMIC、等等),最終的目的是,通過宿主提供的介面,修改regulator的輸出。

2)初始化用於描述regulator的靜態信息(struct regulator_desc)和動態信息(struct regulator_config),並以這二者為參數,調用regulator_register介面,將regulator註冊到kernel中。

3)靜態信息中包含regulator的操作函數集(struct regulator_ops),後續regulator的控制,將會由regulator framework core直接調用這些回調函數完成。

4)後面的事情,例如sysfs attribute創建等,就交給regulator framework core了。

 

3. DTS相關的實現邏輯

3.1 DTS的內容

回憶一下“Linux Regulator Framework(1)_概述”中介紹的machine的主要功能:使用軟體語言(struct regulator_init_data),靜態的描述regulator在板級的物理現狀。對regulator driver而言,DTS主要用於配置regulator的init data。先看一下struct regulator_init_data:

 
   1: /**
   2:  * struct regulator_init_data - regulator platform initialisation data.
   3:  *
   4:  * Initialisation constraints, our supply and consumers supplies.
   5:  *
   6:  * @supply_regulator: Parent regulator.  Specified using the regulator name
   7:  *                    as it appears in the name field in sysfs, which can
   8:  *                    be explicitly set using the constraints field 'name'.
   9:  *
  10:  * @constraints: Constraints.  These must be specified for the regulator to
  11:  *               be usable.
  12:  * @num_consumer_supplies: Number of consumer device supplies.
  13:  * @consumer_supplies: Consumer device supply configuration.
  14:  *
  15:  * @regulator_init: Callback invoked when the regulator has been registered.
  16:  * @driver_data: Data passed to regulator_init.
  17:  */
  18: struct regulator_init_data {
  19:         const char *supply_regulator;        /* or NULL for system supply */
  20:  
  21:         struct regulation_constraints constraints;
  22:  
  23:         int num_consumer_supplies;
  24:         struct regulator_consumer_supply *consumer_supplies;
  25:  
  26:         /* optional regulator machine specific init */
  27:         int (*regulator_init)(void *driver_data);
  28:         void *driver_data;      /* core does not touch this */
  29: };

supply_regulator,該regulator的前級regulator,一般在regulator driver中直接指定;

constraints,該regulator的使用限制,由DTS配置,並可以藉助regulator core提供的輔助API(regulator_of_get_init_data)自動解析。後面會詳細介紹;

num_consumer_supplies、consumer_supplies,使用該regulator的consumer的個數,及其設備名和supply名的map。用於建立consumer設備和regulator之間的關聯,後面介紹consumer DTS時再詳細說明;

regulator_init,regulator的init回調,由regulator driver提供,併在regulator註冊時調用;

driver_data,保存driver的私有數據,併在調用regulator_init時傳入。

 

看來DTS的內容都在struct regulation_constraints中,該結構保存了該regulator所有的物理限制,如下:

   1: struct regulation_constraints {
   2:  
   3:         const char *name;
   4:  
   5:         /* voltage output range (inclusive) - for voltage control */
   6:         int min_uV;
   7:         int max_uV;
   8:  
   9:         int uV_offset;
  10:  
  11:         /* current output range (inclusive) - for current control */
  12:         int min_uA;
  13:         int max_uA;
  14:  
  15:         /* valid regulator operating modes for this machine */
  16:         unsigned int valid_modes_mask;
  17:  
  18:         /* valid operations for regulator on this machine */
  19:         unsigned int valid_ops_mask;
  20:  
  21:         /* regulator input voltage - only if supply is another regulator */
  22:         int input_uV;
  23:  
  24:         /* regulator suspend states for global PMIC STANDBY/HIBERNATE */
  25:         struct regulator_state state_disk;
  26:         struct regulator_state state_mem;
  27:         struct regulator_state state_standby;
  28:         suspend_state_t initial_state; /* suspend state to set at init */
  29:  
  30:         /* mode to set on startup */
  31:         unsigned int initial_mode;
  32:  
  33:         unsigned int ramp_delay;
  34:         unsigned int enable_time;
  35:  
  36:         /* constraint flags */
  37:         unsigned always_on:1;   /* regulator never off when system is on */
  38:         unsigned boot_on:1;     /* bootloader/firmware enabled regulator */
  39:         unsigned apply_uV:1;    /* apply uV constraint if min == max */
  40:         unsigned ramp_disable:1; /* disable ramp delay */
  41: };

 

3.2 DTS的解析

regulator的DTS信息,可以通過兩種方法解析:

1)在regulator註冊前,調用of_get_regulator_init_data介面自行解析,該介面的實現如下:

   1: struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
   2:                                                 struct device_node *node)
   3: {
   4:         struct regulator_init_data *init_data;
   5:  
   6:         if (!node)
   7:                 return NULL;
   8:  
   9:         init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
  10:         if (!init_data)
  11:                 return NULL; /* Out of memory? */
  12:  
  13:         of_get_regulation_constraints(node, &init_data);
  14:         return init_data;
  15: }
  16: EXPORT_SYMBOL_GPL(of_get_regulator_init_data);

 該介面有兩個輸入參數:設備指針,以及包含了DTS信息的node指針(以3.1中的例子,即“tps51632@43”所在的node)。

它會分配一個struct regulator_init_data變數,並調用of_get_regulation_constraints解析DTS,把結果保存在該變數中。

最後返回struct regulator_init_data變數的地址。

 

 

2)在regulator註冊時,由regulator_register調用regulator_of_get_init_data幫忙解析,該介面的實現如下:

   1: struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
   2:                                             const struct regulator_desc *desc,
   3:                                             struct device_node **node)
   4: {
   5:         struct device_node *search, *child;
   6:         struct regulator_init_data *init_data = NULL;
   7:         const char *name;
   8:  
   9:         if (!dev->of_node || !desc->of_match)
  10:                 return NULL;
  11:  
  12:         if (desc->regulators_node)
  13:                 search = of_get_child_by_name(dev->of_node,
  14:                                               desc->regulators_node);
  15:         else
  16:                 search = dev->of_node;
  17:  
  18:         if (!search) {
  19:                 dev_dbg(dev, "Failed to find regulator container node '%s'\n",
  20:                         desc->regulators_node);
  21:                 return NULL;
  22:         }
  23:  
  24:         for_each_child_of_node(search, child) {
  25:                 name = of_get_property(child, "regulator-compatible", NULL);
  26:                 if (!name)
  27:                         name = child->name;
  28:  
  29:                 if (strcmp(desc->of_match, name))
  30:                         continue;
  31:  
  32:                 init_data = of_get_regulator_init_data(dev, child);
  33:                 if (!init_data) {
  34:                         dev_err(dev,
  35:                                 "failed to parse DT for regulator %s\n",
  36:                                 child->name);
  37:                         break;
  38:                 }
  39:  
  40:                 of_node_get(child);
  41:                 *node = child;
  42:                 break;
  43:         }
  44:         of_node_put(search);
  45:  
  46:         return init_data;
  47: }

 與of_get_regulator_init_data不同的是,該介面以struct regulator_desc指針為參數,該參數提供了regulator DTS有關的搜索信息(desc->of_match),根據這些信息,可以獲得包含regulator信息的DTS node。

它本質上是一種通用的DTS匹配邏輯(和kernel解析platform device的標準資源類似),大致如下:

a)調用者提供parent node(struct device指針中,代表regulators的宿主設備,如上面的tps65090@48),以及該regulator在DTS中的名稱(由desc->of_match提供)。

b)還可以在struct regulator_desc中提供包含regulator DTS信息的node名稱(可選,用於regulator不直接在parent node下的情況)。

c)以parent device的node,或者指定的子node為基準,查找其下所有的node,如果node的名字或者“regulator-compatible”欄位和desc->of_match匹配,則調用of_get_regulator_init_data從中解析DTS信息。

總結:1、2兩種DTS解析的方法,各有優缺點:1直接,方便,容易理解,但會有冗餘代碼;2簡潔,但需要regulator driver開發者非常熟悉解析的原理,並以此設計DTS和struct regulator_desc變數。大家可以根據實際情況,靈活使用。

 

4. 主要數據結構

 4.1 struct regulator_desc

   1: /* include/linux/regulator/driver.h */
   2:  
   3: struct regulator_desc {
   4:         const char *name;
   5:         const char *supply_name;
   6:         const char *of_match;
   7:         const char *regulators_node;
   8:         int id;
   9:         bool continuous_voltage_range;
  10:         unsigned n_voltages;
  11:         const struct regulator_ops *ops;
  12:         int irq;
  13:         enum regulator_type type;
  14:         struct module *owner;
  15:  
  16:         unsigned int min_uV;
  17:         unsigned int uV_step;
  18:         unsigned int linear_min_sel;
  19:         int fixed_uV;
  20:         unsigned int ramp_delay;
  21:  
  22:         const struct regulator_linear_range *linear_ranges;
  23:         int n_linear_ranges;
  24:  
  25:         const unsigned int *volt_table;
  26:  
  27:         unsigned int vsel_reg;
  28:         unsigned int vsel_mask;
  29:         unsigned int apply_reg;
  30:         unsigned int apply_bit;
  31:         unsigned int enable_reg;
  32:         unsigned int enable_mask;
  33:         unsigned int enable_val;
  34:         unsigned int disable_val;
  35:         bool enable_is_inverted;
  36:         unsigned int bypass_reg;
  37:         unsigned int bypass_mask;
  38:         unsigned int bypass_val_on;
  39:         unsigned int bypass_val_off;
  40:  
  41:         unsigned int enable_time;
  42:  
  43:         unsigned int off_on_delay;
  44: };

 

4.2 struct regulator_config

 struct regulator_config保存了regulator的動態信息,所謂的動態信息,是指那些會在driver運行過程中改變、或者driver運行後才會確定的信息,如下:

   1: struct regulator_config {
   2:         struct device *dev;
   3:         const struct regulator_init_data *init_data;
   4:         void *driver_data;
   5:         struct device_node *of_node;
   6:         struct regmap *regmap;
   7:  
   8:         int ena_gpio;
   9:         unsigned int ena_gpio_invert:1;
  10:         unsigned int ena_gpio_flags;
  11: };

 

dev,對應的struct device指針。會在regulator_register時,由regulator core分配,保存在此,以便後續使用;

init_data,init data指針,在解析DTS後,保存在此,以便後續使用;

of_node,可以為空;

regmap,參考後續描述;

ena_gpio、ena_gpio_invert、ena_gpio_flags,控制regulator使能的GPIO及其active極性。

 

4.3 struct regulator_dev

struct regulator_dev是regulator設備的抽象,當driver以struct regulator_desc、struct regulator_config兩個類型的參數,調用regulator_register將regulator註冊到kernel之後,regulator就會分配一個struct regulator_dev變數,後續所有的regulator操作,都將以該變數為對象。

 
   1: struct regulator_dev {
   2:         const struct regulator_desc *desc;
   3:         int exclusive;
   4:         u32 use_count;
   5:         u32 open_count;
   6:         u32 bypass_count;
   7:  
   8:         /* lists we belong to */
   9:         struct list_head list; /* list of all regulators */
  10:  
  11:         /* lists we own */
  12:         struct list_head consumer_list; /* consumers we supply */
  13:  
  14:         struct blocking_notifier_head notifier;
  15:         struct mutex mutex; /* consumer lock */
  16:         struct module *owner;
  17:         struct device dev;
  18:         struct regulation_constraints *constraints;
  19:         struct regulator *supply;       /* for tree */
  20:         struct regmap *regmap;
  21:  
  22:         struct delayed_work disable_work;
  23:         int deferred_disables;
  24:  
  25:         void *reg_data;         /* regulator_dev data */
  26:  
  27:         struct dentry *debugfs;
  28:  
  29:         struct regulator_enable_gpio *ena_pin;
  30:         unsigned int ena_gpio_state:1;
  31:  
  32:         /* time when this regulator was disabled last time */
  33:         unsigned long last_off_jiffy;
  34: };

desc,保存了regulator靜態描述信息的指針(從這個角度看,所謂的靜態描述,其變數必須為全局變數);

exclusive、use_count、open_count、bypass_count,一些狀態記錄;

constraints,保存了regulator的constraints指針;

supply,該regulator的supply;

等等。

 

 

5 實現邏輯分析

本章簡單的分析一下regulator driver相關的實現邏輯。如果要理解有些邏輯,必須具備一些regulator的基礎知識,因此在需要的時候,會穿插介紹這些知識。

 

5.1 regulator core的初始化

regulator core的初始化操作由regulator_init介面負責,主要工作包括:

1)註冊regulator class(/sys/class/regulator/)。

2)註冊用於調試的debugfs。

和power switch class、input class等類似,regulator framework也是一種class,可以稱作regulator class。

 

5.2 regulator register

regulator的註冊,由regulator_register/devm_regulator_register介面負責,如下:

   1: /**
   2:  * regulator_register - register regulator
   3:  * @regulator_desc: regulator to register
   4:  * @config: runtime configuration for regulator
   5:  *
   6:  * Called by regulator drivers to register a regulator.
   7:  * Returns a valid pointer to struct regulator_dev on success
   8:  * or an ERR_PTR() on error.
   9:  */
  10: struct regulator_dev *
  11: regulator_register(const struct regulator_desc *regulator_desc,
  12:            const struct regulator_config *config)
  13: {
  14:     const struct regulation_constraints *constraints = NULL;
  15:     const struct regulator_init_data *init_data;
  16:     static atomic_t regulator_no = ATOMIC_INIT(0);
  17:     struct regulator_dev *rdev;
  18:     struct device *dev;
  19:     int ret, i;
  20:     const char *supply = NULL;
  21:  
  22:     if (regulator_desc == NULL || config == NULL)
  23:         return ERR_PTR(-EINVAL);
  24:  
  25:     dev = config->dev;
  26:     WARN_ON(!dev);
  27:  
  28:     if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
  29:         return ERR_PTR(-EINVAL);
  30:  
  31:     if (regulator_desc->type != REGULATOR_VOLTAGE &&
  32:         regulator_desc->type != REGULATOR_CURRENT)
  33:         return ERR_PTR(-EINVAL);
  34:  
  35:     /* Only one of each should be implemented */
  36:     WARN_ON(regulator_desc->ops->get_voltage &&
  37:         regulator_desc->ops->get_voltage_sel);
  38:     WARN_ON(regulator_desc->ops->set_voltage &&
  39:         regulator_desc->ops->set_voltage_sel);
  40:  
  41:     /* If we're using selectors we must implement list_voltage. */
  42:     if (regulator_desc->ops->get_voltage_sel &&
  43:         !regulator_desc->ops->list_voltage) {
  44:         return ERR_PTR(-EINVAL);
  45:     }
  46:     if (regulator_desc->ops->set_voltage_sel &&
  47:         !regulator_desc->ops->list_voltage) {
  48:         return ERR_PTR(-EINVAL);
  49:     }
  50:  
  51:     rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
  52:     if (rdev == NULL)
  53:         return ERR_PTR(-ENOMEM);
  54:  
  55:     init_data = regulator_of_get_init_data(dev, regulator_desc,
  56:                            &rdev->dev.of_node);
  57:     if (!init_data) {
  58:         init_data = config->init_data;
  59:         rdev->dev.of_node = of_node_get(config->of_node);
  60:     }
  61:  
  62:     mutex_lock(®ulator_list_mutex);
  63:  
  64:     mutex_init(&rdev->mutex);
  65:     rdev->reg_data = config->driver_data;
  66:     rdev->owner = regulator_desc->owner;
  67:     rdev->desc = regulator_desc;
  68:     if (config->regmap)
  69:         rdev->regmap = config->regmap;
  70:     else if (dev_get_regmap(dev, NULL))
  71:         rdev->regmap = dev_get_regmap(dev, NULL);
  72:     else if (dev->parent)
  73:         rdev->regmap = dev_get_regmap(dev->parent, NULL);
  74:     INIT_LIST_HEAD(&rdev->consumer_list);
  75:     INIT_LIST_HEAD(&rdev->list);
  76:     BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
  77:     INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
  78:  
  79:     
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 歸併排序就這麼簡單 從前面已經講解了冒泡排序、選擇排序、插入排序,快速排序了,本章主要講解的是 歸併排序 ,希望大家看完能夠理解並手寫出歸併排序快速排序的代碼,然後就通過面試了!如果我寫得有錯誤的地方也請大家在評論下指出。 歸併排序的介紹 來源百度百科: 歸併排序(MERGE SORT)是建立在歸併 ...
  • 最近重構某項目過程中發現的,有同事反饋調試不正常,很久以前也發生過,雖然搜索了一下找到解決方案,但個人覺得還是有必要再記錄一下。 調試某CS結構的應用程式,大致效果可以看下圖: 我們組最終解決方案是:將編譯的目標平臺設置為X64而不是AnyCPU或者X86。 這個問題,我在前廠開發過一個OCR(光學 ...
  • nuget獲取Newtonsoft.Json github地址: "Newtonsoft.Json" ...
  • //定義報表模板 private GridppReport Report = new GridppReport(); //載入報表模板數據 Report.LoadFromFile(GridppReportDemo.Utility.GetReportTemplatePath() + "program\ ...
  • 1、添加引用Newtonsoft.Json.dll 2、具體代碼: ...
  • 概述 前幾天的 Windows Developer Day 正式發佈了 Windows AI Platform,而作為 Windows AI Platform 的模型定義和訓練,更多還是需要藉助雲端來實現。Azure 無疑是一個很好的選擇。 Azure 作為微軟近幾年主推的雲服務,在 AI 和 Ma ...
  • 新建目錄www 下載nodejs 解壓 測試是否安裝成功 進入解壓目錄下的 bin 目錄,執行 ls 命令 有node 和 npm 測試 安裝成功 現在 node 和 npm 還不能全局使用,做個鏈接 可以在任何目錄下執行 node 和 npm 命令 最主要的原因還是在NPM上,因為用了n來管理no ...
  • VMware14安裝Ubuntu16.04教程 久聞Linux(這單詞念做 林尼克斯??)大名,閑來無事就試著給自己筆記本裝一個玩玩,從朋友口中得知可以在Vmware上裝虛擬機,就自己試著嘗試一下,順便隨意記錄一下過程。 1. Vmware14的安裝 百度Vmware14,直接點普通下載就好,接下來 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...