【rk3588-android12】实现【bq40z50R1】系统HAL服务,从硬件驱动层到上层APP

硬件驱动层

qzbattery.h

hardware/libhardware/include/hardware/qzbattery.h

#define ANDROID_QZBATTERY_INTERFACE_H

#include <hardware/hardware.h>

__BEGIN_DECLS

#define QZBATTERY_HARDWARE_MODULE_ID "qzbattery"

// 此方法是固定写法
struct qzbattery_module_t
{
    struct hw_module_t common;
    char *description;
    int methodsNum;
};

struct QZBatteryReadBlockData
{
    int fd;
    int cmd;
    int len;
    char val[6];
};

struct QZBatteryWriteBlockData
{
    int fd;
    int cmd;
    int len;
    int val;
};

struct QZBatteryReadWordData
{
    int fd;
    int cmd;
};
struct QZBatteryWriteWordData
{
    int fd;
    int cmd;
    int value;
};
struct QZBatteryOpenData
{
    int reg;
};

struct QZBatteryCloseData
{
    int file;
};

struct qzbattery_device_t
{
    struct hw_device_t common;
    int (*qz_battery_read_block_data)(struct qzbattery_device_t *dev, struct QZBatteryReadBlockData *data);
    int (*qz_battery_write_block_data)(struct qzbattery_device_t *dev, struct QZBatteryWriteBlockData *data);
    int (*qz_battery_read_word_data)(struct qzbattery_device_t *dev, struct QZBatteryReadWordData *data);
    int (*qz_battery_write_word_data)(struct qzbattery_device_t *dev, struct QZBatteryWriteWordData *data);
    int (*qz_battery_open)(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data);
    int (*qz_battery_test)(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data);
    int (*qz_battery_close)(struct qzbattery_device_t *dev, struct QZBatteryCloseData *data);
        /* data */
};

__END_DECLS

qzbattery.c

hardware/libhardware/modules/qzbattery/qzbattery_hw.c

#define LOG_TAG "qz battery"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
// #include <linux/i2c-smbus.h>
// #include <i2c/smbus.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <hardware/hardware.h>
#include <malloc.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <cutils/log.h>
#include <hardware/qzbattery.h>

#define MODULE_NAME "Hello Battery"
#define MODULE_DES "Battery : Implement read battery function"
#define MODULE_AUTHOR "zuocong@qiictech.com"

#define ADDR 0x0b

#define BQ40Z50_MANUFACTURER_ACCESS 0x00
#define BQ40Z50_MANUFACTURER_BLOCK_ACCESS 0x44
#define BQ40Z50_MANUFACTURER_DATE 0x1B
#define BQ40Z50_SERIAL_NUMBER 0x1C
#define BQ40Z50_MANUFACTURER_DATA 0x23

#define I2C_FILE_PATH "/dev/i2c-1"

// enum bq40z50_mac_cmd
// {
//     BQ40Z50_MAC_CMD_
// }

// 读取 块(,传输连续的字节序列,数据量较大,长度在1-32字节之间) 数据
static int qz_battery_read_block_data(struct qzbattery_device_t *dev, struct QZBatteryReadBlockData *data);
// 写入 块 数据
static int qz_battery_write_block_data(struct qzbattery_device_t *dev, struct QZBatteryWriteBlockData *data);
// 读取 一个字》两个字节 数据
static int qz_battery_read_word_data(struct qzbattery_device_t *dev, struct QZBatteryReadWordData *data);
// 写入 字 数据
static int qz_battery_write_word_data(struct qzbattery_device_t *dev, struct QZBatteryWriteWordData *data);
// 打开电池
static int qz_battery_open(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data);
static int qz_battery_test(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data);
// 关闭电池
static int qz_battery_close(struct qzbattery_device_t *dev, struct QZBatteryCloseData *data);

// 固定写法,打开关闭模块
static int battery_module_close(struct hw_device_t *device);
static int battery_module_open(const struct hw_module_t *module, const char *id, struct hw_device_t **device);


int smbus_write_word(int fd, uint8_t cmd, uint16_t value)
{
    struct i2c_smbus_ioctl_data msgs;
    union i2c_smbus_data data;

    data.word = value;

    msgs.read_write = I2C_SMBUS_WRITE;
    msgs.command = cmd;
    msgs.size = I2C_SMBUS_WORD_DATA;
    msgs.data = &data;

    if (ioctl(fd, I2C_SMBUS, &msgs) < 0)
    {
        perror("error, failed to access smbus");
        ALOGE("error, failed to access smbus");
        return -errno;
    }

    return 0;
}

int smbus_read_word(int fd, uint8_t cmd)
{
    union i2c_smbus_data data;
    struct i2c_smbus_ioctl_data msg;

    msg.read_write = I2C_SMBUS_READ;
    msg.command = cmd;
    msg.size = I2C_SMBUS_WORD_DATA;
    msg.data = &data;

    if (ioctl(fd, I2C_SMBUS, &msg) < 0)
    {
        perror("error, failed to access smbus");
        ALOGE("error, failed to access smbus");
        return -errno;
    }
    printf("raw data: %d\n", data.word);
    ALOGE("raw data: %d\n", data.word);

    return data.word;
}

int smbus_write_block(int fd, uint8_t cmd, uint8_t len, uint8_t *val)
{
    union i2c_smbus_data data;
    struct i2c_smbus_ioctl_data msg;

    if (len > I2C_SMBUS_BLOCK_MAX)
    {
        len = I2C_SMBUS_BLOCK_MAX;
    }

    data.block[0] = len;
    memcpy(data.block + 1, val, len);

    msg.read_write = I2C_SMBUS_WRITE;
    msg.command = cmd;
    msg.size = I2C_SMBUS_BLOCK_DATA;
    msg.data = &data;

    if (ioctl(fd, I2C_SMBUS, &msg) < 0)
    {
        perror("smbus_write_block failed");
        ALOGE("smbus_write_block failed");
        return -errno;
    }

    return 0;
}

