8bd853010f225979c073ad24a3d5aaa630b693f6
[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_DATA          0x03
23
24 #define CMD_SUCCESS             "0\r\n"
25 #define INVALID_COMMAND         "1\r\n"
26 #define SRC_ADDR_ERROR          "2\r\n"
27 #define DST_ADDR_ERROR          "3\r\n"
28 #define SRC_ADDR_NOT_MAPPED     "4\r\n"
29 #define DST_ADDR_NOT_MAPPED     "5\r\n"
30 #define COUNT_ERROR             "6\r\n"
31 #define COMPARE_ERROR           "10\r\n"
32 #define BUSY                    "11\r\n"
33 #define PARAM_ERROR             "12\r\n"
34 #define ADDR_ERROR              "13\r\n"
35 #define ADDR_NOT_MAPPED         "14\r\n"
36 #define CMD_LOCKED              "15\r\n"
37 #define INVALID_CODE            "16\r\n"
38 #define INVALID_BAUD_RATE       "17\r\n"
39 #define INVALID_STOP_BIT        "18\r\n"
40
41 #define CRYSTFREQ               "10000"
42
43 #define BUFSIZE                 64
44
45 typedef unsigned char u8;
46
47 typedef struct s_lpc {
48         int sfd;                /* serial fd */
49         char sdev[128];         /* seriel device */
50         int fwfd;               /* fimrware fd */
51         char fwfile[128];       /* firmware file */
52         u8 info;                /* info/mode */
53         char freq[8];           /* frequency */
54         int partid;             /* part id */
55         u8 bcv[2];              /* boot code version */
56 } t_lpc;
57
58 void usage(void) {
59
60         printf("possible argv:\n");
61         printf("  -d <serial device>\n");
62         printf("  -f <firmware>\n");
63         printf("  -c <crystal freq>\n");
64         printf("  -v\n");
65
66 }
67
68 int open_serial_device(t_lpc *lpc) {
69
70         struct termios term;
71
72         //memset(&term,0,sizeof(struct termios));
73
74         /* open serial device */
75
76         lpc->sfd=open(lpc->sdev,O_RDWR);
77         if(lpc->sfd<0) {
78                 perror("tts open");
79                 return lpc->sfd;
80         }
81
82         /* configure the serial device */
83
84         tcgetattr(lpc->sfd,&term);
85
86         // input/output baudrate
87
88         cfsetispeed(&term,B9600);
89         cfsetospeed(&term,B9600);
90
91         // control options -> 8n1
92
93         term.c_cflag&=~PARENB;  // no parity
94         term.c_cflag&=~CSTOPB;  // only 1 stop bit
95         term.c_cflag&=~CSIZE;   // no bit mask for data bits
96         term.c_cflag|=CS8;      // 8 data bits
97
98         // line options -> raw input
99         
100         term.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
101
102         // input options -> disable flow control
103         
104         term.c_iflag&=~(IXON|IXOFF|IXANY);
105
106         // more control options -> timeout
107         
108         term.c_cc[VMIN]=0;
109         term.c_cc[VTIME]=10;    // 1 second timeout
110
111         tcsetattr(lpc->sfd,TCSANOW,&term);
112
113         return lpc->sfd;
114 }
115
116 int open_firmware(t_lpc *lpc) {
117
118         /* open firmware file */
119
120         lpc->fwfd=open(lpc->fwfile,O_RDONLY);
121
122         if(lpc->fwfd<0)
123                 perror("fw open");
124
125         return lpc->fwfd;
126 }
127
128 int txrx(t_lpc *lpc,char *buf,int len,u8 type) {
129
130         int ret,cnt;
131         int i;
132
133         /* write */
134
135         if(lpc->info&VERBOSE)
136                 printf("  >> ");
137         cnt=0;
138         while(len) {
139                 ret=write(lpc->sfd,buf+cnt,len);
140                 if(ret<0) {
141                         perror("txrx write");
142                         return ret;
143                 }
144                 if(lpc->info&VERBOSE)
145                         for(i=0;i<ret;i++)
146                                 printf("%c",
147                                        ((buf[cnt+i]>0x19)&(buf[cnt+i]<0x7f))?
148                                        buf[cnt+i]:'.');
149                 len-=ret;
150                 cnt+=ret;
151         }
152         if(lpc->info&VERBOSE)
153                 printf(" (%d)\n",cnt);
154
155         /* cut the echo if not of type auto baud */
156
157         if(type!=TXRX_TYPE_BAUD) {
158                 while(cnt) {
159                         ret=read(lpc->sfd,buf,cnt);
160                         if(ret<0) {
161                                 perror("txrx echo cut");
162                                 return ret;
163                         }
164                         cnt-=ret;
165                 }
166         }
167
168         /* read */
169
170         if(lpc->info&VERBOSE)
171                 printf("  << ");
172         ret=1;
173         cnt=0;
174         while(ret>0) {
175                 ret=read(lpc->sfd,buf+cnt,BUFSIZE-cnt);
176                 if(ret<0) {
177                         perror("txrx read");
178                         return ret;
179                 }
180                 if(ret+cnt>BUFSIZE) {
181                         printf("txrx read: too small buf size (%d)!\n",BUFSIZE);
182                         return -1;
183                 }
184                 if(lpc->info&VERBOSE)
185                         for(i=0;i<ret;i++)
186                                 printf("%c",
187                                        ((buf[cnt+i]>0x19)&(buf[cnt+i]<0x7f))?
188                                        buf[cnt+i]:'.');
189                 cnt+=ret;
190         }
191         if(lpc->info&VERBOSE)
192                 printf(" (%d)\n",cnt);
193         len=cnt;
194         buf[cnt]='\0';
195
196         /* check/strip return code if type is data */
197
198         if(type==TXRX_TYPE_DATA) {
199                 ret=strlen(CMD_SUCCESS);
200                 if(!strncmp(buf,CMD_SUCCESS,ret)) {
201                         for(i=ret;i<cnt;i++)
202                                 buf[i-ret]=buf[i];
203                         buf[cnt]='\0';
204                 }
205                 else {
206                         printf("txrx bad return code!\n");
207                         return -1;
208                 }
209         }
210
211         return cnt;
212 }
213
214 int bl_init(t_lpc *lpc) {
215
216         char buf[BUFSIZE];
217         int len;
218
219         /* auto baud sequence */
220         buf[0]='?';
221         txrx(lpc,buf,1,TXRX_TYPE_BAUD);
222         if(strncmp(buf,"Synchronized\r\n",14)) {
223                 printf("auto baud detection failed\n");
224                 return -1;
225         }
226
227         /* tell bl that we are synchronized (it's allready in buf) */
228         txrx(lpc,buf,14,TXRX_TYPE_SYNC);
229         if(strncmp(buf,"OK\r\n",4)) {
230                 printf("sync failed\n");
231                 return -1;
232         }
233
234         /* tell bl the crystal frequency */
235         len=strlen(lpc->freq)+2;
236         strncpy(buf,lpc->freq,BUFSIZE);
237         buf[len-2]='\r';
238         buf[len-1]='\n';
239         txrx(lpc,buf,len,TXRX_TYPE_SYNC);
240         if(strncmp(buf,"OK\r\n",4)) {
241                 printf("freq set failed\n");
242                 return -1;
243         }
244
245         return 0;
246 }
247
248 int read_part_id(t_lpc *lpc) {
249
250         char buf[BUFSIZE];
251
252         memcpy(buf,"J\r\n",3);
253         txrx(lpc,buf,3,TXRX_TYPE_DATA);
254         lpc->partid=atoi(buf);
255
256         return lpc->partid;
257 }
258
259 int read_bcv(t_lpc *lpc) {
260
261         char buf[BUFSIZE];
262         char *ptr;
263
264         memcpy(buf,"K\r\n",3);
265         txrx(lpc,buf,3,TXRX_TYPE_DATA);
266         ptr=strtok(buf,"\r\n");
267         lpc->bcv[0]=strtol(ptr,NULL,16);
268         ptr=strtok(NULL,"\r\n");
269         lpc->bcv[1]=strtol(ptr,NULL,16);
270
271         return 0;
272 }
273
274 int uuencode(char *in,char *out) {
275
276         out[0]=0x20+((in[0]>>2)&0x3f);
277         out[1]=0x20+(((in[0]<<4)|(in[1]>>4))&0x3f);
278         out[2]=0x20+(((in[1]<<2)|(in[2]>>6))&0x3f);
279         out[3]=0x20+(in[2]&0x3f);
280
281         return 0;
282 }
283
284 int write_to_ram(t_lpc *lpc,char *buf,int addr,int len) {
285
286         int lcount;
287         u8 checksum;
288
289         if(len%4) {
290                 printf("ram write: not a multiple of 4\n");
291                 return -1;
292         }
293
294         while(1) {
295                 if(!(lcount%20)) {
296                         /* send checksum */
297                         if(lcount!=0) {
298                                 
299                         }
300                         /* reset checksum */
301                         checksum=0;
302                 }
303
304                 lcount+=1;
305         }
306
307         return 0;
308 }
309
310 int firmware_to_ram(t_lpc *lpc) {
311
312
313
314         return 0;
315 }
316
317 int main(int argc,char **argv) {
318
319         t_lpc lpc;
320         int i;
321
322         /*
323          * initial ... 
324          */
325
326         memset(&lpc,0,sizeof(t_lpc));
327         strncpy(lpc.freq,CRYSTFREQ,7);
328
329         /* parse argv */
330
331         for(i=1;i<argc;i++) {
332
333                 if(argv[i][0]!='-') {
334                         usage();
335                         return -1;
336                 }
337
338                 switch(argv[i][1]) {
339                         case 'd':
340                                 strncpy(lpc.sdev,argv[++i],127);
341                                 break;
342                         case 'f':
343                                 strncpy(lpc.fwfile,argv[++i],127);
344                                 lpc.info|=FIRMWARE;
345                                 break;
346                         case 'v':
347                                 lpc.info|=VERBOSE;
348                                 break;
349                         case 'c':
350                                 strncpy(lpc.freq,argv[++i],7);
351                                 break;
352                         default:
353                                 usage();
354                                 return -1;
355                 }
356
357         }
358
359         /* open serial port */
360         if(open_serial_device(&lpc)<0)
361                 goto end;
362
363         /* boot loader init */
364         printf("boot loader init ...\n");
365         bl_init(&lpc);
366
367         /* read part id */
368         read_part_id(&lpc);
369         printf("part id: %d\n",lpc.partid);
370
371         /* read boot code version */
372         read_bcv(&lpc);
373         printf("boot code version: %02x %02x\n",lpc.bcv[0],lpc.bcv[1]);
374
375         // to be continued ... (parsing fw file and poking it to ram)
376         if(open_firmware(&lpc)<0)
377                 goto end;
378         firmware_to_ram(&lpc);
379
380 end:
381         close(lpc.sfd);
382         close(lpc.fwfd);
383
384         return 0;
385 }
386