BIN 轉化為 S19 格式及 S19 格式解析
阿新 • • 發佈:2019-02-17
bin2srec.c
/* BIN2SREC - Convert binary to Motorola S-Record file Copyright (C) 1998-2012 Anthony Goffart This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stdio.h> #include <string.h> #include <stdint.h> #include "common.h" #define HEADER1 "\nBIN2SREC " SREC_VER " - Convert binary to Motorola S-Record file.\n" char *filename; FILE *infile; uint32_t addr_offset = 0; uint32_t begin_addr; uint32_t end_addr; int addr_bytes = 2; int do_headers = TRUE; int verbose = TRUE; int line_length = 32; /***************************************************************************/ void syntax(void) { fprintf(stderr, HEADER1); fprintf(stderr, HEADER2); fprintf(stderr, "Syntax: BIN2SREC <options> INFILE > OUTFILE\n\n"); fprintf(stderr, "-help Show this help.\n"); fprintf(stderr, "-b <begin> Address to begin at in binary file (hex), default = 0.\n"); fprintf(stderr, "-e <end> Address to end at in binary file (hex), default = end of file.\n"); fprintf(stderr, "-o <offset> Generated address offset (hex), default = begin address.\n"); fprintf(stderr, "-a <addrsize> Number of bytes used for address (2-4),\n"); fprintf(stderr, " default = minimum needed for maximum address.\n"); fprintf(stderr, "-l <linelength> Number of bytes per line (8-32), default = 32.\n"); fprintf(stderr, "-s Suppress header and footer records.\n"); fprintf(stderr, "-q Quiet mode - no output except S-Record.\n"); } /***************************************************************************/ void process(void) { int i; uint32_t max_addr, address; int byte_count, this_line; unsigned char checksum; uint32_t c; int record_count = 0; unsigned char buf[32]; max_addr = addr_offset + (end_addr - begin_addr); fseek(infile, begin_addr, SEEK_SET); if ((max_addr > 0xffffl) && (addr_bytes < 3)) addr_bytes = 3; if ((max_addr > 0xffffffl) && (addr_bytes < 4)) addr_bytes = 4; if (verbose) { fprintf(stderr, HEADER1); fprintf(stderr, HEADER2); fprintf(stderr, "Input binary file: %s\n", filename); fprintf(stderr, "Begin address = %Xh\n", begin_addr); fprintf(stderr, "End address = %Xh\n", end_addr); fprintf(stderr, "Address offset = %Xh\n", addr_offset); fprintf(stderr, "Maximum address = %Xh\n", max_addr); fprintf(stderr, "Address bytes = %d\n", addr_bytes); } if (do_headers) printf("S00600004844521B\n"); /* Header record */ address = addr_offset; for (;;) { if (verbose) fprintf(stderr, "Processing %08Xh\r", address); this_line = min(line_length, (max_addr - address) + 1); byte_count = (addr_bytes + this_line + 1); printf("S%d%02X", addr_bytes - 1, byte_count); checksum = byte_count; for (i = addr_bytes - 1; i >= 0; i--) { c = (address >> (i << 3)) & 0xff; printf("%02X", c); checksum += c; } fread(buf, 1, this_line, infile); for (i = 0; i < this_line; i++) { printf("%02X", buf[i]); checksum += buf[i]; } printf("%02X\n", 255 - checksum); record_count++; /* check before adding to allow for finishing at 0xffffffff */ if ((address - 1 + line_length) >= max_addr) break; address += line_length; } if (do_headers) { if (record_count > 0xffff) { checksum = 4 + (record_count & 0xff) + ((record_count >> 8) & 0xff) + ((record_count >> 16) & 0xff); printf("S604%06X%02X\n", record_count, 255 - checksum); } else { checksum = 3 + (record_count & 0xff) + ((record_count >> 8) & 0xff); printf("S503%04X%02X\n", record_count, 255 - checksum); } byte_count = (addr_bytes + 1); printf("S%d%02X", 11 - addr_bytes, byte_count); checksum = byte_count; for (i = addr_bytes - 1; i >= 0; i--) { c = (addr_offset >> (i << 3)) & 0xff; printf("%02X", c); checksum += c; } printf("%02X\n", 255 - checksum); } if (verbose) fprintf(stderr, "Processing complete \n"); } /***************************************************************************/ int main(int argc, char *argv[]) { int i; uint32_t size; int offset_specified = FALSE; int end_specified = FALSE; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-o")) { addr_offset = str_to_uint32(argv[++i]); offset_specified = TRUE; continue; } else if (!strcmp(argv[i], "-b")) { begin_addr = str_to_uint32(argv[++i]); continue; } else if (!strcmp(argv[i], "-e")) { end_addr = str_to_uint32(argv[++i]); end_specified = TRUE; continue; } else if (!strcmp(argv[i], "-a")) { sscanf(argv[++i], "%d", &addr_bytes); addr_bytes = max(2, addr_bytes); addr_bytes = min(4, addr_bytes); continue; } else if (!strcmp(argv[i], "-l")) { sscanf(argv[++i], "%d", &line_length); line_length = max(8, line_length); line_length = min(32, line_length); continue; } else if (!strcmp(argv[i], "-s")) { do_headers = FALSE; continue; } else if (!strcmp(argv[i], "-q")) { verbose = FALSE; continue; } else if (!strncmp(argv[i], "-h", 2)) /* -h or -help */ { syntax(); return(0); } else { filename = argv[i]; } } if (filename == NULL) { syntax(); fprintf(stderr, "\n** No input filename specified\n"); return(1); } if ((infile = fopen(filename, "rb")) != NULL) { size = file_size(infile) - 1; if (end_specified) end_addr = min(size, end_addr); else end_addr = size; if (begin_addr > size) { fprintf(stderr, "Begin address %Xh is greater than file size %Xh\n", begin_addr, size); return(3); } if (end_addr < begin_addr) { fprintf(stderr, "End address %Xh is less than begin address %Xh\n", end_addr, begin_addr); return(3); } if (!offset_specified) addr_offset = begin_addr; process(); fclose(infile); return(0); } else { fprintf(stderr, "Input file %s not found\n", filename); return(2); } } /***************************************************************************/
common.c
/* common.c - Common functions for both srec2bin and bin2srec Copyright (C) 1998-2012 Anthony Goffart This file is part of SREC2BIN and BIN2SREC BIN2SREC and SREC2BIN are free software: you can redistribute them and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. BIN2SREC and SREC2BIN are distributed in the hope that they will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BIN2SREC and SREC2BIN. If not, see <http://www.gnu.org/licenses/>. */ #include <sys/stat.h> #include "common.h" /***************************************************************************/ unsigned int char_to_uint(char c) { int res = 0; if (c >= '0' && c <= '9') res = (c - '0'); else if (c >= 'A' && c <= 'F') res = (c - 'A' + 10); else if (c >= 'a' && c <= 'f') res = (c - 'a' + 10); return(res); } /***************************************************************************/ uint32_t str_to_uint32(char *s) { int i; char c; uint32_t res = 0; for (i = 0; (i < 8) && (s[i] != '\0'); i++) { c = s[i]; res <<= 4; res += char_to_uint(c); } return(res); } /***************************************************************************/ uint32_t file_size(FILE *f) { struct stat info; if (!fstat(fileno(f), &info)) return((uint32_t)info.st_size); else return(0); } /***************************************************************************/
common.h
#ifndef COMMON_H #define COMMON_H #define SREC_VER "1.43" #define HEADER2 "Copyright (c) 2000-2014 Ant Goffart - http://www.s-record.com/\n\n" #include <stdio.h> #include <stdint.h> #ifndef FALSE #define FALSE (0) #endif #ifndef TRUE #define TRUE (~FALSE) #endif #define max(a,b) (((a)>(b))?(a):(b)) #define min(a,b) (((a)<(b))?(a):(b)) unsigned int char_to_uint(char s); uint32_t str_to_uint32(char *s); uint32_t file_size(FILE *f); #endif
Motorola S-records 16進位制檔案格式是嵌入式中除intel hex之外很常見的格式,下面是它的格式:
+-------------------//------------------//-----------------------+
| type(hex1) | count(hex 1) | address | data | checksum(從count累加到checksum,總和為0xFF) |
+-------------------//------------------//-----------------------+
S0 :標識記錄,地址域長度為2個位元組,並用0000填充,資料區記錄了一些模組名稱和版本之類的資訊
S1 :資料記錄,地址域長度為2個位元組,資料區域為資料內容。
S2 :資料記錄,地址域長度為3個位元組,資料區域為資料內容。
S3 :資料記錄,地址域長度為4個位元組,資料區域為資料內容。
S5 :統計記錄,地址域長度為2個位元組,內容是之前資料記錄(S1,S2,S3)的個數,資料區域空。
S7 : 執行記錄,地址域長度為4個位元組,內容是程式啟動的地址,資料域空。
S8 :執行記錄,地址域長度為3個位元組,內容是程式啟動的地址,資料域空。
S9 :執行記錄,地址域長度為2個位元組,內容是程式啟動的地址,資料域空。
下面是一個例子,大家看看:
S02B0000433A5C446F63756D656E747320616E642053657474696E67735C7A6F75642E4143434F554E54535C7D
S208010000FFFFFFFFFA
S30800020000000000F5
S5030002FA
S9030000FC 第一行:沒什麼,開個頭而已。
第二行:地址0x10000有4個0xFF
第三行:地址0x20000有3個0x00
第四行:標明之前有兩條資料記錄
第五行:程式從0x0000地址開始執行 關於checksum的演算法和intel hex不太一樣,
checksum = 0xFF - (從count段開始所有位元組的總和)。
更快學習的動力來源於適當的壓力。