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