RK3568 Android11 sh366006驱动

news2025/3/21 0:25:51

sh366006.c

/* 
    谁愿压抑心中怒愤冲动
    咒骂这虚与伪与假
    从没信要屈膝面对生命
    纵没有别人帮
    一生只靠我双手
    让我放声疯狂叫囔
    今天的他 呼风可改雨
    不可一世太嚣张 
                --《不可一世》Beyond
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/workqueue.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/sizes.h>

#define SHFG_ENABLE_LOG 1

#define SH_PROPERTIES "sh366006-bat"

#define SHFG_NAME "sh366006"

#define sh_printk(fmt, arg...)                                                 \
	{                                                                          \
		if (SHFG_ENABLE_LOG)                                                   \
			printk(KERN_INFO "SH366006 : %s-%d : " fmt, __FUNCTION__ ,__LINE__,##arg);  \
		else {}                                                                \
	}

#define queue_delayed_work_time  1000
#define queue_start_work_time    50

#define SH366006_SMBUS_ADDR        0x16
#define SH366006_MANUFACTURER_DATA 0x07

static const uint8_t crc8_table[256] =

{

    0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,

    0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,

    0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,

    0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,

    0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,

    0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,

    0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,

    0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,

    0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,

    0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,

    0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,

    0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,

    0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,

    0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,

    0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,

    0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3

};



/* 完整的SBS Command Codes (0x00-0x3F) */
enum sh366006_commands {
    MANUFACTURER_ACCESS     = 0x00,  // 制造商访问
    DEVICE_TYPE             = 0x01,  // 设备类型
    REMAINING_CAPACITY      = 0x0F,  // 剩余容量(mAh)
    VOLTAGE                 = 0x09,  // 电池电压(mV)
    CURRENT                 = 0x0A,  // 实时电流(mA)
    AVERAGE_CURRENT         = 0x0B,  // 平均电流(mA)
    RELATIVE_SOC            = 0x0D,  // 相对电量百分比(%)
    ABSOLUTE_SOC            = 0x0E,  // 绝对电量百分比(%)
    HEALTHY_SOC             = 0x4F,  // 电池健康度
    TEMPERATURE             = 0x08,  // 温度(0.1K)
    FULL_CHARGE_CAPACITY    = 0x10,  // 满电容量
    BATTERY_STATUS          = 0x16,  // 电池状态字
    CYCLE_COUNT             = 0x17,  // 循环次数
    DESIGN_CAPACITY         = 0x18,  // 设计容量(mAh)
    DESIGN_VOLTAGE          = 0x19,  // 标称电压(mV)
    SPECIFICATION_INFO      = 0x1A,  // 规格信息
    MANUFACTURE_DATE        = 0x1B,  // 生产日期
    SERIAL_NUMBER           = 0x1C,  // 序列号
    CELL_VOLTAGE_1          = 0x3C,  // 第1节电压(mV)
    CELL_VOLTAGE_2          = 0x3D,  // 第2节电压(mV)
    CELL_VOLTAGE_3          = 0x3E,  // 第3节电压(mV)
    CELL_VOLTAGE_4          = 0x3F,  // 第4节电压(mV)
    
    // 安全扩展命令(0x20-0x2F)
    SAFETY_STATUS           = 0x20,  // 安全状态寄存器
    SAFETY_ALERT            = 0x21,  // 安全警报阈值
    SAFETY_STATUS_EXT       = 0x22,  // 扩展安全状态
    CHG_VOLTAGE             = 0x30,  // 充电电压设置(mV)
    CHG_CURRENT             = 0x31,  // 充电电流设置(mA)
    DISCHG_CURRENT          = 0x39,  // 放电电流限制(mA)
    
    // 制造商专用命令(0x40-0x5F)
    QMAX_UPDATE             = 0x41,  // Qmax校准命令
    BALANCE_CONTROL         = 0x42,  // 电池均衡控制
    JEITA_CONTROL           = 0x43,  // JEITA温度补偿
    SHA1_AUTH               = 0x44,  // SHA-1认证
    CELL_TEMP_1             = 0x50,  // 第1节温度
    CELL_TEMP_2             = 0x51,  // 第2节温度
    
