parsinf 05 records now too, still strabge bootloader returns to the go cmd!
[my-code/arm.git] / betty / lpcload.c
1 /*
2  * lpcload.c - load firmware into ram of lpc2220 via uart0
3  *
4  * author: hackbard@hackdaworld.org, rolf.anders@physik.uni-augsburg.de
5  *
6  * build: make
7  * usage: sudo ./lpcload -d /dev/ttyS0 -f firmware.hex [-v]
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <termios.h>
18
19 #define VERBOSE                 (1<<0)
20 #define FIRMWARE                (1<<1)
21
22 #define TXRX_TYPE_SYNC          0x00
23 #define TXRX_TYPE_CKSM          0x00
24 #define TXRX_TYPE_BAUD          0x01
25 #define TXRX_TYPE_CMD           0x02
26 #define TXRX_TYPE_DATA          0x03
27 #define TXRX_TYPE_GO            0x04
28
29 #define CMD_SUCCESS             "0\r\n"
30 #define INVALID_COMMAND         "1\r\n"
31 #define SRC_ADDR_ERROR          "2\r\n"
32 #define DST_ADDR_ERROR          "3\r\n"
33 #define SRC_ADDR_NOT_MAPPED     "4\r\n"
34 #define DST_ADDR_NOT_MAPPED     "5\r\n"
35 #define COUNT_ERROR             "6\r\n"
36 #define COMPARE_ERROR           "10\r\n"
37 #define BUSY                    "11\r\n"
38 #define PARAM_ERROR             "12\r\n"
39 #define ADDR_ERROR              "13\r\n"
40 #define ADDR_NOT_MAPPED         "14\r\n"
41 #define CMD_LOCKED              "15\r\n"
42 #define INVALID_CODE            "16\r\n"
43 #define INVALID_BAUD_RATE       "17\r\n"
44 #define INVALID_STOP_BIT        "18\r\n"
45
46 #define CRYSTFREQ               "10000"
47 #define RAMOFFSET               0x40000200
48
49 #define BUFSIZE                 128
50
51 typedef unsigned char u8;
52 typedef unsigned short u16;
53 typedef unsigned int u32;
54
55 typedef struct s_lpc {
56         int sfd;                /* serial fd */
57         char sdev[128];         /* seriel device */
58         int fwfd;               /* fimrware fd */
59         char fwfile[128];       /* firmware file */
60         u8 info;                /* info/mode */
61         char freq[8];           /* frequency */
62         u32 roff;               /* ram offset of uc */
63         u32 jaddr;              /* addr for the jump */
64 } t_lpc;
65
66 void usage(void) {
67
68         printf("possible argv:\n");
69         printf("  -d <serial device>\n");
70         printf("  -f <firmware>\n");
71         printf("  -c <crystal freq>\n");
72         printf("  -r <ram offset>\n");
73         printf("  -v\n");
74
75 }
76
77 int open_serial_device(t_lpc *lpc) {
78
79         struct termios term;
80
81         //memset(&term,0,sizeof(struct termios));
82
83         /* open serial device */
84
85         lpc->sfd=open(lpc->sdev,O_RDWR);
86         if(lpc->sfd<0) {
87                 perror("tts open");
88                 return lpc->sfd;
89         }
90
91         /* configure the serial device */
92
93         tcgetattr(lpc->sfd,&term);
94
95         // input/output baudrate
96
97         cfsetispeed(&term,B38400);
98         cfsetospeed(&term,B38400);
99
100         // control options -> 8n1
101
102         term.c_cflag&=~PARENB;  // no parity
103         term.c_cflag&=~CSTOPB;  // only 1 stop bit
104         term.c_cflag&=~CSIZE;   // no bit mask for data bits
105         term.c_cflag|=CS8;      // 8 data bits
106
107         // line options -> raw input
108         
109         term.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
110
111         // input options -> enable flow control
112         
113         //term.c_iflag&=~(IXON|IXOFF|IXANY|INLCR|ICRNL);
114         term.c_iflag&=~(INLCR|ICRNL|IXANY);
115         term.c_iflag|=(IXON|IXOFF);
116         
117         // output options
118
119         term.c_oflag=0;
120
121         // more control options -> timeout / flow control
122         
123         term.c_cc[VMIN]=0;
124         term.c_cc[VTIME]=10;    // 1 second timeout
125         term.c_cc[VSTART]=0x11;
126         term.c_cc[VSTOP]=0x13;
127
128         tcsetattr(lpc->sfd,TCSANOW,&term);
129
130         return lpc->sfd;
131 }
132
133 int open_firmware(t_lpc *lpc) {
134
135         /* open firmware file */
136
137         lpc->fwfd=open(lpc->fwfile,O_RDONLY);
138
139         if(lpc->fwfd<0)
140                 perror("fw open");
141
142         return lpc->fwfd;
143 }
144
145 int txrx(t_lpc *lpc,char *buf,int len,u8 type) {
146
147         int ret,cnt;
148         int i;
149
150         /* write */
151
152         if(lpc->info&VERBOSE)
153                 printf("  >> ");
154         cnt=0;
155         while(len) {
156                 ret=write(lpc->sfd,buf+cnt,len);
157                 if(ret<0) {
158                         perror("txrx write");
159                         return ret;
160                 }
161                 if(lpc->info&VERBOSE)
162                         for(i=0;i<ret;i++)
163                                 printf("%c",
164                                        ((buf[cnt+i]>0x19)&(buf[cnt+i]<0x7f))?
165                                        buf[cnt+i]:'.');
166                 len-=ret;
167                 cnt+=ret;
168         }
169         if(lpc->info&VERBOSE) {
170                 printf(" | ");
171                 for(i=0;i<cnt;i++)
172                         printf("%02x ",buf[i]);
173                 printf("| (%d)\n",cnt);
174         }
175
176         /* cut the echo if not of type auto baud */
177
178         if(type!=TXRX_TYPE_BAUD) {
179                 while(cnt) {
180                         ret=read(lpc->sfd,buf,cnt);
181                         if(ret<0) {
182                                 perror("txrx echo cut");
183                                 return ret;
184                         }
185                         cnt-=ret;
186                 }
187         }
188
189         /* return here if type is data */
190
191         if(type==TXRX_TYPE_DATA)
192                 return cnt;
193
194         /* read */
195
196         ret=read(lpc->sfd,buf,1);
197         if(ret<0) {
198                 perror("txrx read (first byte)");
199                 return ret;
200         }
201                 
202         switch(buf[0]) {
203                 case 'S':
204                         cnt=13;
205                         break;
206                 case 'O':
207                         cnt=3;
208                         break;
209                 case 'R':
210                         cnt=7;
211                         break;
212                 case '0':
213                         cnt=2;
214                         break;
215                 default:
216                         printf("txrx read: bad return byte '%02x'\n",buf[0]);
217                         break;
218         }
219
220         ret=1;
221         i=cnt;
222         while(i) {
223                 ret=read(lpc->sfd,buf+1+cnt-i,i);
224                 if(ret<0) {
225                         perror("txrx read (next bytes)");
226                         return ret;
227                 }
228                 i-=ret;
229         }
230         if(lpc->info&VERBOSE) {
231                 printf("  << ");
232                 for(i=0;i<cnt+1;i++)
233                         printf("%c",((buf[i]>0x19)&(buf[i]<0x7f))?
234                                     buf[i]:'.');
235                 printf(" | ");
236                 for(i=0;i<cnt+1;i++)
237                         printf("%02x ",buf[i]);
238                 printf("| (%d)\n",cnt+1);
239         }
240         buf[cnt+1]='\0';
241
242         /* return if type is go */
243
244         if(type==TXRX_TYPE_GO)
245                 return 0;
246
247         /* check/strip return code if type is cmd */
248
249         if(type==TXRX_TYPE_CMD) {
250                 ret=strlen(CMD_SUCCESS);
251                 if(!strncmp(buf,CMD_SUCCESS,ret)) {
252                         for(i=ret;i<cnt;i++)
253                                 buf[i-ret]=buf[i];
254                         buf[cnt]='\0';
255                 }
256                 else {
257                         printf("txrx bad return code!\n");
258                         return -1;
259                 }
260         }
261
262         return cnt;
263 }
264
265 int bl_init(t_lpc *lpc) {
266
267         char buf[BUFSIZE];
268         int len;
269
270         /* auto baud sequence */
271         buf[0]='?';
272         txrx(lpc,buf,1,TXRX_TYPE_BAUD);
273         if(strncmp(buf,"Synchronized\r\n",14)) {
274                 printf("auto baud detection failed\n");
275                 return -1;
276         }
277
278         /* tell bl that we are synchronized (it's allready in buf) */
279         txrx(lpc,buf,14,TXRX_TYPE_SYNC);
280         if(strncmp(buf,"OK\r\n",4)) {
281                 printf("sync failed\n");
282                 return -1;
283         }
284
285         /* tell bl the crystal frequency */
286         len=strlen(lpc->freq)+2;
287         strncpy(buf,lpc->freq,BUFSIZE);
288         buf[len-2]='\r';
289         buf[len-1]='\n';
290         txrx(lpc,buf,len,TXRX_TYPE_SYNC);
291         if(strncmp(buf,"OK\r\n",4)) {
292                 printf("freq set failed\n");
293                 return -1;
294         }
295
296         return 0;
297 }
298
299 int unlock_go(t_lpc *lpc) {
300
301         char buf[BUFSIZE];
302         int ret;
303
304         memcpy(buf,"U 23130\r\n",9);
305         ret=txrx(lpc,buf,9,TXRX_TYPE_CMD);
306
307         return ret;
308 }
309
310 int go(t_lpc *lpc) {
311
312         char buf[BUFSIZE];
313         int ret,len;
314
315         snprintf(buf,BUFSIZE,"G %d A\r\n",lpc->jaddr);
316         len=strlen(buf);
317         ret=txrx(lpc,buf,len,TXRX_TYPE_GO);
318
319         return ret;
320 }
321
322 int uuencode(u8 *in,u8 *out,int len) {
323
324         out[0]=0x20+len;
325         out[1]=0x20+((in[0]>>2)&0x3f);
326         out[2]=0x20+(((in[0]<<4)|(in[1]>>4))&0x3f);
327         out[3]=0x20+(((in[1]<<2)|(in[2]>>6))&0x3f);
328         out[4]=0x20+(in[2]&0x3f);
329
330         return 0;
331 }
332
333 int write_to_ram(t_lpc *lpc,char *buf,u32 addr,int len) {
334
335         int lcount;
336         u32 checksum;
337         char txrxbuf[BUFSIZE];
338         int count,bcnt;
339         int nlen,slen;
340         int i;
341
342         /* check length */
343         if(len%4) {
344                 printf("ram write: not a multiple of 4\n");
345                 return -1;
346         }
347
348         /* make it a multiple of 3 (reason: uuencode) */
349         nlen=(!(len%3))?len:((len/3+1)*3);
350         if(nlen>BUFSIZE) {
351                 printf("ram write: too much data\n");
352                 return -1;
353         }
354         for(i=len;i<nlen;i++) buf[i]=0;
355
356         /* prepare addr */
357         addr+=lpc->roff;
358
359         /* prepare write command */
360         if(lpc->info&VERBOSE)
361                 printf("writing 0x%02x bytes to 0x%08x\n",len,addr);
362         snprintf(txrxbuf,BUFSIZE,"W %d %d\r\n",addr,len);
363         slen=strlen(txrxbuf);
364
365         /* send command and check return code */
366         txrx(lpc,txrxbuf,slen,TXRX_TYPE_CMD);
367
368         /* send data */
369         lcount=0;
370         bcnt=0;
371         count=0;
372         checksum=0;
373         while(bcnt<nlen) {
374
375                 /* uuencode / prepare data bytes */
376                 uuencode((u8 *)(buf+bcnt),(u8 *)(txrxbuf),
377                          (bcnt==nlen-3)?(len%3?len%3:3):3);
378                 txrxbuf[5]='\r';
379                 txrxbuf[6]='\n';
380
381                 /* checksum */
382                 checksum+=((u8)buf[bcnt]+(u8)buf[bcnt+1]+(u8)buf[bcnt+2]);
383
384                 /* send a data line */
385                 txrx(lpc,txrxbuf,7,TXRX_TYPE_DATA);
386
387                 /* increase counters */
388                 lcount+=1;
389                 bcnt+=3;
390                 count+=3;
391
392                 /* checksum */
393                 if((!(lcount%20))|(bcnt==nlen)) {
394                         /* send backtick */
395                         memcpy(txrxbuf,"`\r\n",3);
396                         //txrx(lpc,txrxbuf,3,TXRX_TYPE_DATA);
397                         /* send checksum */
398                         snprintf(txrxbuf,BUFSIZE,"%d\r\n",checksum);
399                         slen=strlen(txrxbuf);
400                         txrx(lpc,txrxbuf,slen,TXRX_TYPE_CKSM);
401                         if(!strncmp(txrxbuf,"RESE",4)) {
402                                 read(lpc->sfd,txrxbuf+4,4);
403                                 printf("ram write: resending ...\n");
404                                 bcnt-=count;
405                         }
406                         if(strncmp(txrxbuf,"OK\r\n",4)) {
407                                 printf("ram write: bad response\n");
408                                 return -1;
409                         }
410                         /* reset checksum & counter */
411                         checksum=0;
412                         count=0;
413                 }
414
415         }
416
417         return 0;
418 }
419
420 int firmware_to_ram(t_lpc *lpc) {
421
422         char buf[BUFSIZE];
423         u32 addr,len,type;
424         int ret,temp;
425
426         /* read a line */
427         ret=1;
428         while(ret) {
429                 /* sync line */
430                 ret=read(lpc->fwfd,buf,1);
431                 switch(buf[0]) {
432                         case '\r':
433                                 continue;
434                         case '\n':
435                                 continue;
436                         case ':':
437                                 /* start code */
438                                 break;
439                         default:
440                                 printf("fw to ram: no ihex format\n");
441                                 return -1;
442                 }
443                 /* read len */
444                 ret=read(lpc->fwfd,buf,2);
445                 sscanf(buf,"%02x",&len);
446                 /* read addr */
447                 ret=read(lpc->fwfd,buf,4);
448                 sscanf(buf,"%04x",&addr);
449                 /* read type */
450                 ret=read(lpc->fwfd,buf,2);
451                 sscanf(buf,"%02x",&type);
452                 /* successfull return if type is end of file */
453                 if(type==0x01)
454                         return 0;
455                 /* read data (and cksum) */
456                 ret=read(lpc->fwfd,buf,2*(len+1));
457                 if(ret!=(2*(len+1))) {
458                         printf("fw to ram: data missing\n");
459                                 return -1;
460                 }
461                 for(ret=0;ret<len;ret++) {
462                         sscanf(buf+2*ret,"%02x",&temp);
463                         buf[ret]=temp;
464                 }
465                 /* act according to type */
466                 switch(type) {
467                         //case 0x03:
468                         //      /* get cs and ip */
469                         //      break;
470                         case 0x00:
471                                 if(len%4) {
472                                         printf("fw to ram: invalid len\n");
473                                         return -1;
474                                 }
475                                 write_to_ram(lpc,buf,addr,len);
476                                 break;
477                         case 0x04:
478                                 lpc->roff=((buf[0]<<24)|(buf[1]<<16));
479                                 break;
480                         case 0x05:
481                                 lpc->jaddr=((buf[0]<<24)|(buf[1]<<16));
482                                 lpc->jaddr|=((buf[2]<<8)|buf[3]);
483                                 break;
484                         default:
485                                 printf("fw to ram: unknown type %02x\n",type);
486                                 return -1;
487                 }
488         }
489
490         return 0;
491 }
492
493 int main(int argc,char **argv) {
494
495         t_lpc lpc;
496         int i;
497         int ret;
498
499         /*
500          * initial ... 
501          */
502
503         memset(&lpc,0,sizeof(t_lpc));
504         strncpy(lpc.freq,CRYSTFREQ,7);
505         lpc.roff=RAMOFFSET;
506         lpc.jaddr=RAMOFFSET;
507
508         /* parse argv */
509
510         for(i=1;i<argc;i++) {
511
512                 if(argv[i][0]!='-') {
513                         usage();
514                         return -1;
515                 }
516
517                 switch(argv[i][1]) {
518                         case 'd':
519                                 strncpy(lpc.sdev,argv[++i],127);
520                                 break;
521                         case 'f':
522                                 strncpy(lpc.fwfile,argv[++i],127);
523                                 lpc.info|=FIRMWARE;
524                                 break;
525                         case 'v':
526                                 lpc.info|=VERBOSE;
527                                 break;
528                         case 'c':
529                                 strncpy(lpc.freq,argv[++i],7);
530                                 break;
531                         default:
532                                 usage();
533                                 return -1;
534                 }
535
536         }
537
538         /* open serial port */
539         if(open_serial_device(&lpc)<0)
540                 goto end;
541
542         /* boot loader init */
543         printf("boot loader init ...\n");
544         if(bl_init(&lpc)<0)
545                 return -1;
546
547         /* quit if there is no hex file to process */
548         if(!(lpc.info&FIRMWARE)) {
549                 printf("no firmware -> aborting\n");
550                 goto end;
551         }
552
553         /* open firmware file */
554         if(open_firmware(&lpc)<0)
555                 goto end;
556
557         /* parse intel hex file and write to ram */
558         printf("write firmware to ram ...\n");
559         firmware_to_ram(&lpc);
560
561         /* unlock go cmd */
562         printf("unlock go command ...\n");
563         unlock_go(&lpc);
564
565         /* go! */
566         printf("go ...\n");
567         ret=go(&lpc);
568
569 end:
570         close(lpc.sfd);
571         close(lpc.fwfd);
572
573         return 0;
574 }
575