int smbus_read_block(int fd, uint8_t cmd, uint8_t len, char *val)
{
    union i2c_smbus_data data;
    struct i2c_smbus_ioctl_data msg;

    if (len > I2C_SMBUS_BLOCK_MAX)
    {
        len = I2C_SMBUS_BLOCK_MAX;
    }

    data.block[0] = len;
    data.block[1] = 0xff;
    data.block[2] = 0xff;
    data.block[3] = 0xff;
    data.block[4] = 0xff;
    data.block[5] = 0xff;

    msg.read_write = I2C_SMBUS_READ;
    msg.command = cmd;
    msg.size = I2C_SMBUS_I2C_BLOCK_DATA;
    msg.data = &data;

    if (ioctl(fd, I2C_SMBUS, &msg) < 0)
    {
        perror("smbus_read_block failed");
        ALOGE("smbus_read_block failed");
        return -errno;  
    }

    printf("smbus_read_block len=%d\n", msg.data->block[0]);
    ALOGE("smbus_read_block len=%d\n", msg.data->block[0]);
    for (int i = 0; i < msg.data->block[0]; i++)
    {
        printf("%02X ", msg.data->block[i + 1]);
        ALOGE("%02X ", msg.data->block[i + 1]);
    }
    printf("\n");
    ALOGE("\n");

    memcpy(val, &msg.data->block[1], msg.data->block[0]-1);

    return msg.data->block[0];
}

// int bq40z50_i2c_write_block(int fd, uint8_t cmd, uint8_t len, uint8_t *val)
// {
//     int ret;
//     struct i2c_rdwr_ioctl_data ioctl_data;
//     struct i2c_msg msg;

//     msg.addr = cmd;
//     msg.flags = 0;
//     msg.buf = val;
//     msg.len = len;

//     ioctl_data.msgs = &msg;
//     ioctl_data.nmsgs = 1;

//     if(ioctl(fd, I2C_RDWR, &ioctl_data) < 0)
//     {
//         perror("bq40z50_i2c_write_block failed");
//         return -errno;
//     }

//     return 0;
// }

// int bq40z50_i2c_read_block(int fd, uint8_t cmd, uint8_t len, uint8_t *val)
// {
//     int ret;
//     struct i2c_rdwr_ioctl_data ioctl_data;
//     struct i2c_msg msg[2];

//     msg[0].addr = cmd;
//     msg[0].flags = 0;
//     msg[0].buf = val;
//     msg[0].len = len;

//     ioctl_data.msgs = &msg;
//     ioctl_data.nmsgs = 1;

//     if(ioctl(fd, I2C_RDWR, &ioctl_data) < 0)
//     {
//         perror("bq40z50_i2c_write_block failed");
//         return -errno;
//     }

//     return 0;
// }

// int bq40z50_manufacturer_access_read(int fd, uint16_t cmd, uint8_t len, uint8_t *val)
// {
//     int ret;
//     uint8_t buf[2] = {0};
//     struct i2c_rdwr_ioctl_data ioctl_data;
//     struct i2c_msg msg[2];

//     buf[0] = (uint8_t)(cmd >> 8);
//     buf[1] = (uint8_t)cmd;

//     msg[0].addr = BQ40Z50_MANUFACTURER_ACCESS;
//     msg[0].flags = 0;
//     msg[0].buf = buf;
//     msg[0].len = 2;

//     msg[0].addr = BQ40Z50_MANUFACTURER_DATA;
//     msg[0].flags = I2C_M_RD;
//     msg[0].buf = val;
//     msg[0].len = len;

//     ioctl_data.msgs = &msg;
//     ioctl_data.nmsgs = 2;

//     if(ioctl(fd, I2C_RDWR, &ioctl_data) < 0)
//     {
//         perror("bq40z50_i2c_write_block failed");
//         return -errno;
//     }

//     printf("bq40z50_manufacturer_access_read len=%d\n", len);
//     for (int i = 0; i < msg.data->block[0]; i++)
//     {
//         printf("%02X ", msg.data->block[i + 1]);
//     }
//     printf("\n");

//     return 0;
// }

int bq40z50_get_sn(int fd, char *sn, int size)
{
    int ret;
    uint16_t date;
    uint16_t seial_number;

    ret = smbus_read_word(fd, BQ40Z50_MANUFACTURER_DATE);
    if (ret < 0)
    {
        perror("error, failed to access smbus");
        return ret;
    }
    date = ret;

    ret = smbus_read_word(fd, BQ40Z50_SERIAL_NUMBER);
    if (ret < 0)
    {
        perror("error, failed to access smbus");
        return ret;
    }
    seial_number = ret;

    sn[0] = 0;
    snprintf(sn, size, "%04d%02d%02d%04X", date / 512 + 1980, (date % 512) / 32, (date % 512) % 32, seial_number);

    return 0;
}

int bq40z50_set_serial_number(int fd, uint16_t serial_number)
{
    int ret;

    ret = smbus_write_word(fd, BQ40Z50_SERIAL_NUMBER, serial_number);
    if (ret < 0)
    {
        return ret;
    }

    return 0;
}

int bq40z50_seal(int fd)
{
    int ret;

    ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, 0x3000);
    if (ret < 0)
    {
        return ret;
    }

    return 0;
}

int bq40z50_unseal(int fd, uint32_t key)
{
    int ret;

    ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, (uint16_t)(key >> 16));
    if (ret < 0)
    {
        return ret;
    }

    ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, (uint16_t)key);
    if (ret < 0)
    {
        return ret;
    }

    return 0;
}

int bq40z50_full_access(int fd, uint32_t key)
{
    int ret;

    ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, (uint16_t)(key >> 16));
    if (ret < 0)
    {
        return ret;
    }

    ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, (uint16_t)key);
    if (ret < 0)
    {
        return ret;
    }

    return 0;
}