    // 时间预测命令
    REMAINING_TIME          = 0x11,  // 剩余使用时间(min)
    AVG_TIME_TO_EMPTY       = 0x12,  // 平均耗尽时间
    AVG_TIME_TO_FULL        = 0x13,  // 平均充满时间
};

struct sh36606_chip {
    struct i2c_client *client;

    struct workqueue_struct *shfg_workqueue;
    struct delayed_work monitor_work;

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
	struct power_supply sh_bat;
#else
	struct power_supply *sh_bat;
#endif
    int battery_temp;
    int voltage;
    int soc;
    int battery_current;
    int cycle_count;
    int battery_healthy;
    int status;
};

static int sh_read_reg(struct i2c_client *client, u8 reg, u8 *buf, int len)
{
    struct i2c_msg msgs[2] = {
        {
            .addr = client->addr,
            .flags = 0,
            .len = 1,
            .buf = &reg,
        },
        {
            .addr = client->addr,
            .flags = I2C_M_RD,
            .len = len,
            .buf = buf,
        },
    };
    
    if (i2c_transfer(client->adapter, msgs, 2) != 2) {
        dev_err(&client->dev, "I2C read error\n");
        return -EIO;
    }
    return 0;
}

static int sh_write_reg(struct i2c_client *client, u8 reg, u8 val)
{
    u8 buf[2] = {reg, val};
    struct i2c_msg msg = {
        .addr = client->addr,
        .flags = 0,
        .len = 2,
        .buf = buf,
    };
    
    if (i2c_transfer(client->adapter, &msg, 1) != 1) {
        dev_err(&client->dev, "I2C write error\n");
        return -EIO;
    }
    return 0;
}

uint8_t crc8_check(uint8_t *data , uint16_t len)
{
	uint16_t i   = 0;
	uint8_t  fcs = 0;
	for(i=0 ; i<(len) ; i++)
	{
		fcs = crc8_table[(uint8_t)fcs ^ (*data)];
		data++;
	}
	return fcs;
}

  /*读SBS命令,返回两个字节数据
ID  :SBS命令号,只能是返回两个字节的子命令
value:返回的两字节数据组成的16bit数据

*/
int SH366100_Read_SBS_Word(struct i2c_client *client, uint8_t reg, uint16_t* val)
{
    uint8_t address = 0x16;
    uint8_t recieve_data[6] = {0x00};
    uint8_t crc_check = 0x00;
    recieve_data[0] = address;
    recieve_data[1] = reg;
    recieve_data[2] = address | 0x01;

    if(0 != sh_read_reg( client, reg, recieve_data+3, 3) ){
        *val = 0;
        return -1;
    }
    else{
        crc_check = crc8_check(recieve_data , 5);
        if(crc_check == recieve_data[5] ){
            *val = recieve_data[3] + (((uint16_t)recieve_data[4])<<8);
            return 0;
        }
        else{
            *val = 0;
            return -1;
        }
        
    }
}


static int sh366006_get_voltage(struct sh36606_chip *sh_chip)
{
    int ret;
    uint16_t reg_val[2] = {0, 0};
    unsigned int voltage;

    ret = SH366100_Read_SBS_Word(sh_chip->client, VOLTAGE, reg_val);
    if(ret <0 ) {
        sh_chip->voltage = 3000;
        return ret;
    }
    voltage = reg_val[0];
    sh_chip->voltage = voltage;
    return 0;
}


static int sh366006_get_cycle_count(struct sh36606_chip *sh_chip)
{
    int ret;
    uint16_t reg_val[2] = {0, 0};
    unsigned int cycle_count;

    ret = SH366100_Read_SBS_Word(sh_chip->client, CYCLE_COUNT, reg_val);
    if(ret <0 ) {

        sh_chip->cycle_count = 1;
        return ret;
    }
    cycle_count = reg_val[0];
    sh_chip->cycle_count = cycle_count;
    return 0;
}

