FreeCalypso > hg > freecalypso-tools
view loadtools/flprogsrec.c @ 960:411d1cc14326
sms-pdu-decode family: prepare for SC address becoming optional
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 04 Aug 2023 23:09:12 +0000 |
parents | 185c9bf208d3 |
children |
line wrap: on
line source
/* * This module implements the flash program-srec and flash program-m0 commands: * programming flash using S-record files as the data source. */ #include <sys/types.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #include "flash.h" #include "discontig.h" #include "srecreader.h" extern int target_fd; extern struct flash_bank_info flash_bank_info[2]; extern uint32_t crc32_table[]; read_srec_img_for_flash(imgfile, is_m0, bank_size, reglistp, regcountp, totalp, tmpfilep) char *imgfile; uint32_t bank_size, *totalp; struct discontig_prog *reglistp; unsigned *regcountp; FILE **tmpfilep; { struct srecreader srr; struct discontig_prog *regp; unsigned regcount; uint32_t total_len; char tmpfilename[] = "/tmp/fc-loadtoolXXXXXX"; int rc, tmpfd, i, c; FILE *tmpfile; printf("Reading S-record image from %s\n", imgfile); srr.filename = imgfile; rc = open_srec_file(&srr); if (rc < 0) return(rc); tmpfd = mkstemp(tmpfilename); if (tmpfd < 0) { fprintf(stderr, "unable to get temp file via mkstemp()\n"); fclose(srr.openfile); return(-1); } unlink(tmpfilename); tmpfile = fdopen(tmpfd, "w+"); if (!tmpfile) { perror("fdopen"); close(tmpfd); fclose(srr.openfile); return(-1); } regp = reglistp; regcount = 0; total_len = 0; for (;;) { if (read_s_record(&srr) < 0) { /* error msg already printed */ fclose(srr.openfile); fclose(tmpfile); return(-1); } if (srr.record_type == '0') { if (srr.lineno == 1) continue; fprintf(stderr, "error: S0 record found in line %d of %s (expected in line 1 only)\n", srr.lineno, srr.filename); fclose(srr.openfile); fclose(tmpfile); return(-1); } else if (srr.record_type == '7') break; else if (srr.record_type != '3') { fprintf(stderr, "error: unsupported S%c record type in line %d of %s\n", srr.record_type, srr.lineno, srr.filename); fclose(srr.openfile); fclose(tmpfile); return(-1); } /* must be S3 */ if (s3s7_get_addr_data(&srr) < 0) { /* error msg already printed */ fclose(srr.openfile); fclose(tmpfile); return(-1); } if (srr.datalen < 1) { fprintf(stderr, "%s line %d: S3 record of zero data length ignored\n", srr.filename, srr.lineno); continue; } if (srr.addr & 1 || srr.datalen & 1) { fprintf(stderr, "%s line %d: violates word alignment requirement\n", srr.filename, srr.lineno); fclose(srr.openfile); fclose(tmpfile); return(-1); } srr.addr &= bank_size - 1; if (srr.addr + srr.datalen > bank_size) { fprintf(stderr, "%s line %d: goes past the end of the flash bank\n", srr.filename, srr.lineno); fclose(srr.openfile); fclose(tmpfile); return(-1); } /* is this the first record of the first region? */ if (!regcount) { regp->start = srr.addr; regp->end = srr.addr; regp->crc = 0xFFFFFFFF; regcount = 1; } if (srr.addr < regp->end) { fprintf(stderr, "%s line %d: address going backwards\n", srr.filename, srr.lineno); fclose(srr.openfile); fclose(tmpfile); return(-1); } if (srr.addr != regp->end) { if (regcount >= MAX_SREC_REGIONS) { fprintf(stderr, "error: %s has too many discontiguous regions\n", imgfile); fclose(srr.openfile); fclose(tmpfile); return(-1); } regp++; regcount++; regp->start = srr.addr; regp->end = srr.addr; regp->crc = 0xFFFFFFFF; } /* take in the payload */ if (is_m0) { for (i = 0; i < srr.datalen; i += 2) { c = srr.record[i+6]; regp->crc = crc32_table[regp->crc & 0xFF ^ c] ^ (regp->crc >> 8); putc(c, tmpfile); c = srr.record[i+5]; regp->crc = crc32_table[regp->crc & 0xFF ^ c] ^ (regp->crc >> 8); putc(c, tmpfile); } } else { for (i = 0; i < srr.datalen; i++) { c = srr.record[i+5]; regp->crc = crc32_table[regp->crc & 0xFF ^ c] ^ (regp->crc >> 8); putc(c, tmpfile); } } regp->end += srr.datalen; total_len += srr.datalen; } /* got S7 */ fclose(srr.openfile); if (!regcount) { fprintf(stderr, "%s line %d: S7 without any preceding S3 data records\n", srr.filename, srr.lineno); fclose(tmpfile); return(-1); } /* good read */ if (regcount == 1) printf("Got %lu (0x%lx) bytes in one contiguous region\n", (u_long) total_len, (u_long) total_len); else printf("Got %lu (0x%lx) bytes in %u discontiguous regions\n", (u_long) total_len, (u_long) total_len, regcount); *regcountp = regcount; *totalp = total_len; *tmpfilep = tmpfile; return(0); } flashcmd_progsrec_gen(bank, imgfile, is_m0, with_erase) char *imgfile; { struct flash_bank_info *bi; struct discontig_prog regions[MAX_SREC_REGIONS], *regp; unsigned nregions, reg; uint32_t total_len, bytesdone, addr, len; FILE *tmpfile; char *targv[3], shortarg[10]; u_char databuf[2048 + 7], ackbyte; int reclen, cc, rc; time_t initial_time, curtime, last_time; unsigned duration, mm, ss; u_long crc_from_target; if (flash_detect(bank, 0) < 0) return(-1); bi = flash_bank_info + bank; rc = read_srec_img_for_flash(imgfile, is_m0, bi->geom->total_size, regions, &nregions, &total_len, &tmpfile); if (rc < 0) return(rc); if (with_erase) { rc = erase_sectors_for_prog(bi, regions, nregions); if (rc < 0) { fclose(tmpfile); return(rc); } } sprintf(shortarg, "%lx", (u_long) bi->base_addr); targv[0] = bi->ops->loadagent_setbase_cmd; targv[1] = shortarg; targv[2] = 0; printf("Setting flash base address: %s %s\n", targv[0], targv[1]); tpinterf_make_cmd(targv); if (tpinterf_send_cmd() < 0) { fclose(tmpfile); return(-1); } rc = tpinterf_pass_output(1); if (rc) { fclose(tmpfile); return(rc); } if (bi->ops->prep_for_program(bi) < 0) { fclose(tmpfile); return(-1); } rewind(tmpfile); targv[0] = bi->ops->loadagent_binmode_cmd; targv[1] = 0; tpinterf_make_cmd(targv); if (tpinterf_send_cmd() < 0) { fclose(tmpfile); return(-1); } printf("Programming flash\n"); databuf[0] = 0x01; bytesdone = 0; last_time = 0; time(&initial_time); for (reg = 0, regp = regions; reg < nregions; reg++, regp++) { addr = regp->start; len = regp->end - addr; while (len) { if (len >= 2048) reclen = 2048; else reclen = len; cc = fread(databuf + 7, 1, reclen, tmpfile); if (cc != reclen) { fclose(tmpfile); fprintf(stderr, "error reading from temp file!\n"); /* don't leave loadagent in binary flash mode */ databuf[0] = 0x04; write(target_fd, databuf, 1); tpinterf_pass_output(1); return(-1); } /* binary flash write command to loadagent */ databuf[1] = addr >> 24; databuf[2] = addr >> 16; databuf[3] = addr >> 8; databuf[4] = addr; databuf[5] = reclen >> 8; databuf[6] = reclen; cc = write(target_fd, databuf, reclen + 7); if (cc != reclen + 7) { fclose(tmpfile); perror("binary write to target"); return(-1); } rc = collect_binblock_from_target(&ackbyte, 1, 8); if (rc) { fclose(tmpfile); return(rc); } if (ackbyte == 0x15) { /* NAK */ fclose(tmpfile); tpinterf_pass_output(1); return(-1); } if (ackbyte != 0x06) { /* ACK */ fclose(tmpfile); fprintf(stderr, "binary protocol error: bad ack 0x%02X\n", ackbyte); return(-1); } addr += reclen; len -= reclen; bytesdone += reclen; cc = bytesdone * 100 / total_len; time(&curtime); if (curtime != last_time || cc == 100) { printf("\r0x%lx bytes programmed (%i%%)", bytesdone, cc); fflush(stdout); } last_time = curtime; } } putchar('\n'); fclose(tmpfile); databuf[0] = 0x04; /* EOT */ write(target_fd, databuf, 1); rc = collect_binblock_from_target(&ackbyte, 1, 1); if (rc) return(rc); time(&last_time); if (ackbyte != '=') { fprintf(stderr, "error: \'=\' not received as expected\n"); return(-1); } duration = last_time - initial_time; mm = duration / 60; ss = duration - mm * 60; printf("Operation completed in %um%02us\n", mm, ss); /* reset flash to read mode */ if (bi->ops->reset_cmd(bi) < 0) return(-1); printf("Verifying CRC-32 of %u programmed region(s)\n", nregions); for (reg = 0, regp = regions; reg < nregions; reg++, regp++) { rc = crc32_on_target((u_long) (bi->base_addr + regp->start), (u_long) (regp->end - regp->start), &crc_from_target); if (rc < 0) return(rc); if (crc_from_target != regp->crc) { fprintf(stderr, "error: CRC mismatch!\n"); return(-1); } putchar('.'); fflush(stdout); } putchar('\n'); return(0); } flashcmd_program_srec(argc, argv, bank) char **argv; { if (argc != 3) { fprintf(stderr, "usage: %s %s image.srec\n", argv[0], argv[1]); return(-1); } return flashcmd_progsrec_gen(bank, argv[2], 0, argv[1][0] == 'e'); } flashcmd_program_m0(argc, argv, bank) char **argv; { if (argc != 3) { fprintf(stderr, "usage: %s %s image.m0\n", argv[0], argv[1]); return(-1); } return flashcmd_progsrec_gen(bank, argv[2], 1, argv[1][0] == 'e'); }