int bq40z50_get_operation_status(int fd, uint16_t reg)
{
    int ret;
    printf("reg = %04x \n", reg);
    uint8_t buf[32] = {0};

    // ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, reg);
    // if (ret < 0)
    // {
    //     return ret;
    // }
    buf[0] = 0x54;
    buf[1] = 0x00;
    ret = smbus_write_block(fd, BQ40Z50_MANUFACTURER_BLOCK_ACCESS, 2, buf);
    if (ret < 0)
    {
        return ret;
    }

    // usleep(2000 * 1000); // usleep 接受的单位是微秒

    ret = smbus_read_block(fd, BQ40Z50_MANUFACTURER_BLOCK_ACCESS, 6, (char*)buf);
    if (ret < 0)
    {
        return ret;
    }

    printf("operation_status: ");
    for (int i = 0; i < ret; i++)
    {
        printf("%02X ", buf[i]);
    }
    printf("\n");

    return 0;
}

static int qz_battery_read_block_data(struct qzbattery_device_t *dev, struct QZBatteryReadBlockData *data)
{
    (void)dev;
    return smbus_read_block(data->fd, data->cmd, data->len, (char*)&data->val);
}

static int qz_battery_write_block_data(struct qzbattery_device_t *dev, struct QZBatteryWriteBlockData *data)
{
    (void)dev;
    return smbus_write_block(data->fd, data->cmd, data->len, (uint8_t*)&data->val);
}
static int qz_battery_read_word_data(struct qzbattery_device_t *dev, struct QZBatteryReadWordData *data)
{
    (void)dev;
    return smbus_read_word(data->fd, data->cmd);
}

static int qz_battery_write_word_data(struct qzbattery_device_t *dev, struct QZBatteryWriteWordData *data)
{
    (void)dev;
    return smbus_write_word(data->fd, data->cmd, (uint16_t)data->value);
}

static int qz_battery_open(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data)
{
    (void)dev;
    uint16_t addr1 = data->reg;

    printf("QZBatteryOpenData = %04x \n", addr1);

    int res = 0;
    // I2C 设备路径
    int i2cFile = open(I2C_FILE_PATH, O_RDWR);

    if (i2cFile < 0)
    {
        ALOGI("...Failed to open I2C device");
        return 1;
    }
    ALOGI("...Success to open I2C device");

    int i2cAddress = 0x0B; // I2C 设备地址
    // int registerAddress = 0x1C; // 要读取的寄存器地址
    res = ioctl(i2cFile, I2C_SLAVE_FORCE, i2cAddress);
    if (res < 0)
    {
        ALOGI("...Error message: %s\n", strerror(errno));
        ALOGI("...Failed to set I2C address res : %d", res);
        close(i2cFile);
        return 1;
    }
    ALOGI("...Success to ioctl I2C device");

    int val = 3;
    res = ioctl(i2cFile, I2C_RETRIES, val);
    if(res < 0)
    {
        printf("i2c: set i2c retry times err\n");
    }

    printf("i2c: set i2c retry times %d\n",val);

    return i2cFile;
}
static int qz_battery_close(struct qzbattery_device_t *dev, struct QZBatteryCloseData *data)
{
    (void)dev;
    int fd = data->file;
    if (fd < 0)
    {
        perror("qz battery close failed , fd < 0");
    }
    close(fd);
    return 0;
}



// ============================================================测试================================================================
static int qz_battery_test(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data)
{
    (void)dev;
    uint16_t addr1 = data->reg;

    printf("QZBatteryOpenData = %04x \n", addr1);

    int res = 0;
    // I2C 设备路径
    int i2cFile = open(I2C_FILE_PATH, O_RDWR);

    if (i2cFile < 0)
    {
        ALOGI("...Failed to open I2C device");
        return 1;
    }
    ALOGI("...Success to open I2C device");

    int i2cAddress = 0x0B; // I2C 设备地址
    // int registerAddress = 0x1C; // 要读取的寄存器地址
    res = ioctl(i2cFile, I2C_SLAVE_FORCE, i2cAddress);
    if (res < 0)
    {
        ALOGI("...Error message: %s\n", strerror(errno));
        ALOGI("...Failed to set I2C address res : %d", res);
        close(i2cFile);
        return 1;
    }
    ALOGI("...Success to ioctl I2C device");

    int val = 3;
    res = ioctl(i2cFile, I2C_RETRIES, val);
    if(res < 0)
    {
        printf("i2c: set i2c retry times err\n");
    }

    printf("i2c: set i2c retry times %d\n",val);

    // 读取SN
    // char sn[20] = {0};
    // if (bq40z50_get_sn(i2cFile, sn, sizeof(sn)) != 0)
    // {
    //     printf("...bq40z50_get_sn1 failed\n");
    // }

    // printf("...bq40z50_get_sn1 %s", sn);

    // // 更改SN
    // if (bq40z50_set_serial_number(i2cFile, 0x0011) != 0)
    // {
    //     printf("...bq40z50_set_serial_number failed\n");
    // }

    // // 读取SN
    // if (bq40z50_get_sn(i2cFile, sn, sizeof(sn)) != 0)
    // {
    //     printf("...bq40z50_get_sn2 failed\n");
    // }

    // printf("...bq40z50_get_sn2 %s", sn);

    // 读取电池操作状态
    if (bq40z50_get_operation_status(i2cFile, addr1) != 0)
    {
        printf("...bq40z50_get_operation_status failed\n");
    }

    // unsigned char value;
    // if (read(i2cFile, &value, 1) != 1)
    // {
    //     ALOGI("...Failed to read from I2C device");
    //     close(i2cFile);
    //     return 1;
    // }

    // printf("Read value from register 0x%X: %02X\n", registerAddress, value);

    // close(i2cFile);
    return i2cFile;
}



/**  =====================================================以下是固定结构========================================================== */
static struct hw_module_methods_t qzbattery_module_methods_t = {
    .open = battery_module_open};

struct qzbattery_module_t HAL_MODULE_INFO_SYM = {

    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .module_api_version = 1,
        .hal_api_version = 0,
        .id = QZBATTERY_HARDWARE_MODULE_ID,
        .name = MODULE_NAME,
        .author = MODULE_AUTHOR,
        .methods = &qzbattery_module_methods_t},

    .description = MODULE_DES,
    .methodsNum = 3

};