static int sh366006_get_current(struct sh36606_chip *sh_chip)
{
    int ret;
    uint16_t reg_val[2] = {0, 0};
    unsigned int battery_current;
    
    ret = SH366100_Read_SBS_Word(sh_chip->client, AVERAGE_CURRENT, reg_val);
    if(ret <0 ) {
        sh_chip->battery_current = 65284;
        return ret;
    }

    battery_current = reg_val[0];
    sh_chip->battery_current = battery_current;
    return 0;
}

static int sh366006_get_soc(struct sh36606_chip *sh_chip)
{
    int ret;
    uint16_t reg_val[2] = {0, 0};
    unsigned int soc;

    ret = SH366100_Read_SBS_Word(sh_chip->client, RELATIVE_SOC, reg_val);

    if(ret <0 ) {
        sh_chip->soc = 1;
        return ret;
    }
    soc = reg_val[0] ;
    sh_chip->soc = soc;
    return 0;
}

static int sh366006_get_temperature(struct sh36606_chip *sh_chip)
{
    int ret;
    unsigned char reg_val[2] = {0, 0};
    unsigned int temperature;

    ret = SH366100_Read_SBS_Word(sh_chip->client, TEMPERATURE, reg_val);

    if(ret <0 ) {
        sh_chip->battery_temp = 26;
        return ret;
    }
    temperature = reg_val[0] ;
    sh_chip->battery_temp = temperature;
    return 0;
}


static int sh366006_get_battery_healthy(struct sh36606_chip *sh_chip)
{
    int ret;
    unsigned char reg_val[2] = {0, 0};
    unsigned int healthy;

    ret = SH366100_Read_SBS_Word(sh_chip->client, HEALTHY_SOC, reg_val);

    if(ret <0 ) {
        sh_chip->battery_healthy = 2;
        return ret;
    }
    healthy = reg_val[0] ;
    sh_chip->battery_healthy = healthy;
    return 0;
}

static int sh_init_data(struct sh36606_chip *sh_chip)
{
	int ret = 0;

    u16 device_type;
	
    /* 验证芯片ID */
    ret = SH366100_Read_SBS_Word(sh_chip->client, DEVICE_TYPE, &device_type);
    if (ret != 0 || device_type != 410) {
        dev_err(&sh_chip->client->dev, "Invalid chip ID: 0x%02X\n", device_type);
        sh_chip->battery_temp = 26;
        sh_chip->voltage = 3000;
        sh_chip->soc = 50;
        sh_chip->battery_current = 65284;
        sh_chip->cycle_count = 1;
        sh_chip->battery_healthy = 2;
        sh_chip->status = POWER_SUPPLY_STATUS_CHARGING;
        return -1;
    } else {
        sh_printk("check ok\r\n");
    }

    ret += sh366006_get_voltage(sh_chip);
    ret += sh366006_get_current(sh_chip);
    ret += sh366006_get_soc(sh_chip);
    ret += sh366006_get_temperature(sh_chip);
    ret += sh366006_get_cycle_count(sh_chip);
	ret += sh366006_get_battery_healthy(sh_chip);
    sh_chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
    sh_printk("voltage : %d, current : %d, soc : %d, temperature : %d, cycle_count:%d, battery_healthy:%d ,ret : %d \n",\
        sh_chip->voltage, sh_chip->battery_current, sh_chip->soc, sh_chip->battery_temp, sh_chip->cycle_count, sh_chip->battery_healthy, ret);

	return ret;
}

