Update
[jelmer/at89prog.git] / prog1.c
1 #include <stdio.h>
2 #include <popt.h>
3 #include <signal.h>
4 #include <sys/types.h>
5 #include <string.h>
6 #include <sys/io.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include "pins.h"
10 #include "at89ser.h"
11
12 #define VERSION         "0.5.1"
13
14 void usage(poptContext pc)
15 {
16         poptPrintHelp(pc, stderr, 0);
17         fprintf(stderr, "\nAvailable commands: \n"
18                         "\terase\n"
19                         "\treset\n"
20                         "\tlock <level>\n"
21                         "\twritefile [file] ...\n"
22                         "\treadfile <len> [file] ...\n"
23                         "\twritebyte <address> <byte>\n"
24                         "\treadbyte <address>\n"
25                         "\tversion\n");
26 }
27
28 void quit(int s)
29 {
30         deactivate();
31         fprintf(stderr, "Received signal, exiting...\n");
32         exit(0);
33 }
34
35 void writechar(char datamem, char do_verify, int address, int byte)
36 {
37         int d;
38         if(datamem)writedata(address, byte);
39         else writecode(address, byte);
40
41         if(do_verify) {
42                 if(datamem)d = readdata(address);
43                 else d = readcode(address);
44
45                 if(byte != d) {
46                         fprintf(stderr, "Error verifying byte at offset 0x%x\n", address);
47                         deactivate();
48                         exit(1);
49                 }
50         }
51 }
52
53 int writebin(FILE *fd, char do_verify, char datamem)
54 {
55         int i = 0;
56         while(!feof(fd)) 
57         {
58                 writechar(datamem, do_verify, i, fgetc(fd));
59                 i++;
60                 fputc('.', stderr);
61         }
62         fputc('\n', stderr);
63         return 0;
64 }
65
66 int writehex(FILE *fd, char do_verify, char datamem)
67 {
68         int length; long address; int type;
69         int errors = 0;
70         int checksum1, checksum2;
71         int i, j, byte;
72         i = 0;
73         while(!feof(fd)) 
74         {
75                 checksum1 = 0;
76                 i++;
77                 if(fscanf(fd, ":%2x%4lx%2x", &length, &address, &type) < 3) {
78                         fprintf(stderr, "Error reading intel hex file, line %d\n", i);
79                         deactivate();
80                         exit(1);
81                 }
82
83                 checksum1+=length;
84                 checksum1+=type;
85                 checksum1+=address & 0xFF;
86                 checksum1+=address & 0xFF00;
87
88                 if(type == 1) break;
89
90                 if(type == 2) continue;
91                 
92                 for(j = 0; j < length; j++) {
93                         if(fscanf(fd, "%2x", &byte) < 1) {
94                                 fprintf(stderr, "Error reading byte %d in intel hex file, line %d\n", j, i);
95                                 deactivate();
96                                 exit(1);
97                         }
98
99                         checksum1+=byte;
100                         writechar(datamem,do_verify,address+j,byte);
101                 }
102
103                 if(fscanf(fd, "%2x", &checksum2) < 1) {
104                         fprintf(stderr, "Error reading checksum in intel hex file, line %d\n", i);
105                         deactivate();
106                         exit(1);
107                 }
108
109                 if((0x100 - (checksum1 & 0xFF)) != checksum2) {
110                         fprintf(stderr, "Warning: checksums do NOT match in intel hex file, line %d\n"
111                         "(%x != %x)\n" 
112                                         "File may be corrupt\n", i, 0x100 - (checksum1 & 0xFF), checksum2);
113                         errors++;
114                 }
115
116                 while(!feof(fd)) { 
117                         byte = getc(fd); 
118                         if(byte != '\n' && byte != '\r') {
119                                 ungetc(byte, fd);
120                                 break; 
121                         }
122                 }
123
124                 fputc('.', stderr);
125         }
126         fputc('\n', stderr);
127         return errors;
128 }
129
130
131 int main(int argc, const char **argv) 
132 {
133         char datamem = 0, codemem = 0, verbose = 0, do_verify = 0, ignore_chk = 0;
134         FILE *fd;
135         int newserport = -1;
136         char *format = "auto";
137         char *rcfile = NULL;
138         char c, print_usage = 1;
139         struct poptOption long_options[] = {
140                 POPT_AUTOHELP
141                 { "data-memory", 'd', POPT_ARG_VAL, &datamem, 0, "Write specified file to data memory" },
142                 { "code-memory", 'c', POPT_ARG_VAL, &codemem, 0, "Write specified file to code memory (default)" },
143                 { "format", 'f', POPT_ARG_STRING, &format, 0, "File format (auto,hex,bin)" },
144                 { "ignore-chk", 'i', POPT_ARG_VAL, &ignore_chk, 0, "Don't wait for CHK to confirm RST" },
145                 { "verify", 0, POPT_ARG_VAL, &do_verify, 0, "Verify written bytes" }, 
146                 { "port", 'p', POPT_ARG_STRING, NULL, 'p', "Address of serial port to use [3f8]" },
147                 { "rcfile", 'r', POPT_ARG_STRING, &rcfile, 0, "Use rc file from specified location" },
148                 { "verbose", 'v', POPT_ARG_VAL, &verbose, 0, "Be verbose" },
149                 POPT_TABLEEND
150         };
151
152         poptContext pc;
153
154         pc = poptGetContext(NULL, argc, argv, long_options, POPT_CONTEXT_KEEP_FIRST);
155         poptSetOtherOptionHelp(pc, "command [file-to-write]");
156
157         while ((c = poptGetNextOpt(pc)) != -1) {
158                 switch(c) {
159                         case 'p': newserport = strtol(poptGetOptArg(pc), NULL, 16); break;
160                                 }
161         }
162
163         if(!rcfile) { 
164                 rcfile = malloc(strlen(getenv("HOME")) + 20);
165                 snprintf(rcfile, strlen(getenv("HOME")) + 20, "%s/.at89progrc", getenv("HOME")); 
166         }
167         
168         if(rcfile) {
169                 if(readrcfile(rcfile) != 0) return 1;
170         }
171
172         if(newserport != -1)serport = newserport;
173
174         if(ioperm(serport, 7, 1) == -1) 
175         {
176                 perror("ioperm");
177                 fprintf(stderr, "Run at89prog with IO port access\n");
178                 return 1;
179         }
180
181         if(ioperm(0x80, 1, 1) == -1) 
182         {
183                 perror("ioperm");
184                 return 1;
185         }
186
187         signal(SIGINT, quit);
188         signal(SIGSEGV, quit);
189
190         poptGetArg(pc); /* drop argv[0] */
191
192         if(!poptPeekArg(pc)) 
193         {
194                 usage(pc);
195                 return 0;
196         }
197
198         if(!activate() && !ignore_chk)
199         {
200                 fprintf(stderr, "RST set, but CHK is low\n");
201                 return 1;
202         }
203         
204         if(!strcmp(poptPeekArg(pc), "reset"))
205         { 
206                 print_usage = 0;
207                 deactivate(); 
208                 if(verbose) fprintf(stderr, "Microcontroller has been reset.\n");
209         } else if(!strcmp(poptPeekArg(pc), "erase"))
210         {
211                 print_usage = 0;
212                 programming();
213                 erase();
214                 if(verbose) fprintf(stderr, "Microcontroller memory has been erased.\n");
215         } else if(!strcmp(poptPeekArg(pc), "lock"))
216         {
217                 int lock_level;
218                 poptGetArg(pc);
219                 lock_level = atoi(poptGetArg(pc));
220                 print_usage = 0;
221                 programming();
222                 lock(lock_level);
223                 
224                 if(verbose) fprintf(stderr, "Locked at level %d\n", lock_level);
225         } else if(!strcmp(poptPeekArg(pc), "writefile"))
226         {
227                 int errors;
228                 poptGetArg(pc);
229                 programming();
230                 while(poptPeekArg(pc)) {
231                         int firstchar;
232                         const char *filename = poptGetArg(pc);
233                         
234                         if(!strcmp(filename, "-")) fd = stdin;
235                         else { 
236                                 fd = fopen(filename, "r");
237                                 if(!fd) {
238                                         fprintf(stderr, "Unable to open file %s, ignoring.\n", filename);
239                                         continue;
240                                 }
241                         }
242
243                         firstchar = getc(fd);
244                         ungetc(firstchar, fd);
245
246                         if(!strcmp(format, "hex") || (!strcmp(format, "auto") && firstchar == ':'))errors = writehex(fd, do_verify, datamem);
247                         else if(!strcmp(format, "auto") || !strcmp(format, "bin"))errors = writebin(fd, do_verify, datamem);
248                         else {
249                                 fprintf(stderr, "Unknown format %s, ignoring file\n", format);
250                                 fclose(fd);
251                                 continue;
252                         }
253
254                         if(!errors)fprintf(stderr, "File %s programmed correctly\n", filename);
255                         else fprintf(stderr, "File %s programmed with %d errors\n", filename, errors);
256                         fclose(fd);
257                 }
258         } else if(!strcmp(poptPeekArg(pc), "readfile")) {
259                 int len, i;
260                 programming();
261                 poptGetArg(pc);
262
263                 if(!poptPeekArg(pc)) {
264                         fprintf(stderr, "readfile needs at least one argument (number of bytes to read\n");
265                         deactivate();
266                         return 1;
267                 }
268
269                 len = atol(poptGetArg(pc));
270                 
271                 if(!poptPeekArg(pc)) fd = stdout;
272                 else {
273                         fd = fopen(poptGetArg(pc), "w+");
274                         if(!fd) {
275                                 perror("fopen");
276                                 deactivate();
277                                 return 1;
278                         }
279                 }
280
281                 if(!strcmp(format, "bin"))fprintf(stderr, "Warning: writing in binary mode\n");
282
283                 for(i = 0; i < len; i++) {
284                         if(datamem)fputc(readdata(i), fd);
285                         else fputc(readcode(i), fd);
286                         fputc('.', stderr);
287                 }
288
289                 fputc('\n', stderr);
290                         
291                 if(verbose)fprintf(stderr, "%d bytes read\n", len);
292                 fclose(fd);
293         } else if(!strcmp(poptPeekArg(pc), "writebyte")) {
294                 int address, byte;
295                 poptGetArg(pc);
296                 programming();
297                 if(!poptPeekArg(pc)) {
298                         fprintf(stderr, "writebyte requires 2 arguments\n");
299                         deactivate();
300                         return 1;
301                 }
302                 address = strtol(poptGetArg(pc), NULL, 16);
303
304                 if(!poptPeekArg(pc)) {
305                         fprintf(stderr, "writebyte requires 2 arguments\n");
306                         deactivate();
307                         return 1;
308                 }
309                 byte = strtol(poptGetArg(pc), NULL, 16);
310
311                 writechar(datamem, do_verify, address, byte);
312                 if(verbose)fprintf(stderr, "%x written to %x\n", byte, address);
313         } else if(!strcmp(poptPeekArg(pc), "readbyte")) {
314                 int address;
315                 poptGetArg(pc);
316                 programming();
317                 if(!poptPeekArg(pc)) {
318                         fprintf(stderr, "writebyte requires 2 arguments\n");
319                         deactivate();
320                         return 1;
321                 }
322                 address = strtol(poptGetArg(pc), NULL, 16);
323
324                 if(datamem) printf("%x\n", readdata(address));
325                 else printf("%x\n", readcode(address));
326         } else if(!strcmp(poptPeekArg(pc), "version")) {
327                   fprintf(stderr, "at89prog - a AT89S8252 programmer over the serial port\n");
328                   fprintf(stderr, " Version "VERSION"\n");
329                   fprintf(stderr, " (C) 2003 Jelmer Vernooij <jelmer@samba.org>\n");
330                   fprintf(stderr, "  Published under the GNU GPL\n");
331                   return 0;
332         } else {
333                 fprintf(stderr, "Unknown command %s\n", poptGetArg(pc));
334                 usage(pc);
335         }
336
337         deactivate();
338         poptFreeContext(pc);
339         
340         return 0;
341 }