// 打开电池硬件HAL模块
static int battery_module_open(const struct hw_module_t *module, const char *id, struct hw_device_t **device)
{

    struct qzbattery_device_t *dev;
    printf("ID: %s\n", id);
    dev = (struct qzbattery_device_t *)malloc(sizeof(*dev));
    if (!dev)
    {
        ALOGE("HelloBattery open: faild to alloc device space");
        return -EFAULT;
    }
    // 固定的参数方法
    memset(dev, 0, sizeof(*dev));
    dev->common.tag = HARDWARE_MODULE_TAG;
    dev->common.version = 0;
    dev->common.module = (struct hw_module_t *)module;
    dev->common.close = battery_module_close;
    // 自己定义的方法,给服务层调用
    dev->qz_battery_read_block_data = qz_battery_read_block_data;
    dev->qz_battery_write_block_data = qz_battery_write_block_data;
    dev->qz_battery_read_word_data = qz_battery_read_word_data;
    dev->qz_battery_write_word_data = qz_battery_write_word_data;
    dev->qz_battery_open = qz_battery_open;
    dev->qz_battery_test = qz_battery_test;
    dev->qz_battery_close = qz_battery_close;

    *device = &(dev->common);
    ALOGI("HelloBattery open: driver file successfully");

    return 0;
};

// 关闭模块
static int battery_module_close(struct hw_device_t *device)
{
    struct qzbattery_device_t *battry_device = (struct qzbattery_device_t *)device;
    if (battry_device)
    {
        free(battry_device);
    }

    return 0;
}




JNI

com_android_server_qz_BatteryManagerService.cpp

frameworks/base/services/core/jni/com_android_server_qz_BatteryManagerService.cpp

#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <hardware/hardware.h>
#include <hardware/qzbattery.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <utils/Log.h>
#include <utils/misc.h>

#include <iostream>