/* 
定期循环的工作队列
*/
static void sh366006_monitor_work(struct work_struct *work)
{
    struct delayed_work *delay_work;
    struct sh36606_chip *sh_chip;
    int ret;

    delay_work = container_of(work, struct delayed_work, work);
    sh_chip = container_of(delay_work, struct sh36606_chip, monitor_work);

    ret += sh366006_get_voltage(sh_chip);
    ret += sh366006_get_current(sh_chip);
    ret += sh366006_get_soc(sh_chip);
    ret += sh366006_get_temperature(sh_chip);
    ret += sh366006_get_cycle_count(sh_chip);
    ret += sh366006_get_battery_healthy(sh_chip);


    sh_printk("voltage : %d, current : %d, soc : %d, temperature : %d, cycle_count:%d, battery_healthy:%d ,ret : %d \n",\
        sh_chip->voltage, sh_chip->battery_current, sh_chip->soc, sh_chip->battery_temp, sh_chip->cycle_count, sh_chip->battery_healthy, ret);
    //向Android系统上报电池参数
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
	power_supply_changed(&sh_chip->sh_bat); 
#else
	power_supply_changed(sh_chip->sh_bat);
#endif

    queue_delayed_work(sh_chip->shfg_workqueue, &sh_chip->monitor_work, msecs_to_jiffies(queue_delayed_work_time));
}

static int sh_battery_set_property(struct power_supply *psy,
    enum power_supply_property psp,
    const union power_supply_propval *val)
{
    int ret = 0;
    #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
    struct sh36606_chip *sh_bat;
    sh_bat = container_of(psy, struct sh36606_chip, sh_bat); 
    #else
    struct sh36606_chip *sh_bat = power_supply_get_drvdata(psy); 
    #endif

    switch(psp) {
    default:
    ret = -EINVAL; 
    break; 
    }

    return ret;
}


static int sh_get_capacity_level(struct sh36606_chip *sh_bat)
{
	if (sh_bat->soc < 1)
		return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
	else if (sh_bat->soc <= 20)
		return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
	else if (sh_bat->soc <= 70)
		return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
	else if (sh_bat->soc <= 90)
		return POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
	else
		return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
}

static int sh_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
{
    int ret = 0;

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
	struct sh36606_chip *sh_bat;
	sh_bat = container_of(psy, struct sh36606_chip, sh_bat); 
#else
	struct sh36606_chip *sh_bat = power_supply_get_drvdata(psy); 
#endif   

    switch(psp) {
        case POWER_SUPPLY_PROP_CYCLE_COUNT:
            val->intval = sh_bat->cycle_count;
            break;
        case POWER_SUPPLY_PROP_CAPACITY:
		    val->intval = sh_bat->soc;
		    break;
        case POWER_SUPPLY_PROP_PRESENT:
            val->intval = sh_bat->voltage <= 0 ? 0 : 1;
            break;  
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
            val->intval = sh_bat->voltage;
            break;
        case POWER_SUPPLY_PROP_CURRENT_NOW:
            val->intval = sh_bat->battery_current;
            break;
        case POWER_SUPPLY_PROP_TEMP: 
            val->intval = 250;
            break;
        case POWER_SUPPLY_PROP_HEALTH: 
            val->intval = POWER_SUPPLY_HEALTH_GOOD;
             break;
        case POWER_SUPPLY_PROP_TECHNOLOGY:
            val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
            break;
        case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
            val->intval = sh_get_capacity_level(sh_bat);
        break;

        case POWER_SUPPLY_PROP_STATUS:
            val->intval = sh_bat->status;
        break;

        default:
            ret = -EINVAL; 
            break;
    }    

    return ret;
}

static enum power_supply_property sh_battery_properties[] = {
    POWER_SUPPLY_PROP_CYCLE_COUNT,
    POWER_SUPPLY_PROP_TEMP,
	POWER_SUPPLY_PROP_CAPACITY,
	POWER_SUPPLY_PROP_PRESENT,
	POWER_SUPPLY_PROP_VOLTAGE_NOW,
	POWER_SUPPLY_PROP_CURRENT_NOW,
    POWER_SUPPLY_PROP_HEALTH,
	POWER_SUPPLY_PROP_TECHNOLOGY,
    POWER_SUPPLY_PROP_CAPACITY_LEVEL,
    POWER_SUPPLY_PROP_STATUS,
};

