BQ27510 电量计的校准 的 C语言实现

时间:2021-12-02 14:39:16

根据TI官方MSP430平台移植修改过来的,在Omap37xx(wince)平台测试,理论上和平台无关,伸手党,赶紧复制粘贴代码吧。如果这篇文章帮助了你,给了好评也无妨。


/*
================================================================================
* Texas Instruments OMAP(TM) Platform Software
* (c) Copyright Texas Instruments, Incorporated. All Rights Reserved.
*
* Use of this software is controlled by the terms and conditions found
* in the license agreement under which this software has been supplied.
*
================================================================================
*/
//
// File: bqtool.c
//

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <i2cproxy.h>
#include "bq27500.h"

#define CMD_MAX_DATA_SIZE512
#define MAX_LINE_LEN((CMD_MAX_DATA_SIZE + 4) * 3)
#define CMD_RETRY_DELAY100 /* in ms */
#define RETRY_LIMIT3

typedef enum {
CMD_INVALID = 0,
CMD_R,/* Read */
CMD_W,/* Write */
CMD_C,/* Compare */
CMD_X,/* Delay */
} cmd_type_t;

/*
* DO NOT change the order of fields - particularly reg
* should be immediately followed by data
*/
typedef struct {
cmd_type_t cmd_type;
unsigned char addr;
unsigned char reg;
union {
unsigned char bytes[CMD_MAX_DATA_SIZE + 1];
UINT delay;
} data;
unsigned char data_len;
UINT32 line_num;
CHAR*line;
}cmd_t;

static UINT32 line_num;

/* Parse S into tokens separated by characters in DELIM.
If S is NULL, the saved pointer in SAVE_PTR is used as
the next starting point. For example:
char s[] = "-abc-=-def";
char *sp;
x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def"
x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL
x = strtok_r(NULL, "=", &sp); // x = NULL
// s = "abc/0-def/0"
*/
static char *strtok_r(char *s, const char *delim, char **save_ptr) {
char *token;

if (s == NULL) s = *save_ptr;

/* Scan leading delimiters. */
s += strspn(s, delim);
if (*s == '\0')
return NULL;

/* Find the end of the token. */
token = s;
s = strpbrk(token, delim);
if (s == NULL)
/* This token finishes the string. */
*save_ptr = strchr(token, '\0');
else {
/* Terminate the token and make *SAVE_PTR point past it. */
*s = '\0';
*save_ptr = s + 1;
}

return token;
}

static char *strtok(char *s, const char *delim)
{
static char *last;

return strtok_r(s, delim, &last);
}

//写I2C,根据自己平台修改相关实现
static BOOL i2c_write(HANDLE hI2C, cmd_t *cmd)
{
int ret;
DWORD udwTemp;

if(hI2C)
{
udwTemp=cmd->addr >>1;
DeviceIoControl(hI2C, IOCTL_I2C_SET_SLAVE_ADDRESS, &udwTemp, sizeof(udwTemp), NULL, 0, NULL, NULL);

SetFilePointer(hI2C,LOWORD(cmd->reg),NULL,FILE_BEGIN);
if(!WriteFile(hI2C, cmd->data.bytes, cmd->data_len, &udwTemp, NULL))
{
RETAILMSG(1,(TEXT("ERROR: i2c_write: I2c WriteFile failed.\r\n")));
}
}
return TRUE;
}

//读I2C,根据自己平台修改相关实现
static BOOL i2c_Read(HANDLE hI2C, cmd_t *cmd)
{
int ret;
DWORD udwTemp;

if(hI2C)
{
udwTemp=cmd->addr >>1;
DeviceIoControl(hI2C, IOCTL_I2C_SET_SLAVE_ADDRESS, &udwTemp, sizeof(udwTemp), NULL, 0, NULL, NULL);

SetFilePointer(hI2C,LOWORD(cmd->reg),NULL,FILE_BEGIN);
if(!ReadFile(hI2C, cmd->data.bytes, cmd->data_len,&udwTemp, NULL))
{
RETAILMSG(1,(TEXT("ERROR: i2c_Read: I2c ReadFile failed.\r\n")));
return FALSE;
}else
{
cmd->data_len=udwTemp;
}
}

return TRUE;
}

static BOOL do_exec_cmd(HANDLE i2c_file, cmd_t *cmd)
{
unsigned char tmp_buf[CMD_MAX_DATA_SIZE];
int j=0;

switch (cmd->cmd_type) {
case CMD_R:
return i2c_Read(i2c_file, cmd);

case CMD_W:
return i2c_write(i2c_file, cmd);

case CMD_C:
memcpy(tmp_buf, cmd->data.bytes, cmd->data_len);
if (!i2c_Read(i2c_file, cmd))
return FALSE;
if (memcmp(tmp_buf, cmd->data.bytes, cmd->data_len)) {
RETAILMSG(1, (TEXT("Command C failed at line %d\r\n"),cmd->line_num));
return FALSE;
}
return TRUE;

case CMD_X:
Sleep(cmd->data.delay);
return TRUE;

default:
RETAILMSG(1, (TEXT("Unsupported command at line %d\r\n"),cmd->line_num));
return FALSE;
}
}