namespace android {

struct qzbattery_device_t* qz_device = NULL;

static jboolean qzbattery_init(JNIEnv* env, jobject clazz) {
    qzbattery_module_t* module;
    ALOGI("qzbattery jni init");
    if (hw_get_module(QZBATTERY_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
        ALOGI("hw_get_module success");

        if (module->common.methods->open(&(module->common), QZBATTERY_HARDWARE_MODULE_ID,
                                         (struct hw_device_t**)&qz_device) == 0) {
            ALOGI("open success");
            return JNI_TRUE;
        }

        ALOGI("open error");
        return JNI_FALSE;
    }
    ALOGI("hw_get_module error");
    return JNI_FALSE;
}

static jcharArray battery_read_block_data(JNIEnv* env, jobject clazz, jint _fd, jint _cmd, jint _len, jint _val) {
    if (!qz_device) {
        ALOGI("qz jni device is not open");
        // return  JNI_FALSE;
    }
    ALOGI("QZ jni of qz_battery_read_block_data param _fd = %d, _cmd = %d, _len = %d, _val=%d", _fd, _cmd, _len, _val);

    QZBatteryReadBlockData data;
    data.fd = _fd;
    data.cmd = _cmd;
    data.len = _len;
    // data.val = _val;

    qz_device->qz_battery_read_block_data(qz_device, &data);
    
    jchar* j_version = (jchar*)calloc(sizeof(jchar), data.len);
    for(int i=0; i <= data.len-1; i++){
        j_version[i] =  (jchar) data.val[i];
        ALOGI("QZ jni of qz_battery_read_block_j_version = %02x", j_version[i]);
    }


    jcharArray j_version_array = env->NewCharArray(data.len);
    env->SetCharArrayRegion(j_version_array, 0, data.len , j_version);


    return j_version_array;
}


static int battery_write_block_data(JNIEnv* env, jobject clazz, jint _fd, jint _cmd, jint _len, jint _val) {
    if (!qz_device) {
        ALOGI("qz jni device is not open");
        // return  JNI_FALSE;
    }
    ALOGI("QZ jni of battery_write_block_data param _fd = %d, _cmd = %d, _len = %d, val=%d", _fd, _cmd, _len, _val);

    QZBatteryWriteBlockData data;
    data.fd = _fd;
    data.cmd = _cmd;
    data.len = _len;
    data.val = _val;

    qz_device->qz_battery_write_block_data(qz_device, &data);
    jint blockData = data.val;
    // if (blockData == NULL) {
    //     return 0;
    // }

    // 打印float数组的值
    ALOGI("QZ jni of battery_write_block_data  blockData = %d", blockData);

    return blockData;
}

static int battery_read_word_data(JNIEnv* env, jobject clazz, jint _fd, jint _cmd) {
    if (!qz_device) {
        ALOGI("qz jni device is not open");
        // return  JNI_FALSE;
    }
    ALOGI("QZ jni of battery_read_word_data param _fd = %d, _cmd = %d", _fd, _cmd);

    QZBatteryReadWordData data;
    data.fd = _fd;
    data.cmd = _cmd;

    jint wordData = qz_device->qz_battery_read_word_data(qz_device, &data);
    // if (blockData == NULL) {
    //     return 0;
    // }

    // 打印float数组的值
    ALOGI("QZ jni of battery_read_word_data wordData = %d", wordData);

    return wordData;
}


static int battery_write_word_data(JNIEnv* env, jobject clazz, jint _fd, jint _cmd, jint _val) {
    if (!qz_device) {
        ALOGI("qz jni device is not open");
        // return  JNI_FALSE;
    }
    ALOGI("QZ jni of battery_write_word_data param _fd = %d, _cmd = %d", _fd, _cmd);

    QZBatteryWriteWordData data;
    data.fd = _fd;
    data.cmd = _cmd;
    data.value = _val;

    jint wordData = qz_device->qz_battery_write_word_data(qz_device, &data);
    // if (blockData == NULL) {
    //     return 0;
    // }

    // 打印float数组的值
    ALOGI("QZ jni of battery_write_word_data wordData = %d", wordData);

    return wordData;
}



static int battery_open(JNIEnv* env, jobject clazz, jint _reg) {
    if (!qz_device) {
        ALOGI("qz jni device is not open");
        // return  JNI_FALSE;
    }
    ALOGI("QZ jni of qz_battery_open param _reg = %d", _reg);

    QZBatteryOpenData data;
    data.reg = _reg;

    jint res_code = qz_device->qz_battery_open(qz_device, &data);
    // if (blockData == NULL) {
    //     return 0;
    // }

    // 打印float数组的值
    ALOGI("QZ jni of qz_battery_open res_code = %d", res_code);

    return res_code;
}


static int battery_close(JNIEnv* env, jobject clazz, jint _file) {
    if (!qz_device) {
        ALOGI("qz jni device is not open");
        // return  JNI_FALSE;
    }
    ALOGI("QZ jni of qz_battery_close param _file = %d", _file);

    QZBatteryCloseData data;
    data.file = _file;

    jint res_code = qz_device->qz_battery_close(qz_device, &data);
    // if (blockData == NULL) {
    //     return 0;
    // }

    // 打印float数组的值
    ALOGI("QZ jni of qz_battery_close res_code = %d", res_code);

    return res_code;
}


static JNINativeMethod sMethods[] = {
        {"init", "()Z", (void*)qzbattery_init},
        {"QZbatteryReadBlockData", "(IIII)[C", (void*)battery_read_block_data},
        {"QZbatteryWriteBlockData", "(IIII)I", (void*)battery_write_block_data},
        {"QZbatteryReadWordData", "(II)I", (void*)battery_read_word_data},
        {"QZbatteryWriteWordData", "(III)I", (void*)battery_write_word_data},
        {"QZbatteryOpen", "(I)I", (void*)battery_open},
        {"QZbatteryClose", "(I)I", (void*)battery_close},
};

int request_android_server_qz_BatteryManagerService(JNIEnv* env) {
    return jniRegisterNativeMethods(env, "com/android/server/QzBatteryServerManagerService",
                                    sMethods, NELEM(sMethods));
}
} // namespace android

android.bp

hardware/libhardware/modules/qzbattery/test/Android.bp

cc_library_shared {
    name: "qzbattery.default",
    relative_install_path: "hw",
    proprietary: true,
    srcs: ["qzbattery_hw.c"],
    header_libs: ["libhardware_headers"],
    shared_libs: ["liblog"],
}

JNI测试

qzbatterytest.cpp

hardware/libhardware/modules/qzbattery/test/qzbatterytest.cpp

#include <hardware/hardware.h>
#include <hardware/qzbattery.h>
#include <log/log.h>
#include <stdio.h>
#include <stdlib.h>

#define NULL __null

uint16_t addr = 0x0006;

int main(int argc, char *argv[])
{

    printf("Number of arguments: %d\n", argc);
    for (int i = 0; i < argc; i++)
    {
        printf("Argument %d: %s\n", i, argv[i]);
    }

    qzbattery_device_t *battery_device = NULL;

    const qzbattery_module_t *module = NULL;

    int ret = hw_get_module(QZBATTERY_HARDWARE_MODULE_ID, (const struct hw_module_t **)&module);

    if (!ret)
    {
        ret = module->common.methods->open(&(module->common), QZBATTERY_HARDWARE_MODULE_ID, (struct hw_device_t **)&battery_device);
    }

    QZBatteryOpenData data;
    data.reg = atoi(argv[1]);
    printf("data.reg = %x\n", data.reg);
    battery_device->qz_battery_test(battery_device, &data);

    // if (ret < 0) {
    //     ALOGD("get battery-hal failed.......");
    //     return -1;
    // }

    // BatteryReadBlockData accdata;
    // battery_device->battery_read_block_data(battery_device, &accdata);

    // BatteryWriteBlockData anglveldata;
    // battery_device->battery_write_block_data(battery_device, &anglveldata);

    // // 打印加速度传感器数据
    // ALOGD("Accelerometer sensor data: accdata = %s\n",accdata);

    return 0;
}

android.bp

cc_binary {
    name: "qzbattery_hal",
    srcs: ["qzbatterytest.cpp"],
    cflags: [
        "-Wall",
        "-Wno-unused-parameter",
        "-Werror",
        "-DAPP_PLATFORM=android-29",
    ],
    shared_libs: [
        "libcutils",
        "libhardware",
        "liblog",
    ],
}

HAL服务层

IQzBatteryServiceManager

frameworks/base/core/java/android/app/IQzBatteryServiceManager.aidl

package android.app;

interface IQzBatteryServiceManager{
    char[] iBatteryReadBlockData(in int fd,in int cmd,in int len, in int val);
    int iBatteryWriteBlockData(in int fd,in int cmd,in int len, in int val);
    int iBatteryReadWordData(in int fd,in int cmd);
    int iBatteryWriteWordData(in int fd,in int cmd,in int value);
    int iBatteryOpen(in int reg);
    int iBatteryClose(in int file);
}

QzBatteryServerManager

frameworks/base/core/java/android/app/QzBatteryServerManager.java

package android.app;

import android.content.Context;
import android.annotation.SystemService;
import android.os.RemoteException;
import android.annotation.Nullable;
import android.os.IBinder;
import android.util.Log;
import android.util.Singleton;
import android.util.Slog;
import android.os.ServiceManager;
import android.compat.annotation.UnsupportedAppUsage;

@SystemService(Context.QZ_BATTERY_SERVICE)
public class QzBatteryServerManager {

    private static String TAG = "QzBatteryServerManager";

    /**
     * @hide
     */
    @UnsupportedAppUsage
    public static IQzBatteryServiceManager getService() {
        return IQzBatteryServiceManagerSingleton.get();
    }

    @UnsupportedAppUsage
    private static final Singleton<IQzBatteryServiceManager> IQzBatteryServiceManagerSingleton = new Singleton<IQzBatteryServiceManager>() {
        @Override
        protected IQzBatteryServiceManager create() {
            final IBinder b = ServiceManager.getService(Context.QZ_BATTERY_SERVICE);
            final IQzBatteryServiceManager am = IQzBatteryServiceManager.Stub.asInterface(b);
            return am;
        }
    };