static int sh366006_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret;
    static struct sh36606_chip *sh_bat;
	struct power_supply_desc *psy_desc;
	struct power_supply_config psy_cfg = {0};


    sh_printk("\n");

    sh_bat = devm_kzalloc(&client->dev, sizeof(*sh_bat), GFP_KERNEL);
    if (!sh_bat) {
		sh_printk("%s : sh_bat create fail!\n", __func__);
		return -ENOMEM;
	}
    // sh_printk("fuck 1\n");
    i2c_set_clientdata(client, sh_bat);
	sh_bat->client = client;


    // sh_printk("fuck 2.5\n");

    ret = sh_init_data(sh_bat);

	if (ret < 0) {
		sh_printk(" sh_init_data fail!\n");
		// return ret;
	}


#ifdef SH_PROPERTIES
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
    sh_bat->sh_bat.name = SH_PROPERTIES;
	sh_bat->sh_bat.type = POWER_SUPPLY_TYPE_BATTERY;
	sh_bat->sh_bat.properties = sh_battery_properties;
	sh_bat->sh_bat.num_properties = ARRAY_SIZE(sh_battery_properties);
	sh_bat->sh_bat.get_property = sh_battery_get_property;
	sh_bat->sh_bat.set_property = sh_battery_set_property;
	ret = power_supply_register(&client->dev, &sh_bat->sh_bat);
	if (ret < 0) {
		power_supply_unregister(&sh_bat->sh_bat);
        sh_printk("failed to register battery: %d\n", ret);
		return ret;
	}
    // sh_printk("fuck 2.6\n");
#else
	psy_desc = devm_kzalloc(&client->dev, sizeof(*psy_desc), GFP_KERNEL);
	if (!psy_desc)
		return -ENOMEM;
	psy_cfg.drv_data = sh_bat;
	psy_desc->name = SH_PROPERTIES;
	psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
	psy_desc->properties = sh_battery_properties;
	psy_desc->num_properties = ARRAY_SIZE(sh_battery_properties);
	psy_desc->get_property = sh_battery_get_property;
	psy_desc->set_property = sh_battery_set_property;
	sh_bat->sh_bat = power_supply_register(&client->dev, psy_desc, &psy_cfg);
	if (IS_ERR(sh_bat->sh_bat)) {
		ret = PTR_ERR(sh_bat->sh_bat);
		sh_printk("failed to register battery: %d\n", ret);
		return ret;
	}
    // sh_printk("fuck 2.7\n");
#endif
#endif
// sh_printk("fuck 3\n");

    sh_bat->shfg_workqueue = create_singlethread_workqueue("shfg_gauge");
	INIT_DELAYED_WORK(&sh_bat->monitor_work, sh366006_monitor_work);
	queue_delayed_work(sh_bat->shfg_workqueue, &sh_bat->monitor_work , msecs_to_jiffies(queue_start_work_time));

    // sh_printk("fuck 4\n");

    sh_printk("sh366006 driver probe success!\n");



    return 0;    
}

static int sh366006_remove(struct i2c_client *client)	 
{
	sh_printk("\n");
	return 0;
}

static const struct i2c_device_id sh366006_id_table[] = {
	{ SHFG_NAME, 0 },
	{ }
};

static struct of_device_id sh366006_match_table[] = {
	{ .compatible = "shunwei,sh366006", },
	{ },
};

static struct i2c_driver sh366006_driver = {
	.driver   = {
		.name = SHFG_NAME,

		.owner = THIS_MODULE,
		.of_match_table = sh366006_match_table,
	},
	.probe = sh366006_probe,
	.remove = sh366006_remove,
	.id_table = sh366006_id_table,
};

static int __init sh366006_init(void)
{
	sh_printk("\n");
	i2c_add_driver(&sh366006_driver);
	return 0; 
}

static void __exit sh366006_exit(void)
{
	i2c_del_driver(&sh366006_driver);
}

module_init(sh366006_init);
module_exit(sh366006_exit);

MODULE_AUTHOR("SRED Cole");
MODULE_DESCRIPTION("SH366006 Device Driver V0.1");
MODULE_LICENSE("GPL");

