]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - bms-linux/bqtool.git/blob - bqtool.c
84384cdf0d5c20afd38a780c20ba79f4953602e4
[bms-linux/bqtool.git] / bqtool.c
1 /*
2  * Copyright (C) 2014 Texas Instruments Inc
3  *
4  * Aneesh V <aneesh@ti.com>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
19 #include <stdio.h>
20 #include <string.h>
21 #include <i2c-dev.h>
22 #include <sys/ioctl.h>
23 #include <unistd.h>
24 #include <stdint.h>
25 #include <fcntl.h>
26 #include <stdbool.h>
28 /* #define BQPROG_DEBUG */
30 #define CMD_MAX_DATA_SIZE       96
31 #define MAX_LINE_LEN            ((CMD_MAX_DATA_SIZE + 4) * 3)
32 #define RETRY_LIMIT             3
33 #define CMD_RETRY_DELAY         100 /* in ms */
34 #define DEFAULT_POLL_INTVL      360
35 #define I2C_BUS                 "2"
36 #define I2C_DEV                 "/dev/i2c-"I2C_BUS
37 #define SYSFS_POLL_INTVL "/sys/module/bq27x00_battery/parameters/poll_interval"
39 #ifdef __GNUC__
40 #define __PACKED        __attribute__((packed))
41 #else
42 #error "Make sure structure cmd_t is packed"
43 #endif
45 typedef enum {
46         CMD_INVALID = 0,
47         CMD_R,  /* Read */
48         CMD_W,  /* Write */
49         CMD_C,  /* Compare */
50         CMD_X,  /* Delay */
51 } cmd_type_t;
53 /*
54  * DO NOT change the order of fields - particularly reg
55  * should be immediately followed by data
56  */
57 typedef struct {
58         cmd_type_t cmd_type;
59         uint8_t addr;
60         uint8_t reg;
61         union {
62                 uint8_t bytes[CMD_MAX_DATA_SIZE + 1];
63                 uint16_t delay;
64         } data;
65         uint8_t data_len;
66         uint32_t line_num;
67 } __PACKED cmd_t;
69 static uint32_t line_num;
71 /*
72  * Print usage of all commands when cmd == NULL
73  * Otherwise print the usage of the respective command
74  * Currently we have only one commnd
75  */
76 static void usage(const char *cmd)
77 {
78         fprintf(stderr, "Usage: bqtool --flash <bqfs-file|dffs-file>\n");
79 }
81 static void print_delay(cmd_t *cmd)
82 {
83         fprintf(stdout, "delay: %d", cmd->data.delay);
84 }
86 static void print_buf(FILE *fd, uint8_t *buf, uint8_t len)
87 {
88         uint8_t i;
90         for (i = 0; i < len; i++)
91                 fprintf(fd, " %02x", buf[i]);
92 }
94 static void print_data(cmd_t *cmd)
95 {
96         int i;
98         fprintf(stdout, "data: ");
99         print_buf(stdout, cmd->data.bytes, cmd->data_len);
101 static void print_addr_reg(cmd_t *cmd)
103         fprintf(stdout, "addr: %02x ", cmd->addr);
104         fprintf(stdout, "reg: %02x ", cmd->reg);
107 #ifdef BQPROG_DEBUG
108 static void print_cmd(cmd_t *cmd)
110         switch (cmd->cmd_type) {
111         case CMD_R:
112                 fprintf(stdout, "R: ");
113                 print_addr_reg(cmd);
114                 break;
115         case CMD_W:
116                 fprintf(stdout, "W: ");
117                 print_addr_reg(cmd);
118                 print_data(cmd);
119                 break;
120         case CMD_C:
121                 fprintf(stdout, "C: ");
122                 print_addr_reg(cmd);
123                 print_data(cmd);
124                 break;
125         case CMD_X:
126                 fprintf(stdout, "X: ");
127                 print_delay(cmd);
128                 break;
129         default:
130                 fprintf(stdout, "Unknown: ");
131                 break;
132         }
133         fprintf(stdout, "\n");
135 #else
136 static void print_cmd(cmd_t *cmd)
139 #endif
141 static int read_bq_poll_intvl(void)
143         int poll_file = -1;
144         int poll_intvl = -1;
145         char buf[20];
147         poll_file = open(SYSFS_POLL_INTVL, O_RDONLY);
149         if ((poll_file >= 0) && read(poll_file, buf, 20))
150                 sscanf(buf, "%d", &poll_intvl);
151         else
152                 fprintf(stderr, "Failed to read %s\n", SYSFS_POLL_INTVL);
154         if (poll_file >= 0)
155                 close(poll_file);
157         return poll_intvl;
160 static bool write_bq_poll_intvl(int poll_intvl)
162         int poll_file = -1;
163         char buf[20];
165         poll_file = open(SYSFS_POLL_INTVL, O_RDWR);
167         if (poll_file >= 0) {
168                 sprintf(buf, "%d", poll_intvl);
169                 write(poll_file, buf, 20);
170                 close(poll_file);
171         }
173         if (poll_intvl == read_bq_poll_intvl())
174                 return true;
175         else
176                 return false;
179 static bool i2c_rw(int i2c_file, cmd_t *cmd, int write)
181         int ret;
182         struct i2c_rdwr_ioctl_data i2c_data;
183         char *op;
184         /* msg[0] for write command and msg[1] for read command */
185         struct i2c_msg msgs[2];
187         /* Linux expects 7 bit address */
188         msgs[0].addr = cmd->addr >> 1;
189         /* reg is data too as far as I2C xfr is concerned */
190         msgs[0].buf = (char *)&cmd->reg;
191         msgs[0].flags = 0;
193         if (write) {
194                 msgs[0].len = cmd->data_len + 1;
195                 i2c_data.nmsgs = 1;
196                 op = "write";
197         } else {
198                 msgs[0].len = 1;
200                 /* read command */
201                 msgs[1].addr = cmd->addr >> 1;
202                 msgs[1].buf = (char *)cmd->data.bytes;
203                 msgs[1].flags = I2C_M_RD;
204                 msgs[1].len = cmd->data_len;
206                 i2c_data.nmsgs = 2;
207                 op = "read";
208         }
210         i2c_data.msgs = msgs;
211         ret = ioctl(i2c_file, I2C_RDWR, &i2c_data);
212         if (ret < 0) {
213                 fprintf(stderr, "I2C %s failed at line %d error = %d\n",
214                         op, cmd->line_num, ret);
215                 return false;
216         }
218         return true;
221 static bool do_exec_cmd(int i2c_file, cmd_t *cmd)
223         uint8_t tmp_buf[CMD_MAX_DATA_SIZE];
225         switch (cmd->cmd_type) {
226         case CMD_R:
227                 return i2c_rw(i2c_file, cmd, 0);
229         case CMD_W:
230                 return i2c_rw(i2c_file, cmd, 1);
232         case CMD_C:
233                 memcpy(tmp_buf, cmd->data.bytes, cmd->data_len);
234                 if (!i2c_rw(i2c_file, cmd, 0))
235                         return false;
236                 if (memcmp(tmp_buf, cmd->data.bytes, cmd->data_len)) {
237                         fprintf(stderr, "\nCommand C failed at line %d:\n",
238                                 cmd->line_num);
239                         fprintf(stderr, "Expected data:");
240                         print_buf(stderr, tmp_buf, cmd->data_len);
241                         fprintf(stderr, "\nReceived data:");
242                         print_buf(stderr, cmd->data.bytes, cmd->data_len);
243                         fprintf(stderr, "\n");
244                         return false;
245                 }
246                 return true;
248         case CMD_X:
249                 usleep(cmd->data.delay * 1000);
250                 return true;
252         default:
253                 fprintf(stderr, "Unsupported command at line %d\n",
254                         cmd->line_num);
255                 return false;
256         }
259 static bool execute_cmd(int i2c_file, cmd_t *cmd)
261         int i = 1;
262         bool ret;
264         ret = do_exec_cmd(i2c_file, cmd);
266         while (!ret && i < RETRY_LIMIT) {
267                 usleep(CMD_RETRY_DELAY * 1000);
268                 ret = do_exec_cmd(i2c_file, cmd);
269                 i++;
270         }
272         if (!ret) {
273                 fprintf(stderr, "Command execution failed at line %d"
274                         " addr - 0x%02x reg - 0x%02x, tried %d times\n",
275                         cmd->line_num, cmd->addr, cmd->reg, RETRY_LIMIT);
276         }
278         return ret;
281 static bool get_delay(uint16_t *delay)
283         char *tok;
284         uint32_t temp;
286         tok = strtok(NULL, " ");
287         if (!tok)
288                 return false; /*end of line or file */
290         if (1 != sscanf(tok, "%u", &temp)) {
291                 fprintf(stderr, "Syntax error while parsing delay at line %d\n",
292                         line_num);
293                 return false; /* syntax error */
294         }
296         if (temp > UINT16_MAX) {
297                 fprintf(stderr, "Command X delay too high at line %d - %dms\n",
298                         line_num, temp);
299                 return false;
300         }
302         *delay = (uint16_t)temp;
303         return true;
307 /*
308  * Returns:
309  *       0: success
310  *       1: EOF
311  *      -1: Parse error
312  */
313 static int get_byte(uint8_t *byte)
315         char *tok;
316         unsigned int temp;
318         tok = strtok(NULL, " \t\r\n");
319         if (!tok)
320                 return 1; /*end of line or file */
322         if ((strlen(tok) != 2) || (sscanf(tok, "%2x", &temp) != 1)) {
323                         fprintf(stderr, "Syntax error at line %d, token - %s,"
324                                 " temp - %x\n", line_num, tok, temp);
325                         return -1; /* syntax error */
326         }
328         *byte = (uint8_t)temp;
330         return 0;       /* success */
333 static bool get_addr_n_reg(cmd_t *cmd)
335         if (get_byte(&cmd->addr))
336                 return false;
338         if (get_byte(&cmd->reg))
339                 return false;
341         return true;
344 static bool get_data_bytes(cmd_t *cmd)
346         int ret, i = 0;
347         cmd->data_len = 0;
349         do {
350                 ret = get_byte(&cmd->data.bytes[i++]);
351                 if (ret == -1)
352                         return false;
353         } while ((ret == 0) && (i <= CMD_MAX_DATA_SIZE));
355         if (ret == 0) {
356                 fprintf(stderr, "More than allowed number of data bytes at"
357                         " line %d, data_len %d, i %d\n", cmd->line_num,
358                         cmd->data_len, i);
359                 return false;
360         }
362         cmd->data_len = i - 1;
364         return true;
367 static bool get_line(FILE *bqfs_file, char **buffer)
369         int c;
370         int i = 0;
371         bool ret = true;
372         char *buf;
374         buf = malloc(MAX_LINE_LEN);
375         line_num++;
377         while (1) {
378                 c = fgetc(bqfs_file);
380                 if (feof(bqfs_file)) {
381 #ifdef BQPROG_DEBUG
382                         fprintf(stdout, "EOF\n");
383 #endif
384                         break;
385                 } else if (ferror(bqfs_file)) {
386                         fprintf(stderr, "File read error\n");
387                         ret = false;
388                         break;
389                 }
391                 if (((c == '\r') || (c == '\n') || (c == '\t')
392                         || (c == ' ')) && (i == 0)) {
393                         /*
394                          * Skip leading white space, if any, at the beginning
395                          * of the line because this interferes with strtok
396                          */
397                         fprintf(stderr, "Leading whitespace at line %d\n",
398                                 line_num);
399                         if (c == '\n')
400                                 line_num++;
401                         continue;       /* blank line, let's continue */
402                 } else if (c == '\n') {
403                         /* We've reached end of line */
404                         break;
405                 }
407                 buf[i++] = c;
409                 if (i == MAX_LINE_LEN) {
410                         /*
411                          * Re-allocate in case the line is longer than
412                          * expected
413                          */
414                         buf = realloc(buf, MAX_LINE_LEN * 2);
415                         fprintf(stderr, "Line %d longer than expected,"
416                                 " reallocating..\n", line_num);
417                 } else if (i == MAX_LINE_LEN * 2) {
418                         /*
419                          * The line is already twice the expected maximum length
420                          * - maybe the bqfs/dffs needs to be fixed
421                          */
422                         fprintf(stderr, "Line %d too long, abort parsing..\n",
423                                 line_num);
424                         ret = false;
425                         break;
426                 }
427         }
429         *buffer = buf;
430         buf[i] = '\0';
432         if (i < 1)
433                 ret = false;
435         return ret;
438 static bool get_cmd(FILE *bqfs_file, cmd_t *cmd)
440         char *res;
441         char *tok;
442         char *buf = NULL;
443         int ret;
445         if (!get_line(bqfs_file, &buf))
446                 goto error;
448         cmd->line_num = line_num;
449         tok = strtok(buf, ":");
450         if (!tok || (strlen(tok) != 1)) {
451                 fprintf(stderr, "Error parsing command at line %d tok=%s"
452                         " buf=%s", line_num, tok, buf);
453                 goto error;
454         }
456         switch (tok[0]) {
457         case 'R':
458         case 'r':
459                 cmd->cmd_type = CMD_R;
460                 if (!get_addr_n_reg(cmd))
461                         goto error;
462                 break;
463         case 'W':
464         case 'w':
465                 cmd->cmd_type = CMD_W;
466                 if (!get_addr_n_reg(cmd))
467                         goto error;
468                 if (!get_data_bytes(cmd))
469                         goto error;
470                 break;
471         case 'C':
472         case 'c':
473                 cmd->cmd_type = CMD_C;
474                 if (!get_addr_n_reg(cmd))
475                         goto error;
476                 if (!get_data_bytes(cmd))
477                         goto error;
478                 break;
479         case 'X':
480         case 'x':
481                 cmd->cmd_type = CMD_X;
482                 if (!get_delay(&cmd->data.delay))
483                         goto error;
484                 break;
485         default:
486                 fprintf(stderr, "No command or unexpected command at"
487                         " line %d tok=\"%s\" buf=\"%s\"",
488                         line_num, tok, buf);
489                 goto error;
490         }
492         print_cmd(cmd);
493         free(buf);
494         return true;
496 error:
497         cmd->cmd_type = CMD_INVALID;
498         free(buf);
499         return false;
502 int bqfs_flash(char *fname)
504         int poll_intvl = -1;
505         int i2c_file = -1;
506         int poll_file = -1;
507         FILE *bqfs_file = NULL;
508         char *line = NULL;
509         cmd_t *cmd = NULL;
510         int ret = 0;
511         char buf[20];
513         bqfs_file = fopen(fname, "r");
514         if (!bqfs_file) {
515                 usage("--flash");
516                 ret = -1;
517                 goto end;
518         }
520         poll_intvl = read_bq_poll_intvl();
521         /* Turn off polling */
522         if (!write_bq_poll_intvl(0)) {
523                 fprintf(stderr, "Failed to stop driver polling\n");
524                 ret = -1;
525                 goto end;
526         }
528         i2c_file = open(I2C_DEV, O_RDWR);
529         if (i2c_file < 0) {
530                 fprintf(stderr, "Failed to open I2C device %s\n", I2C_DEV);
531                 ret = -1;
532                 goto end;
533         }
535         cmd = malloc(sizeof(cmd_t));
537         while (get_cmd(bqfs_file, cmd) && execute_cmd(i2c_file, cmd))
538                 fputc('.', stdout);
540         if (feof(bqfs_file)) {
541                 fprintf(stdout, "\n%s programmed successfully!\n", fname);
542                 ret = 0;
543         } else {
544                 fprintf(stdout, "\nprogramming %s failed!!\n", fname);
545                 ret = -1;
546         }
548 end:
549         if (poll_intvl >= 0) {
550                 if (!write_bq_poll_intvl(poll_intvl))
551                         fprintf(stderr, "Failed to restore driver polling\n");
552         }
554         if (poll_file >= 0)
555                 close(poll_file);
557         if (i2c_file >= 0)
558                 close(i2c_file);
560         if (bqfs_file)
561                 fclose(bqfs_file);
563         if (cmd)
564                 free(cmd);
566         return ret;
569 int main(int argc, char **argv)
571         if ((argc >= 3) && (strncmp(argv[1], "--flash", 7) == 0)) {
572                 return bqfs_flash(argv[2]);
573         } else {
574                 usage(argv[0]);
575                 return -1;
576         }