    public char[] batteryReadBlockDataM(@Nullable int fd, @Nullable int cmd, @Nullable int len, @Nullable int val)
            throws RemoteException {
        Slog.d(TAG, "fd = " + fd + " cmd = " + cmd + " len=" + len+ " val="+val);
        return getService().iBatteryReadBlockData(fd, cmd, len, val);
    }

    public int batteryWriteBlockData(@Nullable int fd, @Nullable int cmd, @Nullable int len, @Nullable int val) throws RemoteException {
        Slog.d(TAG, "fd = " + fd + " cmd = " + cmd + " len=" + len+" val="+val);
        return getService().iBatteryWriteBlockData(fd, cmd, len, val);
    }

    public int btteryReadWordDataM(@Nullable int fd, @Nullable int cmd) throws RemoteException {
        Slog.d(TAG, "fd = " + fd + " cmd = " + cmd);
        return getService().iBatteryReadWordData(fd, cmd);
    }

    public int batteryWriteWordDataM(@Nullable int fd, @Nullable int cmd, @Nullable int value) throws RemoteException {
        Slog.d(TAG, "fd = " + fd + " cmd = " + cmd + " value=" + value);
        return getService().iBatteryWriteWordData(fd, cmd, value);
    }

    public int batteryOpenM(@Nullable int reg) throws RemoteException {
        Slog.d(TAG, "reg = " + reg);
        return getService().iBatteryOpen(reg);
    }

    public int batteryCloseM(@Nullable int file) throws RemoteException {
        Slog.d(TAG, "file = " + file);
        return getService().iBatteryClose(file);
    }

   

    /**
     * @hide
     */
    public QzBatteryServerManager() {
        Slog.d(TAG, "......start success!");
    }

}

QzBatteryServerManagerService

frameworks/base/services/core/java/com/android/server/QzBatteryServerManagerService.java

package com.android.server;

import android.annotation.Nullable;
import android.os.RemoteException;
import android.util.Slog;
import android.app.IQzBatteryServiceManager;

public class QzBatteryServerManagerService extends IQzBatteryServiceManager.Stub {
    private static final String TAG = "QzBatteryServerManagerService";

    public QzBatteryServerManagerService() {
        boolean result = init();
        if(result){
            Slog.d(TAG, "init success");
        }else{
            Slog.d(TAG, "init error");
        }
        Slog.d(TAG, "......start success! result =  "+result);
    }


    public void charArrayToHex(char[] charArray) {

        for (char c : charArray) {
            String hexChar = String.format("%02x", (int) c); // 使用 %02x 格式化为十六进制
            Slog.i(TAG, "......hexChar = "+hexChar);
        }

    }

    @Override
    @Nullable
    public char[] iBatteryReadBlockData(int fd, int cmd, int len, int val) throws RemoteException {
        Slog.d(TAG, "......exec qzbattery read block data fd =" + fd + " cmd=" + cmd + " len=" + len+" val="+val);
        charArrayToHex(QZbatteryReadBlockData(fd, cmd, len, val));
        return QZbatteryReadBlockData(fd, cmd, len, val);
    }
    

    @Override
    @Nullable
    public int iBatteryWriteBlockData(int fd, int cmd, int len, int val)  throws RemoteException{
        Slog.d(TAG, "......exec qzbattery write block data fd =" + fd + " cmd=" + cmd + " len=" + len+ " val="+val);
        return QZbatteryWriteBlockData(fd, cmd, len, val);
    }

    @Override
    @Nullable
    public int iBatteryReadWordData(int fd, int cmd)  throws RemoteException{
        Slog.d(TAG, "......exec qzbattery read word data fd =" + fd + " cmd=" + cmd);
        return QZbatteryReadWordData(fd, cmd);
    }

    @Override
    @Nullable
    public int iBatteryWriteWordData(int fd, int cmd, int value)  throws RemoteException{
        Slog.d(TAG, "......exec qzbattery write word data fd =" + fd + " cmd=" + cmd + " value=" + value);
        return QZbatteryWriteWordData(fd, cmd, value);
    }

    @Override
    @Nullable
    public int iBatteryOpen(int reg) throws RemoteException {
        Slog.d(TAG, "......exec qzbattery open reg =" + reg);
        return QZbatteryOpen(reg);
    }

    @Override
    @Nullable
    public int iBatteryClose(int file) throws RemoteException {
        Slog.d(TAG, "......exec qzbattery close file =" + file);
        return QZbatteryClose(file);
    }

    private static native boolean init();
    private static native char[] QZbatteryReadBlockData(int fd, int cmd, int len, int val);

    private static native int QZbatteryWriteBlockData(int fd, int cmd, int len, int val);

    private static native int QZbatteryReadWordData(int fd, int cmd);

    private static native int QZbatteryWriteWordData(int fd, int cmd, int value);

    private static native int QZbatteryOpen(int reg);

    private static native int QZbatteryClose(int fd);

}

系统配置文件更改

frameworks/base/core/java/android/content/Context.java

frameworks/base/services/java/com/android/server/SystemServer.java

frameworks/base/core/java/android/app/SystemServiceRegistry.java

Context.java

public static final String QZ_BATTERY_SERVICE = "qz_battery";

QZ_BATTERY_SERVICE

在这里插入图片描述

SystemServer.java
// 添加位置:startOtherServices方法
// 添加内容如下
// 此处一定要记得捕获异常
t.traceBegin("StartQzBatteryManagerService");
try {
   	 ServiceManager.addService(Context.QZ_BATTERY_SERVICE,
     new QzBatteryServerManagerService());
} catch (Throwable e) {
     Slog.e(TAG, "Failure starting QzBatteryServerManagerService", e);
}
t.traceEnd();
SystemServiceRegistry.java
registerService(Context.QZ_BATTERY_SERVICE, QzBatteryServerManager.class,
new CachedServiceFetcher<QzBatteryServerManager>() {
     @Override
     public QzBatteryServerManager createService(ContextImpl ctx) {
           return new QzBatteryServerManager();
	}});

APP调用

安卓源码下导出Jar包

// 进入源码目录out/target/common/obj/JAVA_LIBRARIES/framework-minus-apex_intermediates下运行以下命令
// 解压查看是否有自定义的QzBatteryServerManager类源文件
jar -tf classes.jar
#解压出QzBatteryServerManager.class
jar -xvf classes.jar android/app/QzBatteryServerManager.class
#打包成QzBatteryServerManager.jar供APP使用
jar -cvf QzBatteryServerManager.jar android

APP调用