static BOOL execute_cmd(HANDLE i2c_file, cmd_t *cmd)
{
int i = 1,j=0;
BOOL ret;

RETAILMSG(0,(TEXT("cmd:cmd_type=%d;addr=%02x,reg=%02x,cmd->data_len=%d,"),cmd->cmd_type,cmd->addr,cmd->reg,cmd->data_len));
#if 0//only for debug TODO:delete
RETAILMSG(1,(TEXT("line=%d:"),cmd->line_num));
for(j=0;j<cmd->data_len;j++)
{
RETAILMSG(1,(TEXT("%02x "),cmd->data.bytes[j]));
}
RETAILMSG(1,(TEXT("\r\n")));
#endif

ret = do_exec_cmd(i2c_file, cmd);

//if execute failed,retry three times
while (!ret && i < RETRY_LIMIT) {
Sleep(CMD_RETRY_DELAY);
ret = do_exec_cmd(i2c_file, cmd);
i++;
}

if (!ret) {
RETAILMSG(1, (TEXT("Command execution failed at line %d addr=0x%02x reg=0x%02x\r\n"),cmd->line_num, cmd->addr, cmd->reg));
}

return ret;
}

static BOOL get_delay(UINT *delay)
{
char *tok;
UINT temp;

tok = strtok(NULL, " ");
if (!tok)
return FALSE; /*end of line or file */

if (1 != sscanf(tok, "%u", &temp)) {
RETAILMSG(1, (TEXT("Syntax error while parsing delay at line %d\r\n"),line_num));
return FALSE; /* syntax error */
}

*delay = (UINT)temp;
return TRUE;
}

/*
* Returns:
* 0: success
* 1: EOF
*-1: Parse error
*/
static int get_byte(unsigned char *byte)
{
char *tok;
unsigned char temp;

tok = strtok(NULL, " ");
if (!tok)
return 1; /*end of line or file */

if ((strlen(tok) != 2) || (sscanf(tok, "%2x", &temp) != 1)) {
RETAILMSG(1, (TEXT("Syntax error at line %d\r\n"), line_num));
return -1; /* syntax error */
}

*byte = (unsigned char)temp;

return 0;/* success */
}

static BOOL get_addr_n_reg(cmd_t *cmd)
{
if (get_byte(&cmd->addr))
return FALSE;

if (get_byte(&cmd->reg))
return FALSE;

return TRUE;
}

static BOOL get_data_bytes(cmd_t *cmd)
{
int ret, i = 0;
cmd->data_len = 0;

do {
ret = get_byte(&cmd->data.bytes[i++]);
} while ((ret == 0) && (i <= CMD_MAX_DATA_SIZE));

if (ret == 0) {
RETAILMSG(1, (TEXT("More than allowed number of data bytes at line %d, data_len %d, i %d\r\n"), cmd->line_num,cmd->data_len, i));
return FALSE;
}

cmd->data_len = i - 1;

return TRUE;
}

static BOOL get_line(FILE *bqfs_file, char **buffer)
{
int c;
int i = 0;
BOOL ret = TRUE;
char *buf;

buf = malloc(MAX_LINE_LEN);
line_num++;

while (1) {
c = fgetc(bqfs_file);

if (feof(bqfs_file)) {
break;
} else if (ferror(bqfs_file)) {
RETAILMSG(1, (TEXT("File read error\r\n")));
ret = FALSE;
break;
}

if (((c == '\r') || (c == '\n') || (c == '\t')
|| (c == ' ')) && (i == 0)) {
/*
* Skip leading white space, if any, at the beginning
* of the line because this interferes with strtok
*/
RETAILMSG(1, (TEXT("Leading whitespace at line %d\r\n"),line_num));
if (c == '\n')
line_num++;
continue;/* blank line, let's continue */
} else if (c == '\n') {
/* We've reached end of line */
break;
}

buf[i++] = c;

if (i == MAX_LINE_LEN) {
/*
* Re-allocate in case the line is longer than
* expected
*/
buf = realloc(buf, MAX_LINE_LEN * 2);
RETAILMSG(1, (TEXT("Line %d longer than expected,reallocating..\r\n"), line_num));
} else if (i == MAX_LINE_LEN * 2) {
/*
* The line is already twice the expected maximum length
* - maybe the bqfs/dffs needs to be fixed
*/
RETAILMSG(1, (TEXT("Line %d too long, abort parsing..\r\n"),line_num));
ret = FALSE;
break;
}
}

*buffer = buf;
buf[i] = '\0';

if (i < 1)
ret = FALSE;

return ret;
}


