/***************************************************************************
* Linux power supply class hacking
* 声明:
* 本文主要是记录linux电源管理的工作机制是什么,那些供Android jni使用
* 的属性文件是如何生成的,调用机制是什么。
*
* 2016-2-23 深圳 南山平山村 曾剑锋
**************************************************************************/ static int __init power_supply_class_init(void)
{
power_supply_class = class_create(THIS_MODULE, "power_supply"); if (IS_ERR(power_supply_class))
return PTR_ERR(power_supply_class); power_supply_class->dev_uevent = power_supply_uevent; ------------------+
power_supply_init_attrs(&power_supply_dev_type); ------------------*-+
| | |
return ; +--------------------------------------------------------+ | |
} | | |
| | |
static void __exit power_supply_class_exit(void) | | |
{ | | |
class_destroy(power_supply_class); | | |
} | | |
| | |
subsys_initcall(power_supply_class_init); | | |
module_exit(power_supply_class_exit); | | |
| | |
MODULE_DESCRIPTION("Universal power supply monitor class"); | | |
MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, " | | |
"Szabolcs Gyurko, " | | |
"Anton Vorontsov <cbou@mail.ru>"); | | |
MODULE_LICENSE("GPL"); | | |
| | |
int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) <-*-+ |
{ | |
struct power_supply *psy = dev_get_drvdata(dev); | |
int ret = , j; | |
char *prop_buf; | |
char *attrname; | |
| |
dev_dbg(dev, "uevent\n"); | |
| |
if (!psy || !psy->dev) { | |
dev_dbg(dev, "No power supply yet\n"); | |
return ret; | |
} | |
| |
dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name); | |
| |
ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name); | |
if (ret) | |
return ret; | |
| |
prop_buf = (char *)get_zeroed_page(GFP_KERNEL); | |
if (!prop_buf) | |
return -ENOMEM; | |
| |
for (j = ; j < psy->num_properties; j++) { | |
struct device_attribute *attr; | |
char *line; | |
| |
attr = &power_supply_attrs[psy->properties[j]]; | |
| |
ret = power_supply_show_property(dev, attr, prop_buf); | |
if (ret == -ENODEV || ret == -ENODATA) { | |
/* When a battery is absent, we expect -ENODEV. Don't abort; | |
send the uevent with at least the the PRESENT=0 property */ | |
ret = ; | |
continue; | |
} | |
| |
if (ret < ) | |
goto out; | |
| |
line = strchr(prop_buf, '\n'); | |
if (line) | |
*line = ; | |
| |
attrname = kstruprdup(attr->attr.name, GFP_KERNEL); | |
if (!attrname) { | |
ret = -ENOMEM; | |
goto out; | |
} | |
| |
dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf); | |
| |
ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); | |
kfree(attrname); | |
if (ret) | |
goto out; | |
} | |
| |
out: | |
free_page((unsigned long)prop_buf); | |
| |
return ret; | |
} | |
| |
static struct device_type power_supply_dev_type; <--------------------*---+
^ |
/* +-----------------------------------------------+ |
* The type of device, "struct device" is embedded in. A class | |
* or bus can contain devices of different types | |
* like "partitions" and "disks", "mouse" and "event". | |
* This identifies the device type and carries type-specific | |
* information, equivalent to the kobj_type of a kobject. | |
* If "name" is specified, the uevent will contain it in | |
* the DEVTYPE variable. | |
*/ | |
struct device_type { <----------------------+ |
const char *name; |
const struct attribute_group **groups; |
int (*uevent)(struct device *dev, struct kobj_uevent_env *env); |
char *(*devnode)(struct device *dev, mode_t *mode); |
void (*release)(struct device *dev); |
|
const struct dev_pm_ops *pm; |
}; |
|
void power_supply_init_attrs(struct device_type *dev_type) <------------+
{
int i;
----------+
dev_type->groups = power_supply_attr_groups; |
|
for (i = ; i < ARRAY_SIZE(power_supply_attrs); i++) |
__power_supply_attrs[i] = &power_supply_attrs[i].attr; ------+ |
} | |
| |
static const struct attribute_group *power_supply_attr_groups[] = { <--*-+
&power_supply_attr_group, ------------+ |
NULL, | |
}; | |
| |
static struct attribute_group power_supply_attr_group = { <-----+ |
.attrs = __power_supply_attrs, ------+ |
.is_visible = power_supply_attr_is_visible, | |
}; | |
| |
static struct attribute * | |
__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + ]; <-----+ --+
|
/* Must be in the same order as POWER_SUPPLY_PROP_* */ |
static struct device_attribute power_supply_attrs[] = { <-----------+
/* Properties of type `int' */
POWER_SUPPLY_ATTR(status),
POWER_SUPPLY_ATTR(charge_type),
POWER_SUPPLY_ATTR(health),
POWER_SUPPLY_ATTR(present),
POWER_SUPPLY_ATTR(online),
POWER_SUPPLY_ATTR(technology),
POWER_SUPPLY_ATTR(cycle_count),
POWER_SUPPLY_ATTR(voltage_max),
POWER_SUPPLY_ATTR(voltage_min),
POWER_SUPPLY_ATTR(voltage_max_design),
POWER_SUPPLY_ATTR(voltage_min_design),
POWER_SUPPLY_ATTR(voltage_now),
POWER_SUPPLY_ATTR(voltage_avg),
POWER_SUPPLY_ATTR(current_max),
POWER_SUPPLY_ATTR(current_now),
POWER_SUPPLY_ATTR(current_avg),
POWER_SUPPLY_ATTR(power_now),
POWER_SUPPLY_ATTR(power_avg),
POWER_SUPPLY_ATTR(charge_full_design),
POWER_SUPPLY_ATTR(charge_empty_design),
POWER_SUPPLY_ATTR(charge_full),
POWER_SUPPLY_ATTR(charge_empty),
POWER_SUPPLY_ATTR(charge_now),
POWER_SUPPLY_ATTR(charge_avg),
POWER_SUPPLY_ATTR(charge_counter),
POWER_SUPPLY_ATTR(energy_full_design),
POWER_SUPPLY_ATTR(energy_empty_design),
POWER_SUPPLY_ATTR(energy_full),
POWER_SUPPLY_ATTR(energy_empty),
POWER_SUPPLY_ATTR(energy_now),
POWER_SUPPLY_ATTR(energy_avg),
POWER_SUPPLY_ATTR(capacity),
POWER_SUPPLY_ATTR(capacity_level),
POWER_SUPPLY_ATTR(temp),
POWER_SUPPLY_ATTR(temp_ambient),
POWER_SUPPLY_ATTR(time_to_empty_now),
POWER_SUPPLY_ATTR(time_to_empty_avg),
POWER_SUPPLY_ATTR(time_to_full_now),
POWER_SUPPLY_ATTR(time_to_full_avg),
POWER_SUPPLY_ATTR(type),
/* Properties of type `const char *' */
POWER_SUPPLY_ATTR(model_name), --------------+
POWER_SUPPLY_ATTR(manufacturer), |
POWER_SUPPLY_ATTR(serial_number), |
}; +--------------------------------------+
v
#define POWER_SUPPLY_ATTR(_name) \
{ \
.attr = { .name = #_name }, \
.show = power_supply_show_property, \ ---------+
.store = power_supply_store_property, \ ---------*-+
} | |
| |
static ssize_t power_supply_show_property(struct device *dev, <-----+ |
struct device_attribute *attr, |
char *buf) { |
static char *type_text[] = { |
"Battery", "UPS", "Mains", "USB", |
"USB_DCP", "USB_CDP", "USB_ACA" |
}; |
static char *status_text[] = { |
"Unknown", "Charging", "Discharging", "Not charging", "Full" |
}; |
static char *charge_type[] = { |
"Unknown", "N/A", "Trickle", "Fast" |
}; |
static char *health_text[] = { |
"Unknown", "Good", "Overheat", "Dead", "Over voltage", |
"Unspecified failure", "Cold", |
}; |
static char *technology_text[] = { |
"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd", |
"LiMn" |
}; |
static char *capacity_level_text[] = { |
"Unknown", "Critical", "Low", "Normal", "High", "Full" |
}; |
ssize_t ret = ; |
struct power_supply *psy = dev_get_drvdata(dev); --------*-+
const ptrdiff_t off = attr - power_supply_attrs; | |
union power_supply_propval value; | |
| |
if (off == POWER_SUPPLY_PROP_TYPE) | |
value.intval = psy->type; | |
else | |
ret = psy->get_property(psy, off, &value); <-------*-*------+
| | |
if (ret < ) { | | |
if (ret == -ENODATA) | | |
dev_dbg(dev, "driver has no data for `%s' property\n", | | |
attr->attr.name); | | |
else if (ret != -ENODEV) | | |
dev_err(dev, "driver failed to report `%s' property\n", | | |
attr->attr.name); | | |
return ret; | | |
} | | |
| | |
if (off == POWER_SUPPLY_PROP_STATUS) | | |
return sprintf(buf, "%s\n", status_text[value.intval]); | | |
else if (off == POWER_SUPPLY_PROP_CHARGE_TYPE) | | |
return sprintf(buf, "%s\n", charge_type[value.intval]); | | |
else if (off == POWER_SUPPLY_PROP_HEALTH) | | |
return sprintf(buf, "%s\n", health_text[value.intval]); | | |
else if (off == POWER_SUPPLY_PROP_TECHNOLOGY) | | |
return sprintf(buf, "%s\n", technology_text[value.intval]); | | |
else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL) | | |
return sprintf(buf, "%s\n", capacity_level_text[value.intval]); | | |
else if (off == POWER_SUPPLY_PROP_TYPE) | | |
return sprintf(buf, "%s\n", type_text[value.intval]); | | |
else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) | | |
return sprintf(buf, "%s\n", value.strval); | | |
| | |
return sprintf(buf, "%d\n", value.intval); | | |
} | | |
| | |
static ssize_t power_supply_store_property(struct device *dev, <-------+ | |
struct device_attribute *attr, | |
const char *buf, size_t count) { | |
ssize_t ret; | |
struct power_supply *psy = dev_get_drvdata(dev); ----------+ |
const ptrdiff_t off = attr - power_supply_attrs; | |
union power_supply_propval value; | |
long long_val; | |
| |
/* TODO: support other types than int */ | |
ret = strict_strtol(buf, , &long_val); | |
if (ret < ) | |
return ret; | |
| |
value.intval = long_val; | |
| |
ret = psy->set_property(psy, off, &value); | |
if (ret < ) | |
return ret; | |
| |
return count; | |
} | |
| |
void *dev_get_drvdata(const struct device *dev) <-----+ <----------+ |
{ + |
if (dev && dev->p) + |
return dev->p->driver_data; + |
return NULL; + |
} + |
EXPORT_SYMBOL(dev_get_drvdata); + |
+ |
int dev_set_drvdata(struct device *dev, void *data) <-----+ <----------+ |
{ | |
int error; | |
| |
if (!dev->p) { | |
error = device_private_init(dev); | |
if (error) | |
return error; | |
} | |
dev->p->driver_data = data; | |
return ; | |
} | |
EXPORT_SYMBOL(dev_set_drvdata); | |
| |
static inline void i2c_set_clientdata(struct i2c_client *dev, void *data) | ----+|
{ | ||
dev_set_drvdata(&dev->dev, data); -----------------------------+ ||
} ||
||
static int __init bq27x00_battery_probe(struct i2c_client *client, ||
const struct i2c_device_id *id) ||
{ ||
char *name; ||
struct bq27x00_device_info *di; ||
int num; ||
int retval = ; ||
u8 *regs; ||
||
/* Get new ID for the new battery device */ ||
retval = idr_pre_get(&battery_id, GFP_KERNEL); ||
if (retval == ) ||
return -ENOMEM; ||
mutex_lock(&battery_mutex); ||
retval = idr_get_new(&battery_id, client, &num); ||
mutex_unlock(&battery_mutex); ||
if (retval < ) ||
return retval; ||
||
name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num); ||
if (!name) { ||
dev_err(&client->dev, "failed to allocate device name\n"); ||
retval = -ENOMEM; ||
goto batt_failed_1; ||
} ||
||
di = kzalloc(sizeof(*di), GFP_KERNEL); ||
if (!di) { ||
dev_err(&client->dev, "failed to allocate device info data\n"); ||
retval = -ENOMEM; ||
goto batt_failed_2; ||
} ||
||
di->id = num; ||
di->dev = &client->dev; ||
di->chip = id->driver_data; ||
di->bat.name = name; ||
di->bus.read = &bq27xxx_read_i2c; ||
di->bus.write = &bq27xxx_write_i2c; ||
di->bus.blk_read = bq27xxx_read_i2c_blk; ||
di->bus.blk_write = bq27xxx_write_i2c_blk; ||
di->dm_regs = NULL; ||
di->dm_regs_count = ; ||
||
if (di->chip == BQ27200) ||
regs = bq27200_regs; ||
else if (di->chip == BQ27500) ||
regs = bq27500_regs; ||
else if (di->chip == BQ27520) ||
regs = bq27520_regs; ||
else if (di->chip == BQ2753X) ||
regs = bq2753x_regs; ||
else if (di->chip == BQ274XX) { ||
regs = bq274xx_regs; ||
di->dm_regs = bq274xx_dm_regs; ||
di->dm_regs_count = ARRAY_SIZE(bq274xx_dm_regs); ||
} else if (di->chip == BQ276XX) { ||
/* commands are same as bq274xx, only DM is different */ ||
regs = bq276xx_regs; ||
di->dm_regs = bq276xx_dm_regs; ||
di->dm_regs_count = ARRAY_SIZE(bq276xx_dm_regs); ||
} else { ||
dev_err(&client->dev, ||
"Unexpected gas gague: %d\n", di->chip); ||
regs = bq27520_regs; ||
} ||
||
memcpy(di->regs, regs, NUM_REGS); ||
||
di->fw_ver = bq27x00_battery_read_fw_version(di); ||
dev_info(&client->dev, "Gas Guage fw version is 0x%04x\n", di->fw_ver); ||
||
retval = bq27x00_powersupply_init(di); --------+ ||
if (retval) | ||
goto batt_failed_3; | ||
| ||
/* Schedule a polling after about 1 min */ | ||
schedule_delayed_work(&di->work, * HZ); | ||
| ||
i2c_set_clientdata(client, di); <-------|----+|
retval = sysfs_create_group(&client->dev.kobj, &bq27x00_attr_group); | |
if (retval) | |
dev_err(&client->dev, "could not create sysfs files\n"); | |
| |
return ; | |
| |
batt_failed_3: | |
kfree(di); | |
batt_failed_2: | |
kfree(name); | |
batt_failed_1: | |
mutex_lock(&battery_mutex); | |
idr_remove(&battery_id, num); | |
mutex_unlock(&battery_mutex); | |
| |
return retval; | |
} | |
| |
static int bq27x00_powersupply_init(struct bq27x00_device_info *di) <-----+ |
{ | |
int ret; +------------------+ |
v--------------------------------------------------------------*------+ |
di->bat.type = POWER_SUPPLY_TYPE_BATTERY; | | |
di->bat.properties = bq27x00_battery_props; | | |
di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); | | |
di->bat.get_property = bq27x00_battery_get_property; ------------+-*------*-+
di->bat.external_power_changed = bq27x00_external_power_changed; | | |
| | |
INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll); | | |
mutex_init(&di->lock); | | |
| | |
ret = power_supply_register(di->dev, &di->bat); ----------*-*------*----+
if (ret) { | | | |
dev_err(di->dev, "failed to register battery: %d\n", ret); | | | |
return ret; | | | |
} | | | |
| | | |
dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION); | | | |
| | | |
bq27x00_update(di); --------------*-*-+ | |
| | | | |
return ; | | | | |
} | | | | |
| | | | |
struct bq27x00_device_info { <--------*-+ | | |
struct device *dev; | | | |
int id; | | | |
enum bq27x00_chip chip; | | | |
| | | |
struct bq27x00_reg_cache cache; ---------+ <--------*---*----*---+|
int charge_design_full; | | | | ||
| | | | ||
unsigned long last_update; | | | | ||
struct delayed_work work; | | | | ||
| | | | ||
struct power_supply bat; | <--------*---*----+ ||
| | | ||
struct bq27x00_access_methods bus; | | | ||
| | | ||
struct mutex lock; | | | ||
}; | | | ||
| | | ||
struct bq27x00_reg_cache { <---------+ | | ||
int temperature; | | ||
int time_to_empty; | | ||
int time_to_empty_avg; | | ||
int time_to_full; | | ||
int charge_full; | | ||
int cycle_count; | | ||
int capacity; | | ||
int flags; | | ||
| | ||
int current_now; | | ||
}; | | ||
| | ||
static int bq27x00_battery_get_property(struct power_supply *psy, <---+ | ||
enum power_supply_property psp, | ||
union power_supply_propval *val) | ||
{ | ||
int ret = ; | ||
struct bq27x00_device_info *di = to_bq27x00_device_info(psy); | ||
| ||
mutex_lock(&di->lock); | ||
if (time_is_before_jiffies(di->last_update + * HZ)) { | ||
cancel_delayed_work_sync(&di->work); | ||
bq27x00_battery_poll(&di->work.work); | ||
} | ||
mutex_unlock(&di->lock); | ||
| ||
if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < ) | ||
return -ENODEV; | ||
| ||
switch (psp) { | ||
case POWER_SUPPLY_PROP_STATUS: | ||
ret = bq27x00_battery_status(di, val); | ||
break; | ||
case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
ret = bq27x00_battery_voltage(di, val); | ||
break; | ||
case POWER_SUPPLY_PROP_PRESENT: | ||
val->intval = di->cache.flags < ? : ; | ||
break; | ||
case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
ret = bq27x00_battery_current(di, val); | ||
break; | ||
case POWER_SUPPLY_PROP_CAPACITY: | ||
ret = bq27x00_simple_value(di->cache.capacity, val); | ||
break; | ||
case POWER_SUPPLY_PROP_TEMP: | ||
ret = bq27x00_battery_temperature(di, val); | ||
break; | ||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: | ||
ret = bq27x00_simple_value(di->cache.time_to_empty, val); | ||
break; | ||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | ||
ret = bq27x00_simple_value(di->cache.time_to_empty_avg, val); | ||
break; | ||
case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: | ||
ret = bq27x00_simple_value(di->cache.time_to_full, val); | ||
break; | ||
case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
val->intval = POWER_SUPPLY_TECHNOLOGY_LION; | ||
break; | ||
case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
ret = bq27x00_simple_value(bq27x00_battery_read_nac(di), val); | ||
break; | ||
case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
ret = bq27x00_simple_value(di->cache.charge_full, val); | ||
break; | ||
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
ret = bq27x00_simple_value(di->charge_design_full, val); | ||
break; | ||
case POWER_SUPPLY_PROP_CYCLE_COUNT: | ||
ret = bq27x00_simple_value(di->cache.cycle_count, val); | ||
break; | ||
case POWER_SUPPLY_PROP_ENERGY_NOW: | ||
ret = bq27x00_battery_energy(di, val); | ||
break; | ||
default: | ||
return -EINVAL; | ||
} | ||
| ||
return ret; | ||
} | ||
| ||
static void bq27x00_update(struct bq27x00_device_info *di) <------------+ ||
{ ||
struct bq27x00_reg_cache cache = {, }; ||
bool is_bq27500 = di->chip == BQ27500; ||
||
cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500); ||
if (cache.flags >= ) { ||
cache.capacity = bq27x00_battery_read_rsoc(di); ||
cache.temperature = bq27x00_read(di, BQ27x00_REG_TEMP, false); ||
cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); ||
cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);||
cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); ||
cache.charge_full = bq27x00_battery_read_lmd(di); ||
cache.cycle_count = bq27x00_battery_read_cyct(di); ||
||
if (!is_bq27500) ||
cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false); ||
||
/* We only have to read charge design full once */ ||
if (di->charge_design_full <= ) ||
di->charge_design_full = bq27x00_battery_read_ilmd(di); ||
} ||
||
/* Ignore current_now which is a snapshot of the current battery state ||
* and is likely to be different even between two consecutive reads */ ||
if (memcmp(&di->cache, &cache, sizeof(cache) - sizeof(int)) != ) { ------+|
di->cache = cache; |
power_supply_changed(&di->bat); |
} |
|
di->last_update = jiffies; |
} |
|
int power_supply_register(struct device *parent, struct power_supply *psy) <------+
{
struct device *dev;
int rc; dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM; device_initialize(dev); dev->class = power_supply_class;
dev->type = &power_supply_dev_type;
dev->parent = parent;
dev->release = power_supply_dev_release;
dev_set_drvdata(dev, psy);
psy->dev = dev; INIT_WORK(&psy->changed_work, power_supply_changed_work); rc = kobject_set_name(&dev->kobj, "%s", psy->name);
if (rc)
goto kobject_set_name_failed; spin_lock_init(&psy->changed_lock);
wake_lock_init(&psy->work_wake_lock, WAKE_LOCK_SUSPEND, "power-supply"); rc = device_add(dev);
if (rc)
goto device_add_failed; rc = power_supply_create_triggers(psy);
if (rc)
goto create_triggers_failed; power_supply_changed(psy); goto success; create_triggers_failed:
wake_lock_destroy(&psy->work_wake_lock);
device_del(dev);
kobject_set_name_failed:
device_add_failed:
put_device(dev);
success:
return rc;
}
EXPORT_SYMBOL_GPL(power_supply_register);