  1. 将Jar放置在APP-Demo的libs目录下
	// app文件夹下build.gradle导入jar包
	implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])

  1. 调用服务,读取数据
package com.example.testdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.app.QzBatteryServerManager;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.widget.TextView;

import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private static final String SERVICE_NAME = "qz_battery";

    QzBatteryServerManager qzBatteryServerManager;

    private int fd;
    private String lastSn = null; // 上一次的SN
    private String readSn = null; // 现在读到的SN
    private String resultStr = "测试结果:"; // 测试结果提醒
    private boolean resultFlag = true; // 测试结果标志

    @SuppressLint("WrongConstant")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
        try {
            qzBatteryServerManager = (QzBatteryServerManager) getSystemService(SERVICE_NAME);
            fd = qzBatteryServerManager.batteryOpenM(84);

            // 第一步:连接一个电池然后读出参数显示
            // 第二步:连接到新电池时,先读取SN,判断SN号不一样,则为界面赋值新的电池参数,然后改变上一次SN

            readSN();
            readBatteryParam();
        } catch (RemoteException e) {
            e.printStackTrace();
        }

        new MyThread().run();
    }


    public static String charArrayToHex(char[] charArray) {
        StringBuilder hexBuilder = new StringBuilder();

        for (char c : charArray) {
            String hexChar = String.format("%02x", (int) c); // 使用 %02x 格式化为十六进制
            Log.i(TAG, "......hexChar = " + hexChar);
            hexBuilder.append(hexChar);
        }

        return hexBuilder.toString();
    }


    Handler handler = new Handler();

    public class MyThread implements Runnable {
        @Override
        public void run() {
            // 循环最开始初始化参数
            resultFlag = true;
            // 读取一次参数延迟时间
            handler.postDelayed(this, 3000);
            Log.i(TAG, "......readSN = " + readSn + " lastSn = " + lastSn);
            readSN();
            if (readSn.equals("001980-FFFFFFFA")) {
                setWaiting();
                return;
            }
            readBatteryParam();
        }
    }


    private TextView text_relativeStateOfCharge;
    private TextView text_absoluteStateOfCharge;
    private TextView text_stateOfHealth;
    private TextView text_serialNumber;
    private TextView text_voltage;
    private TextView text_remainingCapacity;
    private TextView text_operationStatus;
    private TextView text_temperature;
    private TextView text_result;

    public void initViews() {
        text_relativeStateOfCharge = findViewById(R.id.text_relativeStateOfCharge);
        text_absoluteStateOfCharge = findViewById(R.id.text_absoluteStateOfCharge);
        text_stateOfHealth = findViewById(R.id.text_stateOfHealth);
        text_serialNumber = findViewById(R.id.text_serialNumber);
        text_voltage = findViewById(R.id.text_voltage);
        text_remainingCapacity = findViewById(R.id.text_remainingCapacity);
        text_operationStatus = findViewById(R.id.text_operationStatus);
        text_temperature = findViewById(R.id.text_temperature);
        text_result = findViewById(R.id.text_result);
    }


    /**
     * 正则表达式验证SN号
     *
     * @param input
     * @return
     */
    public static boolean isFormatValid(String input) {
        String pattern = "^(0[1-9]|1[0-2])(20\\d{2})-(\\d{4})$";
        Pattern regex = Pattern.compile(pattern);
        Matcher matcher = regex.matcher(input);
        return matcher.matches();
    }


    private void readBatteryParam() {

        try {
            setTextView(text_serialNumber, isFormatValid(readSn) == true, readSn, BatteryParamEnum.SERIAL_NUMBER);
            Log.i(TAG, "=================  readSn= " + readSn + " lastSn = " + lastSn);
            Log.i(TAG, "=================  readSn==lastSn : " + (readSn.equals(lastSn)));

            Log.i(TAG, "......QZ Battery 绝对电量");
            int absoluteStateOfCharge = readWordData(fd, BatteryParamEnum.ABSOLUTE_STATE_OF_CHARGE.getCmd());// 绝对电量

            Log.i(TAG, "......QZ Battery 相对电量");
            int relativeStateOfCharge = readWordData(fd, BatteryParamEnum.RELATIVE_STATE_OF_CHARGE.getCmd());// 相对电量

            Log.i(TAG, "......QZ Battery 电池健康");
            int stateOfHealth = readWordData(fd, BatteryParamEnum.STATE_OF_HEALTH.getCmd());// 电池健康

            Log.i(TAG, "......QZ Battery 电压");
            int vo1 = readWordData(fd, BatteryParamEnum.VOLTAGE.getCmd());// Cell 1 电压

            Log.i(TAG, "......QZ Battery 电池mode");
            int batteryMode = readWordData(fd, BatteryParamEnum.BATTERY_MODE.getCmd());// 电池容量
            Log.i(TAG, "......QZ batteryMode = " + Integer.toHexString(batteryMode));
            Log.i(TAG, "......QZ Battery 电池容量");
            int remainingCapacity = readWordData(fd, BatteryParamEnum.REMAINING_CAPACITY.getCmd());// 电池容量

            Log.i(TAG, "......QZ Battery 操作状态");
            int value = -1;
            boolean operationStatus = getOperationStatus();// 操作状态
            Log.i(TAG, "......QZ Battery value = " + value);

            Log.i(TAG, "......QZ Battery 电池温度");
            int temperature = readWordData(fd, BatteryParamEnum.TEMPERATURE.getCmd());// 电池温度
            double formatTemperature = (double) (temperature - 2732) / 10;


            Log.i(TAG, "......readSn ......更新UI");
            setTextView(text_absoluteStateOfCharge, (absoluteStateOfCharge > 0 && absoluteStateOfCharge < 100), absoluteStateOfCharge, BatteryParamEnum.ABSOLUTE_STATE_OF_CHARGE);
            setTextView(text_relativeStateOfCharge, (relativeStateOfCharge < 100 && relativeStateOfCharge > 0), relativeStateOfCharge, BatteryParamEnum.RELATIVE_STATE_OF_CHARGE);
            setTextView(text_stateOfHealth, stateOfHealth >= 99, stateOfHealth, BatteryParamEnum.STATE_OF_HEALTH);
            setTextView(text_voltage, (vo1 < 12000 && vo1 > 11000), vo1, BatteryParamEnum.VOLTAGE);
            setTextView(text_remainingCapacity, remainingCapacity > 0, remainingCapacity, BatteryParamEnum.REMAINING_CAPACITY);
            setTextView(text_operationStatus, operationStatus, operationStatus ? "正常" : "异常", BatteryParamEnum.OPERATION_STATUS);
            setTextView(text_temperature, (Double.compare(formatTemperature, new Double("30.0")) == -1 && temperature > 0), formatTemperature, BatteryParamEnum.TEMPERATURE);

            // 得出测试结果
            resultStr = resultFlag ? "测试通过,请插入下一个电池" : "测试失败,请贴上不良标签";
            text_result.setText(resultStr);
            text_result.setBackgroundColor(resultFlag ? greenColor : redColor);

            // 循环结束,给参数更新数值
            lastSn = readSn;
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }


    /**
     * 未插入电池时,清空参数,提醒插入电池
     */
    private void setWaiting() {
        text_relativeStateOfCharge.setText("......请插入电池......");
        text_absoluteStateOfCharge.setText("......请插入电池......");
        text_stateOfHealth.setText("......请插入电池......");
        text_serialNumber.setText("......请插入电池......");
        text_voltage.setText("......请插入电池......");
        text_remainingCapacity.setText("......请插入电池......");
        text_operationStatus.setText("......请插入电池......");
        text_temperature.setText("......请插入电池......");
        text_result.setText("");

        text_relativeStateOfCharge.setBackgroundColor(warningColor);
        text_absoluteStateOfCharge.setBackgroundColor(warningColor);
        text_stateOfHealth.setBackgroundColor(warningColor);
        text_serialNumber.setBackgroundColor(warningColor);
        text_voltage.setBackgroundColor(warningColor);
        text_remainingCapacity.setBackgroundColor(warningColor);
        text_operationStatus.setBackgroundColor(warningColor);
        text_temperature.setBackgroundColor(warningColor);
        text_result.setBackgroundColor(Color.WHITE);
    }

    /**
     * 读取电池SN
     *
     * @return
     */
    private String readSN() {
        String sn = "";
        try {
            Log.i(TAG, "......QZ Battery 生产日期");
            int date = 0;// 生产日期
            date = readWordData(fd, BatteryParamEnum.MANUFACTURER_DATE.getCmd());
            int year = date / 512 + 1980;
            int month = (date % 512) / 32;
            int day = (date % 512) % 32;
            String manufacturerDate = (month < 10 ? "0" + month : month + "") + year;
            Log.i(TAG, "......QZ Battery 生产日期 = " + manufacturerDate);
            Log.i(TAG, "......QZ Battery 序列号");
            int serialNumber = readWordData(fd, BatteryParamEnum.SERIAL_NUMBER.getCmd());// 序列号
            Log.i(TAG, "......QZ Battery format serial number = " + String.format("%04X", serialNumber));
            sn = manufacturerDate + "-" + String.format("%04X", serialNumber);
            readSn = sn;
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return sn;
    }

    private boolean getOperationStatus() throws RemoteException {
        int cmd = 0x44;
        int len = 6;
        int val = 0x5400;
        char[] blockData = readBlockData(fd, cmd, len, val);
        Log.i(TAG, "......QZ getOperationStatus = " + charArrayToHex(blockData));
        String hexChar = String.format("%02x", (int) blockData[4]);
        if (hexChar.equals("ff")) {
            return false;
        }
        int data = blockData[4] & 3;
        return data == 3;
    }

    /**
     * 读取Block数据
     *
     * @param fd  文件
     * @param cmd 读取命令
     * @return
     * @throws RemoteException
     */
    private char[] readBlockData(int fd, int cmd, int len, int val) throws RemoteException {
        int i = qzBatteryServerManager.batteryWriteBlockData(fd, cmd, 2, val);
        Log.i(TAG, "......QzBatteryServerManagerService i= " + i);
        return qzBatteryServerManager.batteryReadBlockDataM(fd, cmd, 6, val);
    }


    /**
     * 读取Word数据
     *
     * @param fd  文件
     * @param cmd 读取命令
     * @return
     * @throws RemoteException
     */
    private int readWordData(int fd, int cmd) throws RemoteException {
        return qzBatteryServerManager.btteryReadWordDataM(fd, cmd);
    }

    /**
     * @param tv        文本框
     * @param res       判断表达式
     * @param data      数据
     * @param labelEnum 数据Label
     * @throws RemoteException
     */
    private static final int greenColor = Color.GREEN;
    private static final int redColor = Color.RED;
    private static final int warningColor = Color.YELLOW;

    private String setTextView(TextView tv, boolean res, Object data, BatteryParamEnum labelEnum) throws RemoteException {
        if (res == false) {
            resultFlag = false;
        }
        tv.setBackgroundColor(res == true ? greenColor : redColor);
        String str = labelEnum.getLabel() + "   :   " + data + labelEnum.getSymbol();
        tv.setText(str);
        return str;
    }


}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值