设备树

	sh366006@0b {
		status = "okay";
        compatible = "shunwei,sh366006";
        reg = <0x0b>;
    };

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

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

相关文章

蓝桥杯学习——二叉树+奇点杯题目解析

基础认知 一、二叉树种类&#xff1a; 1.满二叉树。记深度k&#xff0c;节点数量2^k-1。 2.完全二叉树&#xff1a;除了底层&#xff0c;其余全满&#xff0c;底部从左到右连续。 3&#xff0c;平衡二叉搜索树&#xff1a;左子树和右子树高度差不大于1。 二、存储方式&…

基于django+vue的购物商城系统

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.8数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 系统首页 热卖商品 优惠资讯 个人中心 后台登录 管理员功能界面 用户管理 商品分类管理…

AI安全、大模型安全研究(DeepSeek)

DeepSeek 点燃AI应用革命之火,但安全 “灰犀牛” 正在逼近 DeepSeek-R1国产大模型的发布,以技术创新惊艳了全球,更是极致的性价比推动国内千行百业接入 AI,政府、企业竞速开发智能业务处理、智能客服、代码生成、营销文案等应用,“落地效率” 成为第一关键词。然而与此相…

卷积神经网络 - 汇聚层

卷积神经网络一般由卷积层、汇聚层和全连接层构成&#xff0c;本文我们来学习汇聚层。 汇聚层(Pooling Layer)也叫子采样层(Subsampling Layer)&#xff0c;其作用是进 行特征选择&#xff0c;降低特征数量&#xff0c;从而减少参数数量。 卷积层虽然可以显著减少网络中连接的…

论文分享:PL-ALF框架实现无人机低纹理环境自主飞行

在室内仓库、地下隧道等低纹理复杂场景中&#xff0c;无人机依赖视觉传感器进行自主飞行时&#xff0c;往往会遇到定位精度低、路径规划不稳定等难题。针对这一问题&#xff0c;重庆邮电大学计算机学院雷大江教授团队在IEEE Trans期刊上提出了一种新型自主飞行框架&#xff1a;…

Nodejs使用redis

框架&#xff1a;koa&#xff0c;通过koa-generator创建 redis: 本地搭建&#xff0c;使用默认帐号&#xff0c;安装说明地址以及默认启动设置&#xff1a;https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/ 中间件&#x…

GitHub 超火的开源终端工具——Warp

Warp 作为近年来 GitHub 上备受瞩目的开源终端工具&#xff0c;以其智能化、高性能和协作能力重新定义了命令行操作体验。以下从多个维度深入解析其核心特性、技术架构、用户评价及生态影响力&#xff1a; 一、背景与核心团队 Warp 由前 GitHub CTO Jason Warner 和 Google 前…

计算机视觉技术探索:美颜SDK如何利用深度学习优化美颜、滤镜功能?

时下&#xff0c;计算机视觉深度学习正在重塑美颜技术&#xff0c;通过智能人脸检测、AI滤镜、深度美肤、实时优化等方式&#xff0c;让美颜效果更加自然、精准、个性化。 那么&#xff0c;美颜SDK如何结合深度学习来优化美颜和滤镜功能&#xff1f;本文将深入解析AI在美颜技术…

应用商店上新:Couchbase Enterprise Server集群

可移植的冗余数据平台&#xff0c;这往往是创建可扩展的云原生应用程序的先决条件。而不依赖特定平台的工具可用于为多云、多区域工作负载提供企业级应用所需的灵活性。 ​Couchbase是一种高性能NoSQL数据库&#xff0c;专为当今复杂的云生态系统所需的动态扩展能力而设计。最近…

Redis解决缓存击穿问题——两种方法

目录 引言 解决办法 互斥锁&#xff08;强一致&#xff0c;性能差&#xff09; 逻辑过期&#xff08;高可用&#xff0c;性能优&#xff09; 设计逻辑过期时间 引言 缓存击穿&#xff1a;给某一个key设置了过期时间&#xff0c;当key过期的时候&#xff0c;恰好这个时间点对…

集成学习之随机森林