static BOOL get_cmd(FILE *bqfs_file, cmd_t *cmd)
{
char *res;
char *tok;
char *buf = NULL;
BOOL ret;

while ((ret = get_line(bqfs_file, &buf))) {
if (buf[0] == ';') {
/*
* Comment line - ignore it and get the
* next line
*/
RETAILMSG(0, (TEXT("Comment line,line_num=%d\r\n"),line_num));
free(buf);
} else {
break;
}
}

if (!ret)
goto error;

cmd->line_num = line_num;
tok = strtok(buf, ":");
if (!tok || (strlen(tok) != 1)) {
RETAILMSG(1, (TEXT("Error parsing command at line %d\r\n"),line_num));
goto error;
}

switch (tok[0]) {
case 'R':
case 'r':
cmd->cmd_type = CMD_R;
if (!get_addr_n_reg(cmd))
goto error;
break;
case 'W':
case 'w':
cmd->cmd_type = CMD_W;
if (!get_addr_n_reg(cmd))
goto error;
if (!get_data_bytes(cmd))
goto error;
break;
case 'C':
case 'c':
cmd->cmd_type = CMD_C;
if (!get_addr_n_reg(cmd))
goto error;
if (!get_data_bytes(cmd))
goto error;
break;
case 'X':
case 'x':
cmd->cmd_type = CMD_X;
cmd->data_len = 1;//only one data
if (!get_delay(&cmd->data.delay))
goto error;
break;
default:
RETAILMSG(1, (TEXT("No command or unexpected command at line %d.\r\n"),line_num));
goto error;
}

if(buf)
{
free(buf);
}
return TRUE;

error:
RETAILMSG(1, (TEXT("get_line error,line_num=%d\r\n"),line_num));
cmd->cmd_type = CMD_INVALID;
free(buf);
return FALSE;
}


//Param:char *fname
//File to flash BQ27510 generate by TI's engineer.
//for example:bq27510G3.bqfs(with G2 update G3 firmware)
int bqfs_flash(char *fname)
{
FILE *bqfs_file = NULL;
cmd_t *cmd = NULL;
int ret = 0;
DWORD udwTemp;
HANDLE hI2C=NULL;

RETAILMSG(0,(TEXT("bqfs_flush beging...\r\n")));

bqfs_file = fopen(fname, "r");
if (!bqfs_file) {
RETAILMSG(1,(TEXT("bqfs_flush fopen failed.\r\n")));
ret = -1;
goto end;
}

hI2C=CreateFile(BATT_I2C_PORT, GENERIC_READ | GENERIC_WRITE, 0,NULL, OPEN_EXISTING, 0, NULL);
if(!hI2C)
{
RETAILMSG(1,(TEXT("bqfs_flash: I2c CreateFile failed.\r\n")));
ret = -1;
goto end;
}

//I2C相关配置寻址,根据自己平台修改相关实现
//set slave address
udwTemp=I2CSLAVEADDR;
DeviceIoControl(hI2C, IOCTL_I2C_SET_SLAVE_ADDRESS, &udwTemp, sizeof(udwTemp), NULL, 0, NULL, NULL);

//set i2c work mode
udwTemp=I2C_SUBADDRESS_MODE_8;
DeviceIoControl(hI2C, IOCTL_I2C_SET_SUBADDRESS_MODE, &udwTemp, sizeof(udwTemp), NULL, 0, NULL, NULL);

//set i2c transfer speed
udwTemp=SLOWSPEED_MODE;
DeviceIoControl(hI2C, IOCTL_I2C_SET_BAUD_INDEX, &udwTemp, sizeof(udwTemp), NULL, 0, NULL, NULL);

cmd = malloc(sizeof(cmd_t));
if(!cmd)
{
RETAILMSG(1, (TEXT("bqfs_flash malloc failed.\r\n")));
ret=-1;
goto end;
}

while (get_cmd(bqfs_file, cmd) && execute_cmd(hI2C, cmd));

if (feof(bqfs_file)) {
RETAILMSG(1, (TEXT("programmed successfully!\r\n")));
ret = 0;
} else {
RETAILMSG(1, (TEXT("programming failed!!\r\n")));
ret = -1;
}

end:

if (cmd)
free(cmd);

if(hI2C)
{
CloseHandle(hI2C);
hI2C=NULL;
}

if (bqfs_file)
fclose(bqfs_file);

return ret;
}