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

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

根据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_SIZE	512
#define MAX_LINE_LEN		((CMD_MAX_DATA_SIZE + 4) * 3)
#define CMD_RETRY_DELAY		100 /* in ms */
#define RETRY_LIMIT		3

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;
}