目录 一、集成学习的含义 二、集成学习的代表 三、集成学习的应用 1、分类问题集成。&#xff08;基学习器是分类模型&#xff09; 2、回归问题集成。&#xff08;基学习器是回归模型&#xff09; 3、特征选取集成。 四、Bagging之随机森林 1、随机森林是有多个决策树&a…

在线JSON格式校验工具站

在线JSON校验格式化工具&#xff08;Be JSON&#xff09;在线,JSON,JSON 校验,格式化,xml转json 工具,在线工具,json视图,可视化,程序,服务器,域名注册,正则表达式,测试,在线json格式化工具,json 格式化,json格式化工具,json字符串格式化,json 在线查看器,json在线,json 在线验…

SAP的WPS导出找不到路径怎么办;上载报错怎么办

一.打开注册编辑器 二.输入以下地址 计算机\HKEY_CLASSES_ROOT\ExcelWorksheet\Protocol\StdFileEditing\Server 去除掉EXE后面的命令即可 二&#xff1a;WPS上载文件没反应怎么办 如何切换整合模式或多组件模式-WPS学堂 根据官方操作把整合模式改成多组件模式

Moonlight-16B-A3B: 变革性的高效大语言模型,凭借Muon优化器打破训练效率极限

近日&#xff0c;由Moonshot AI团队推出的Moonlight-16B-A3B模型&#xff0c;再次在AI领域引发了广泛关注。这款全新的Mixture-of-Experts (MoE)架构的大型语言模型&#xff0c;凭借其创新的训练优化技术&#xff0c;特别是Muon优化器的使用&#xff0c;成功突破了训练效率的极…

rust学习笔记17-异常处理

今天聊聊rust中异常错误处理 1. 基础类型&#xff1a;Result 和 Option&#xff0c;之前判断空指针就用到过 Option<T> 用途&#xff1a;表示值可能存在&#xff08;Some(T)&#xff09;或不存在&#xff08;None&#xff09;&#xff0c;适用于无需错误信息的场景。 f…

PyTorch系列教程:使用预训练语言模型增强文本分类

文本分类仍是自然语言处理&#xff08;NLP&#xff09;领域的一项基础任务&#xff0c;其目标是将文本数据归入预先设定的类别之中。预训练语言模型的出现极大地提升了这一领域的性能。本文将探讨如何利用 PyTorch 来利用这些模型&#xff0c;展示它们如何能增强文本分类任务。…

LabVIEW 线性拟合

该 LabVIEW 程序实现了 线性拟合&#xff08;Linear Fit&#xff09;&#xff0c;用于计算给定一组数据点的斜率&#xff08;Slope&#xff09;和截距&#xff08;Intercept&#xff09;&#xff0c;并将结果可视化于 XY Graph 中。本案例适用于数据拟合、实验数据分析、传感器…

nacos安装,服务注册,服务发现,远程调用3个方法

安装 点版本下载页面 服务注册 每个微服务都配置nacos的地址&#xff0c;都要知道 服务发现 2个是知道了解 远程调用基本实现 远程调用方法2&#xff0c;负载均衡API测试 远程调用方法3&#xff0c;注解 负载均衡的远程调用&#xff0c; 总结 面试题

Mac:JMeter 下载+安装+环境配置(图文详细讲解)

&#x1f4cc; 下载JMeter 下载地址&#xff1a;https://jmeter.apache.org/download_jmeter.cgi &#x1f4cc; 无需安装 Apache官网下载 JMeter 压缩包&#xff0c;无需安装&#xff0c;下载解压后放到自己指定目录下即可。 按我自己的习惯&#xff0c;我会在用户 jane 目…

Python IP解析器 ip2region使用

说明&#xff1a;最近需要在python项目内使用IP定位所在城市的需求&#xff0c;没有采用向外部ISP服务商API请求获取信息的方案&#xff0c;则翻了翻&#xff0c;在搞Java时很多的方案&#xff0c;在Python端反而可选择范围很小。 # 示例查询 ips ["106.38.188.214"…