00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <sys/types.h>
00033 #include <sys/ioctl.h>
00034 #include <stdio.h>
00035 #include <stdarg.h>
00036 #include <string.h>
00037 #include <stdlib.h>
00038 #include <unistd.h>
00039 #include <fcntl.h>
00040 #include <termios.h>
00041
00042
00043 #include "proto.h"
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 static int serial_fd;
00056 int read_timeout = 100;
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 static int serial_write(uint8_t c);
00069 static int serial_readTimeout(uint8_t *c, int timeout);
00070 static uint8_t serial_read(uint8_t *c);
00071 static uint8_t serial_readEncoded(uint8_t *c);
00072 static void encode_send_byte(uint8_t c);
00073
00074
00075
00076
00077
00078
00079 void fatalnum(int num, char *message, ...)
00080 {
00081 char buffer[512];
00082 va_list ap;
00083 va_start(ap, message);
00084 vsprintf(buffer, message, ap);
00085 fprintf(stderr, "Error: %s\n", buffer);
00086 va_end(ap);
00087 exit(num);
00088 }
00089
00090
00091 void fatal(char *message, ...)
00092 {
00093 char buffer[512];
00094 va_list ap;
00095 va_start(ap, message);
00096 vsprintf(buffer, message, ap);
00097 fprintf(stderr, "Error: %s\n", buffer);
00098 va_end(ap);
00099 exit(1);
00100 }
00101
00102 void warning(char *message, ...)
00103 {
00104 char buffer[512];
00105 va_list ap;
00106 va_start(ap, message);
00107 vsprintf(buffer, message, ap);
00108 fprintf(stderr, "Warning: %s\n", buffer);
00109 va_end(ap);
00110 }
00111
00112
00113
00114
00115
00116 void ionkbd_send_packet(uint8_t cmd, uint8_t length, uint8_t *data)
00117 {
00118 uint8_t i, crc = cmd + length;
00119 serial_write(IONKBD_START);
00120 encode_send_byte(cmd);
00121 encode_send_byte(length);
00122 for (i=0;i<length;i++)
00123 {
00124 crc += data[i];
00125 encode_send_byte(data[i]);
00126 }
00127 encode_send_byte(crc);
00128 }
00129
00130
00131
00132
00133
00134 int ionkbd_get_response(uint8_t *command, uint8_t *length, uint8_t *data)
00135 {
00136 uint8_t cmd, len, crc, mycrc, c = 0;
00137 uint8_t i = 0;
00138 while(c != IONKBD_START)
00139 {
00140 if (serial_read(&c)) return 1;
00141 }
00142 if (serial_readEncoded(&cmd)) return 1;
00143 if (serial_readEncoded(&len)) return 1;
00144 mycrc = cmd+len;
00145 while (i<len)
00146 {
00147 if (serial_readEncoded(&data[i])) return 1;
00148 mycrc += data[i++];
00149 }
00150 if (serial_readEncoded(&crc)) return 1;
00151 if (crc != mycrc)
00152 {
00153 fatal("Response packet CRC failed");
00154 }
00155 *command = cmd;
00156 *length = len;
00157 return 0;
00158 }
00159
00160
00161
00162
00163
00164 int ionkbd_send_request(
00165 uint8_t cmd,
00166 uint8_t length,
00167 uint8_t *data,
00168 uint8_t *rcmd,
00169 uint8_t *rlen,
00170 uint8_t *rdata)
00171 {
00172 ionkbd_send_packet(cmd, length, data);
00173 return ionkbd_get_response(rcmd, rlen, rdata);
00174 }
00175
00176
00177
00178
00179
00180 int sector_erase(int mode, uint16_t addr)
00181 {
00182 uint8_t data[2], rcmd, rlen, rdata[16];
00183 data[0] = addr>>8;
00184 data[1] = addr&0xFF;
00185 uint8_t req = (mode == MODE_BOOT) ? IONKBD_REQ_ERASE_FLASH_BOOT :
00186 IONKBD_REQ_ERASE_FLASH;
00187 if (ionkbd_send_request(req, 2, data, &rcmd, &rlen, rdata))
00188 {
00189 warning("Micro failed to respond to erase request (0x%02X)", req);
00190 return 1;
00191 }
00192 if (rcmd!=IONKBD_RESP_ERASE)
00193 {
00194 warning("Invalid erase response");
00195 return 1;
00196 }
00197 if (!rdata[0])
00198 {
00199 warning("Flash erase failed");
00200 return 1;
00201 }
00202 return 0;
00203 }
00204
00205
00206
00207
00208
00209 void micro_erase(int mode, uint16_t start, uint16_t end)
00210 {
00211 uint32_t pos = start;
00212 uint8_t tries;
00213 while (pos < end)
00214 {
00215 printf("Erasing sector @ 0x%04X\r", pos);
00216 tries = 0;
00217 while ((sector_erase(mode, pos)) && (tries<3))
00218 {
00219 tries++;
00220 warning("Erase attempt %d failed", tries);
00221 }
00222 if (tries==3)
00223 {
00224 fatal("Error erasing sector 0x%04X", pos);
00225 }
00226 pos += 512;
00227 }
00228 printf("\nErasing done\n");
00229 }
00230
00231
00232
00233
00234
00235 int chunk_program(int mode, uint16_t addr, uint8_t len, uint8_t *chunk)
00236 {
00237 uint8_t data[32], rcmd, rlen, rdata[16];
00238 data[0] = addr>>8;
00239 data[1] = addr&0xFF;
00240 uint8_t req = (mode == MODE_BOOT) ? IONKBD_REQ_PROGRAM_FLASH_BOOT :
00241 IONKBD_REQ_PROGRAM_FLASH;
00242 memcpy(&data[2], chunk, len);
00243 if (ionkbd_send_request(req, 2+len, data, &rcmd, &rlen, rdata))
00244 {
00245 fatal("Micro failed to respond to flash request (0x%02X)", req);
00246 }
00247 if (rcmd!=IONKBD_RESP_FLASH)
00248 {
00249 fatal("Invalid flash response");
00250 }
00251 if (!rdata[0])
00252 {
00253 fatal("Flash write failed at 0x%04X", (rdata[1]<<8)|rdata[2]);
00254 }
00255 return 0;
00256 }
00257
00258 int dr1000_micro_program_application(char* filename)
00259 {
00260 int size, pos=0;
00261 uint8_t bsize, bdata[16];
00262 uint16_t baddr;
00263
00264
00265 FILE *f = fopen(filename, "rb");
00266
00267 fseek(f, 0, SEEK_END);
00268 size = ftell(f)-2;
00269 fseek(f, 2, SEEK_SET);
00270
00271 while (pos<size)
00272 {
00273 fread(&bsize, 1, 1, f);
00274 fread(&baddr, 2, 1, f);
00275 baddr = ((baddr&0xFF)<<8) | (baddr>>8);
00276 bsize -= 2;
00277 fread(bdata, bsize, 1, f);
00278 if ((bsize>0x0E) ||
00279 (baddr<DR1000_APPL_ADDR_MIN) ||
00280 (baddr>DR1000_APPL_ADDR_MAX))
00281 {
00282 fatal("Invalid firmware params: size: 0x%02X, addr: 0x%04X",
00283 bsize, baddr);
00284 exit(1);
00285 }
00286 chunk_program(MODE_APP, baddr, bsize, bdata);
00287 pos += (bsize+3);
00288 }
00289 fclose(f);
00290 return 0;
00291 }
00292
00293 int dr800_micro_program_application(char* filename)
00294 {
00295 int size, pos=0;
00296 uint8_t bdata[16];
00297
00298
00299 FILE *f = fopen(filename, "rb");
00300
00301 fseek(f, 0, SEEK_END);
00302 size = ftell(f)-2;
00303 fseek(f, 0, SEEK_SET);
00304
00305 while (pos<size)
00306 {
00307 fread(bdata, 16, 1, f);
00308 printf("Programming address 0x%04X\r", DR800_APPL_ADDR_MIN + pos);
00309 chunk_program(MODE_APP, DR800_APPL_ADDR_MIN + pos, 16, bdata);
00310 pos += 16;
00311 }
00312 printf("\nProgramming done\n");
00313 fclose(f);
00314 return 0;
00315 }
00316
00317 int dr800_micro_program_bootloader(char* filename)
00318 {
00319 int size, pos=0;
00320 uint8_t bdata[16];
00321
00322
00323 FILE *f = fopen(filename, "rb");
00324
00325 fseek(f, 0, SEEK_END);
00326 size = ftell(f)-2;
00327 fseek(f, 0, SEEK_SET);
00328
00329 while (pos<size)
00330 {
00331 fread(bdata, 16, 1, f);
00332 printf("Programming address 0x%04X\r", DR800_BOOT_ADDR_MIN + pos);
00333 chunk_program(MODE_BOOT, DR800_BOOT_ADDR_MIN + pos, 16, bdata);
00334 pos += 16;
00335 }
00336 printf("\nProgramming done\n");
00337 fclose(f);
00338 return 0;
00339 }
00340
00341 int micro_read_devicetype(int mode)
00342 {
00343 uint8_t data[4], rcmd, rlen, rdata[16];
00344 data[0] = DEVICETYPE_ADDR>>8;
00345 data[1] = DEVICETYPE_ADDR&0xFF;
00346 data[2] = 1;
00347 uint8_t req = (mode==MODE_BOOT) ? IONKBD_REQ_READ_FLASH :
00348 IONKBD_REQ_READ_FLASH_BOOT;
00349 if (ionkbd_send_request(req, 3, data, &rcmd, &rlen, rdata))
00350 {
00351 fatal("Micro failed to respond to flash request");
00352 }
00353 if (rcmd!=IONKBD_RESP_READ)
00354 {
00355 fatal("Invalid flash response: 0x%02X", rcmd);
00356 }
00357 return rdata[0];
00358 }
00359
00360 int micro_write_devicetype(int mode, int devtype)
00361 {
00362 uint8_t data[3], rcmd, rlen, rdata[16];
00363 data[0] = DEVICETYPE_ADDR>>8;
00364 data[1] = DEVICETYPE_ADDR&0xFF;
00365 data[2] = devtype;
00366 uint8_t req = (mode==MODE_BOOT) ? IONKBD_REQ_PROGRAM_FLASH :
00367 IONKBD_REQ_PROGRAM_FLASH_BOOT;
00368 if (ionkbd_send_request(req, 3, data, &rcmd, &rlen, rdata))
00369 {
00370 fatal("Micro failed to respond to flash request");
00371 }
00372 if (rcmd!=IONKBD_RESP_FLASH)
00373 {
00374 fatal("Invalid flash response");
00375 }
00376 if (!rdata[0])
00377 {
00378 fatal("Flash write failed at 0x%04X", (rdata[1]<<8)|rdata[2]);
00379 }
00380 return 0;
00381 }
00382
00383 int micro_check_battery_charge(uint16_t min_level)
00384 {
00385 uint8_t rcmd, rlen, rdata[16];
00386 uint8_t level, charging;
00387 if (ionkbd_send_request(IONKBD_REQ_GET_BATTERY, 0, NULL,
00388 &rcmd, &rlen, rdata))
00389 {
00390 fatal("Micro failed to respond to battery request");
00391 }
00392 if (rcmd!=IONKBD_RESP_BATTERY)
00393 {
00394 fatal("Invalid flash response");
00395 }
00396 level = rdata[0];
00397 charging = rdata[1];
00398 printf("Micro battery at %d%%%s\n", level, charging?", charging":"");
00399 if (level>=min_level)
00400 {
00401 return 1;
00402 }
00403 else
00404 {
00405 return ((level>5) && charging);
00406 }
00407 }
00408
00409 int micro_get_versions(uint16_t *bootloader, uint16_t *application)
00410 {
00411 uint8_t rcmd, rlen, rdata[16];
00412 if (ionkbd_send_request(IONKBD_REQ_GET_VERSION, 0, NULL,
00413 &rcmd, &rlen, rdata))
00414 {
00415 fatal("Micro failed to respond to version request");
00416 }
00417 if (rcmd!=IONKBD_RESP_VERSION)
00418 {
00419 fatal("Invalid version response");
00420 }
00421 *bootloader = (rdata[0]<<8)|rdata[1];
00422 *application = (rdata[2]<<8)|rdata[3];
00423 return 0;
00424 }
00425
00426 void micro_enter_mode(uint8_t boot)
00427 {
00428 uint8_t data, rcmd, rlen, rdata[16];
00429 uint8_t tries = 0;
00430 int i;
00431
00432 printf("Entering %s mode.\n", boot ? "app" : "boot");
00433 while (tries<5)
00434 {
00435 for (i=0;i<10;i++)
00436 {
00437 serial_write(IONKBD_START);
00438 usleep(1 * 1000);
00439 }
00440 usleep(5 * 1000);
00441 if (ionkbd_send_request(IONKBD_REQ_GET_STATUS, 0, NULL,
00442 &rcmd, &rlen, rdata))
00443 {
00444 warning("Micro failed to respond to status request");
00445 }
00446 else
00447 {
00448 if (rcmd!=IONKBD_RESP_STATUS)
00449 {
00450 warning("Invalid response from status request: 0x%02X", rcmd);
00451 }
00452 else
00453 {
00454 if ((rdata[0]&1)==boot)
00455 {
00456 return;
00457 }
00458 data = boot;
00459 if (ionkbd_send_request(IONKBD_REQ_SET_MODE, 1, &data,
00460 &rcmd, &rlen, rdata))
00461 {
00462 warning("Micro failed to respond to set mode request");
00463 }
00464 usleep(1000 * 1000);
00465 }
00466 }
00467 tries++;
00468 }
00469 fatal("Failed to enter %s mode.", boot ? "app" : "boot");
00470 }
00471
00472 int micro_get_mode()
00473 {
00474 uint8_t rcmd, rlen, rdata[16];
00475 if (ionkbd_send_request(IONKBD_REQ_GET_STATUS, 0, NULL,
00476 &rcmd, &rlen, rdata))
00477 {
00478 fatal("Micro failed to respond to status request");
00479 }
00480 else
00481 {
00482 if (rcmd!=IONKBD_RESP_STATUS)
00483 {
00484 fatal("Invalid response from status request: 0x%02X", rcmd);
00485 }
00486 else
00487 {
00488 return (rdata[0]&1);
00489 }
00490 }
00491 return MODE_BOOT;
00492 }
00493
00494 void micro_get_devicetype(uint8_t *type)
00495 {
00496 uint8_t rcmd, rlen, rdata[16];
00497 if (ionkbd_send_request(IONKBD_REQ_GET_DEVICETYPE, 0, NULL,
00498 &rcmd, &rlen, rdata))
00499 {
00500 fatal("Micro failed to respond to devicetype request");
00501 }
00502 if (rcmd!=IONKBD_RESP_DEVICETYPE)
00503 {
00504 if (rcmd!=IONKBD_RESP_STATUS)
00505 {
00506 fatal("Invalid devicetype response");
00507 }
00508 warning("Received status instead of devicetype respons. Assuming DR1000-series");
00509 rdata[0] = 0;
00510 }
00511 *type = rdata[0];
00512 }
00513
00514 int gasgauge_get_versions(uint16_t *firmware, uint16_t *hardware)
00515 {
00516 uint8_t rcmd, rlen, rdata[16];
00517 int i;
00518 *firmware = 0x0;
00519 *hardware = 0x0;
00520 for (i=0;i<3;i++)
00521 {
00522 if (!ionkbd_send_request(IONKBD_REQ_GET_GG_VERSION, 0, NULL,
00523 &rcmd, &rlen, rdata))
00524 {
00525 break;
00526 }
00527 warning("Retrying gas gauge version request");
00528 }
00529 if (i==3)
00530 {
00531 warning("Micro failed to respond to gasgauge version request");
00532 return 1;
00533 }
00534 if ((rcmd != IONKBD_RESP_GG_VERSION) || (rlen != 4))
00535 {
00536 warning("Invalid response to gasgauge version request: %d (%d)",rcmd, rlen);
00537 return 1;
00538 }
00539 *firmware = (rdata[0]*100)|rdata[1];
00540 *hardware = (rdata[2]*100)|rdata[3];
00541 return 0;
00542 }
00543
00544 int gasgauge_do_command_base(uint8_t *data, uint8_t len)
00545 {
00546 uint8_t rcmd, rlen, rdata[16];
00547
00548 if (data[0] > GASGAUGE_STOP)
00549 {
00550 warning("Invalid gasgauge command %d\n", data[0]);
00551 return 1;
00552 }
00553
00554
00555
00556
00557
00558
00559 if (ionkbd_send_request(IONKBD_REQ_FLASH_GASGAUGE, len, data,
00560 &rcmd, &rlen, rdata))
00561 {
00562 warning("Micro failed to respond to gasgauge request %d", data[0]);
00563 return 1;
00564 }
00565 if ((rcmd == IONKBD_RESP_GASGAUGE) && (rlen > 0) &&
00566 (rdata[0] == data[0]))
00567 {
00568 if (rdata[1] == 0)
00569 {
00570 warning("Gasgauge request %d failed after %d tries",
00571 data[0], rdata[2]);
00572 return 1;
00573 }
00574 else
00575 {
00576
00577
00578 return 0;
00579 }
00580 }
00581 else
00582 {
00583 warning("Invalid respond to gasgauge request %d", data[0]);
00584 return 1;
00585 }
00586 return 0;
00587 }
00588
00589 int gasgauge_do_command(uint8_t command)
00590 {
00591 return gasgauge_do_command_base(&command, 1);
00592 }
00593
00594 int gasgauge_do_setup_row(uint8_t start, uint8_t *data, uint8_t len)
00595 {
00596 uint8_t buf[16];
00597 int i;
00598 buf[0] = GASGAUGE_SETUP_ROW;
00599 buf[1] = start;
00600 for (i=0;i<len;i++)
00601 buf[2+i] = data[i];
00602 return gasgauge_do_command_base(buf, 2+len);
00603 }
00604
00605 int gasgauge_do_program_row(uint8_t row)
00606 {
00607 uint8_t buf[2];
00608 buf[0] = GASGAUGE_PROGRAM_ROW;
00609 buf[1] = row;
00610 return gasgauge_do_command_base(buf, 2);
00611 }
00612
00613 int gasgauge_flash(char *filename)
00614 {
00615 uint8_t image[1024];
00616 uint8_t *imgptr;
00617 int row, i;
00618 int attempts=0;
00619 FILE *f;
00620
00621 read_timeout = 1000;
00622
00623 printf("Loading gasgauge firmware\n");
00624
00625 f = fopen(filename, "rb");
00626 if (!f)
00627 {
00628 warning("Couldn't open firmware file");
00629 return 1;
00630 }
00631
00632 fseek(f, 0, SEEK_END);
00633 if (ftell(f)!=1025)
00634 {
00635 warning("Invalid firmware size");
00636 return 1;
00637 }
00638 fseek(f, 0, SEEK_SET);
00639
00640 fread(image, 1024, 1, f);
00641 fclose(f);
00642
00643 printf("Initialising gasgauge programming\n");
00644
00645 for (i=0;i<3;i++)
00646 {
00647 if (!gasgauge_do_command(GASGAUGE_INIT))
00648 break;
00649 warning("Retrying gas gauge init");
00650 }
00651 if (i==3)
00652 {
00653 warning("Failed to initialise gas gauge programming");
00654 return 1;
00655 }
00656 printf("starting\n");
00657
00658 for (i=0;i<3;i++)
00659 {
00660 if (!gasgauge_do_command(GASGAUGE_START))
00661 break;
00662 warning("Retrying gas gauge start");
00663 }
00664 if (i==3)
00665 {
00666 warning("Failed to start gas gauge programming");
00667 return 1;
00668 }
00669 printf("saving settings\n");
00670
00671 while (gasgauge_do_command(GASGAUGE_SAVE_SETTINGS))
00672 {
00673 warning("Failed to save gasgauge settings, retrying");
00674 }
00675
00676 while (attempts<20)
00677 {
00678 imgptr = image;
00679 printf("Starting flash loop (attempt %d)\n",attempts+1);
00680 printf("Erasing gasgauge flash\n");
00681
00682 if (gasgauge_do_command(GASGAUGE_ERASE))
00683 {
00684 warning("Failed to erase gasgauge flash, restarting");
00685 continue;
00686 }
00687
00688 for (row=0;row<32;row++)
00689 {
00690
00691 printf("Setting up row %2d\n",row);
00692 for (i=0;i<4;i++)
00693 {
00694 gasgauge_do_setup_row(i*8, imgptr, 8);
00695 imgptr += 8;
00696 }
00697
00698
00699 printf("Programming row %2d\n", row);
00700 if (gasgauge_do_program_row(row))
00701 {
00702 warning("Failed programming, restarting");
00703 break;
00704 }
00705 }
00706
00707 if (row==32)
00708 {
00709 printf("Restoring settings\n");
00710
00711 if (!gasgauge_do_command(GASGAUGE_RESTORE_SETTINGS))
00712 {
00713 printf("All OK, finishing\n");
00714 break;
00715 }
00716 }
00717 attempts++;
00718 }
00719
00720 if (attempts==20)
00721 {
00722 warning("Failed to program gasgauge");
00723 return 1;
00724 }
00725
00726 printf("Stopping\n");
00727
00728 if (gasgauge_do_command(GASGAUGE_STOP))
00729 {
00730 warning("Failed to stop gas gauge programming");
00731 return 1;
00732 }
00733
00734 return 0;
00735 }
00736
00737 void port_open(char* name, int flags, int speed)
00738 {
00739 struct termios t;
00740
00741 if ((serial_fd = open(name, O_RDWR | O_NOCTTY)) < 0)
00742 {
00743 fatal("Can't open device %s", name);
00744 }
00745
00746 tcgetattr(serial_fd, &t);
00747
00748 t.c_cflag = flags | CREAD | HUPCL | CLOCAL;
00749 t.c_iflag = IGNBRK | IGNPAR;
00750 t.c_oflag = 0;
00751 t.c_lflag = 0;
00752 t.c_cc[VMIN ] = 1;
00753 t.c_cc[VTIME] = 0;
00754
00755 cfsetispeed(&t, speed);
00756 cfsetospeed(&t, speed);
00757 tcflush(serial_fd, TCIFLUSH);
00758 tcsetattr(serial_fd, TCSANOW, &t);
00759 }
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 static int serial_write(uint8_t c)
00771 {
00772 write(serial_fd, &c, 1);
00773 return 0;
00774 }
00775
00776
00777
00778
00779
00780 static int serial_readTimeout(uint8_t *c, int timeout)
00781 {
00782 struct timeval tv;
00783 fd_set set;
00784
00785 tv.tv_sec = 0;
00786 tv.tv_usec = timeout * 1000;
00787
00788 FD_ZERO(&set);
00789 FD_SET(serial_fd, &set);
00790
00791 if (!select(serial_fd+1, &set, NULL, NULL, &tv)) return -1;
00792 if (read(serial_fd, c, 1) != 1) return -1;
00793
00794 return 0;
00795 }
00796
00797
00798
00799
00800
00801 static uint8_t serial_read(uint8_t *c)
00802 {
00803 if (serial_readTimeout(c, read_timeout))
00804 {
00805 warning("Timeout waiting for response");
00806 return 1;
00807 }
00808 return 0;
00809 }
00810
00811
00812
00813
00814
00815 static uint8_t serial_readEncoded(uint8_t *c)
00816 {
00817 if (serial_read(c)) return 1;
00818 if (*c==IONKBD_ESC)
00819 {
00820 if (serial_read(c)) return 1;
00821 switch (*c)
00822 {
00823 case IONKBD_ESC_START:
00824 *c = IONKBD_START;
00825 break;
00826 case IONKBD_ESC_ESC:
00827 *c = IONKBD_ESC;
00828 break;
00829 default:
00830 return 1;
00831 }
00832 }
00833 return 0;
00834 }
00835
00836
00837
00838
00839
00840 static void encode_send_byte(uint8_t c)
00841 {
00842 if (c==IONKBD_START)
00843 {
00844 serial_write(IONKBD_ESC);
00845 serial_write(IONKBD_ESC_START);
00846 }
00847 else if (c==IONKBD_ESC)
00848 {
00849 serial_write(IONKBD_ESC);
00850 serial_write(IONKBD_ESC_ESC);
00851 }
00852 else
00853 {
00854 serial_write(c);
00855 }
00856 }