Linux power supply class hacking的更多相关文章

  1. Linux power supply class(1)_软件架构及API汇整【转】

    1. 前言 power supply class为编写供电设备(power supply,后面简称PSY)的驱动提供了统一的框架,功能包括: 1)抽象PSY设备的共性,向用户空间提供统一的API. 2 ...

  2. ti processor sdk linux am335x evm Makefile hacking

    # # ti processor sdk linux am335x evm Makefile hacking # 说明: # 本文主要对TI的sdk中的Makefile脚本进行解读,是为了了解其工作机 ...

  3. I.MX6 Power off register hacking

    /*********************************************************************** * I.MX6 Power off register ...

  4. linux SPI bus demo hacking

    /********************************************************************** * linux SPI bus demo hacking ...

  5. Linux Power Managment详解 【转】

    转自:http://blog.chinaunix.net/uid-24517893-id-254740.html Linux Power Managment 谨以此文纪念过往的岁月 一.前言 在这个对 ...

  6. I.MX6 Linux Serial Baud Rate hacking

    /******************************************************************************** * I.MX6 Linux Seri ...

  7. I.MX6 Linux I2C device& driver hacking

    /******************************************************************************************* * I.MX6 ...

  8. Level-shifting nixes need for dual power supply

    The AD736 true-rms-to-dcconverter is useful for many applications that require precise calculation o ...

  9. Programmable current source requires no power supply

    Engineering labs are usually equipped with various power supplies, voltmeters, function generators, ...

随机推荐

  1. Spark Streaming揭秘 Day7 再探Job Scheduler

    Spark Streaming揭秘 Day7 再探Job Scheduler 今天,我们对Job Scheduler再进一步深入一下,对一些更加细节的源码进行分析. Job Scheduler启动 在 ...

  2. numpy简单入门

    声明:本文大量参考https://www.dataquest.io/mission/6/getting-started-with-numpy(建议阅读原文)   读取文件 有一个名为world_alc ...

  3. 利用rlwrap配置linux下oracle sqlplus 历史记录回调

    .下载rlwrap wget http://utopia.knoware.nl/~hlub/uck/rlwrap/rlwrap-0.42.tar.gz .解压 tar -xvzf rlwrap-0.4 ...

  4. PHP数组的操作

    一.数组操作的基本函数数组的键名和值array_values($arr);获得数组的值array_keys($arr);获得数组的键名array_flip($arr);数组中的值与键名互换(如果有重复 ...

  5. EXTJS 3.0 资料 控件之 combo 用法

    EXTJS combo 控件: 1.先定义store //年款 var comboData_ReleasYear = [ ['], ['], ['], ['] ]; 2.定义combo控件 { lay ...

  6. EXTJS 4.2 资料 控件之 Store 用法

    最近工作,发现在Extjs中自定义Store的功能挺多,特意在此做笔记,几下来,具体代码如下: 1.定义Store //定义Store var ItemSelectorStore = new Ext. ...

  7. 通过物理模型生成Java代码

    通过物理模型生成Java代码 软件开发过程中,我们一般是先针对数据库建模,物理建模完成后,生成数据库表,编码阶段的时候我们会针对数据库表生成大量的Javaeban或者是实体类 Powertdesign ...

  8. 操作邮箱的类和文件的Md5【粘】

     MailMessage mailMsg = new MailMessage();//两个类,别混了,要引入System.Net这个Assembly             mailMsg.From ...

  9. BZOJ 1593: [Usaco2008 Feb]Hotel 旅馆

    Description 奶牛们最近的旅游计划,是到苏必利尔湖畔,享受那里的湖光山色,以及明媚的阳光.作为整个旅游的策划者和负责人,贝茜选择在湖边的一家著名的旅馆住宿.这个巨大的旅馆一共有N (1 &l ...

  10. DWR

    DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站.它可以允许在浏览器里的代码使用运行在 ...