|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Based on PREPRO.CPP and ROMBUILD.CPP |
|
15 // |
|
16 // |
|
17 |
|
18 #define WIN32_LEAN_AND_MEAN |
|
19 #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union |
|
20 #include <windows.h> |
|
21 #include <winbase.h> |
|
22 |
|
23 #include <stdio.h> |
|
24 #include <stdlib.h> |
|
25 #include <string.h> |
|
26 #include "h_utl.h" |
|
27 #include "h_ver.h" |
|
28 |
|
29 // need to pretend we've done e32image.h, to avoid clashes with winnt.h |
|
30 #define __E32IMAGE_H__ |
|
31 struct E32ImageFile |
|
32 { |
|
33 }; |
|
34 class CBytePair; |
|
35 #include "r_rom.h" |
|
36 |
|
37 #define READ_BUFFER_SIZE 0x1000 // allows for exuberant T_REPRO without delays in it |
|
38 #define WRITE_BUFFER_SIZE 0x1000 |
|
39 |
|
40 TRomLoad TheRomHeader; |
|
41 TUint ImageDataSize=0; |
|
42 TUint FileSize=0; |
|
43 TText PortNumber='1'; |
|
44 TUint BaudRate=115200; |
|
45 TBool Kick=EFalse; |
|
46 TBool UseHex=EFalse; |
|
47 TBool Verbose=EFalse; |
|
48 TBool RawImage=EFalse; |
|
49 TText* BootstrapName=NULL; |
|
50 |
|
51 const TUint KReproWrapperSize = 0x100; // REPRO protocol assumes a wrapper size of 256 bytes |
|
52 |
|
53 HANDLE comPort; |
|
54 TUint32 BytesWritten; |
|
55 |
|
56 TText *processCommandLine(int argc, char *argv[]) |
|
57 // |
|
58 // Process the command line arguments, printing a helpful message if none are supplied |
|
59 // |
|
60 { |
|
61 |
|
62 char HelpText[] = |
|
63 "* Syntax: W32REPRO [options] filename[.bin]\n" |
|
64 "* \n" |
|
65 "* Option: -P<n> port number, defaults to COM1,\n" |
|
66 "* Option: -K kick the other end, to force another repro attempt\n" |
|
67 "* Option: -B<rate> baud rate, minimum 9600, defaults to 115200\n" |
|
68 "* Option: -RAW raw image with no header\n" |
|
69 "* Option: -BOOT <file> bootstrap with <file> transmitted at 9600 baud\n" |
|
70 "* Option: -HEX use base 16 (for use with ReproC)\n" |
|
71 "* Option: -V display raw protocol messages\n" |
|
72 "* \n" |
|
73 "* All messages from W32REPRO begin with '*', every thing else comes from the\n" |
|
74 "* machine being reprogrammed.\n"; |
|
75 |
|
76 TText *filename=NULL; |
|
77 if (argc == 1) |
|
78 { |
|
79 cout << HelpText; |
|
80 return NULL; |
|
81 } |
|
82 for (int i=1; i<argc; i++) |
|
83 { |
|
84 strupr(argv[i]); |
|
85 if ((argv[i][0] == '-') || (argv[i][0] == '/')) |
|
86 { |
|
87 if (strcmp(argv[i],"-RAW")==0) |
|
88 { |
|
89 RawImage=ETrue; |
|
90 } |
|
91 else if (strcmp(argv[i],"-HEX")==0) |
|
92 { |
|
93 UseHex=ETrue; |
|
94 } |
|
95 else if (strcmp(argv[i],"-BOOT")==0) |
|
96 { |
|
97 if (++i==argc) |
|
98 { |
|
99 cout << "**** Missing argument for -BOOT\n*\n"; |
|
100 cout << HelpText; |
|
101 return NULL; |
|
102 } |
|
103 BootstrapName=(TText*)argv[i]; |
|
104 } |
|
105 else if (argv[i][1] == 'P') |
|
106 { |
|
107 PortNumber=argv[i][2]; |
|
108 } |
|
109 else if (argv[i][1] == 'K') |
|
110 { |
|
111 Kick=ETrue; |
|
112 } |
|
113 else if (argv[i][1] == 'V') |
|
114 { |
|
115 Verbose=ETrue; |
|
116 } |
|
117 else if (argv[i][1] == 'B') |
|
118 { |
|
119 TInt rate=atoi(argv[i]+2); |
|
120 if (rate>=9600) |
|
121 { |
|
122 BaudRate=rate; |
|
123 } |
|
124 else |
|
125 { |
|
126 cout << "**** Invalid baud rate: " << argv[i] << "\n*\n"; |
|
127 cout << HelpText; |
|
128 return NULL; |
|
129 } |
|
130 } |
|
131 else if (argv[i][1] == '?') |
|
132 { |
|
133 cout << HelpText; |
|
134 return NULL; |
|
135 } |
|
136 else |
|
137 { |
|
138 cout << "**** Unrecognised argument " << argv[i] << "\n*\n"; |
|
139 cout << HelpText; |
|
140 return NULL; |
|
141 } |
|
142 } |
|
143 else // Must be the image filename |
|
144 filename=(TText *)argv[i]; |
|
145 } |
|
146 if (filename==NULL) |
|
147 { |
|
148 cout << "**** Missing image filename\n*\n"; |
|
149 cout << HelpText; |
|
150 } |
|
151 return filename; |
|
152 } |
|
153 |
|
154 TInt openComPort() |
|
155 // |
|
156 // Open the com port and configure it |
|
157 // |
|
158 { |
|
159 char port[5]="COM1"; |
|
160 port[3]=PortNumber; |
|
161 comPort=CreateFile(port,GENERIC_READ+GENERIC_WRITE,0,0,OPEN_EXISTING,0,NULL); |
|
162 if (comPort==INVALID_HANDLE_VALUE) |
|
163 return Print(EError,"* Cannot open %s\n",port); |
|
164 |
|
165 DCB settings; |
|
166 if (!GetCommState(comPort,&settings)) |
|
167 return Print(EError,"* Cannot read settings for %s\n",port); |
|
168 |
|
169 if (!SetupComm(comPort,READ_BUFFER_SIZE,WRITE_BUFFER_SIZE)) |
|
170 return Print(EError,"* Cannot set buffer sizes for %s\n",port); |
|
171 |
|
172 settings.fBinary=TRUE; |
|
173 settings.fParity=FALSE; |
|
174 settings.fAbortOnError=TRUE; // overrides EV_ERR |
|
175 settings.BaudRate=BaudRate; |
|
176 settings.ByteSize=8; |
|
177 settings.Parity=NOPARITY; |
|
178 settings.StopBits=ONESTOPBIT; |
|
179 settings.fRtsControl=RTS_CONTROL_ENABLE; |
|
180 settings.fDtrControl=DTR_CONTROL_ENABLE; |
|
181 settings.fOutxCtsFlow=FALSE; |
|
182 settings.fOutxDsrFlow=FALSE; |
|
183 settings.fDsrSensitivity=FALSE; |
|
184 settings.fOutX=FALSE; // no XON/XOFF for transmission |
|
185 settings.fInX=FALSE; // no XON/XOFF for reception |
|
186 settings.fNull=FALSE; // don't discard null bytes |
|
187 |
|
188 settings.EvtChar='\001'; // REPRO command separator |
|
189 |
|
190 if (!SetCommState(comPort,&settings)) |
|
191 return Print(EError,"* Cannot configure %s\n",port); |
|
192 |
|
193 if (!SetCommMask(comPort,EV_RXFLAG+EV_ERR)) |
|
194 return Print(EError,"* Cannot set CommMask for %s\n",port); |
|
195 |
|
196 COMMTIMEOUTS timeouts = { |
|
197 //20,0,0, // allow up to 20 milliseconds between characters, i.e. buffer them properly |
|
198 MAXDWORD,0,0, // return immediately |
|
199 0,0 // no write timeouts |
|
200 }; |
|
201 if (!SetCommTimeouts(comPort,&timeouts)) |
|
202 return Print(EError,"* Cannot set timeouts for %s\n",port); |
|
203 |
|
204 if (!SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_HIGHEST)) |
|
205 Print(EError,"* Failed to raise priority of this thread err=%d\n",GetLastError()); |
|
206 if (!SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS)) |
|
207 Print(EError,"* Failed to raise priority of this process err=%d\n",GetLastError()); |
|
208 |
|
209 Print(EScreen,"* Using %s at %d baud\n\n",port,BaudRate); |
|
210 return KErrNone; |
|
211 } |
|
212 |
|
213 BOOL WriteToComPort(char* data, DWORD length, char* comment) |
|
214 { |
|
215 if (Verbose) |
|
216 { |
|
217 if (comment==NULL) |
|
218 Print(EScreen, "* TX=%*s\n", length, data); |
|
219 else |
|
220 Print(EScreen, "* TX <%d bytes of %s>\n", length, comment); |
|
221 } |
|
222 return WriteFile(comPort, data, length, &BytesWritten, NULL); |
|
223 } |
|
224 |
|
225 TInt Bootstrap9600() |
|
226 { |
|
227 DCB settings; |
|
228 if (!GetCommState(comPort,&settings)) |
|
229 return Print(EError,"* Cannot read COM settings\n"); |
|
230 |
|
231 settings.BaudRate=9600; |
|
232 if (!SetCommState(comPort,&settings)) |
|
233 return Print(EError,"* Cannot reconfigure to 9600 baud\n"); |
|
234 |
|
235 FILE* bootstrapFile=fopen((const char*)BootstrapName,"rb"); |
|
236 if (bootstrapFile==NULL) |
|
237 return Print(EError,"* Cannot open bootstrap file %s for input (errno=%d)\n",BootstrapName,errno); |
|
238 |
|
239 Print(EScreen,"* Sending bootstrap %s at 9600 baud\n",BootstrapName,BaudRate); |
|
240 |
|
241 char bootdata[WRITE_BUFFER_SIZE]; |
|
242 TUint32 imageBytes=0; |
|
243 |
|
244 while (!feof(bootstrapFile)) |
|
245 { |
|
246 imageBytes=fread(bootdata,1,WRITE_BUFFER_SIZE,bootstrapFile); |
|
247 if (imageBytes==0 && feof(bootstrapFile)) |
|
248 break; |
|
249 if (imageBytes!=WRITE_BUFFER_SIZE && ferror(bootstrapFile)) |
|
250 { |
|
251 return Print(ESevereError,"* Read only %d bytes of bootstrap err=%d\n",imageBytes,ferror(bootstrapFile)); |
|
252 } |
|
253 if (!WriteToComPort(bootdata,imageBytes,"bootstrap data")) |
|
254 return Print(ESevereError,"* Wrote only %d of %d bytes of bootstrap err=%d\n", |
|
255 BytesWritten,imageBytes,GetLastError()); |
|
256 } |
|
257 fclose(bootstrapFile); |
|
258 |
|
259 settings.BaudRate=BaudRate; |
|
260 if (!SetCommState(comPort,&settings)) |
|
261 return Print(EError,"* Cannot reconfigure to %d baud\n",BaudRate); |
|
262 |
|
263 Print(EScreen,"* Bootstrap downloaded\n\n"); |
|
264 |
|
265 return KErrNone; |
|
266 } |
|
267 |
|
268 TInt main(int argc, char *argv[]) |
|
269 { |
|
270 TInt err=KErrNone; |
|
271 |
|
272 Print(EScreen,"\n* W32REPRO - Win32 version of PREPRO"); |
|
273 Print(EScreen," V%02d.%02d (Build %03d)\n",MajorVersion,MinorVersion,Build); |
|
274 Print(EScreen,"* %s",Copyright); |
|
275 |
|
276 TText *imageFileName = processCommandLine(argc, argv); |
|
277 if (imageFileName==NULL) |
|
278 return KErrGeneral; |
|
279 |
|
280 FILE* romFile=fopen((const char*)imageFileName,"rb"); |
|
281 if (romFile==NULL) |
|
282 return Print(EError,"* Cannot open ROM Image file %s for input (errno=%d)\n",imageFileName,errno); |
|
283 |
|
284 if (RawImage) |
|
285 TheRomHeader.wrapSize=0; |
|
286 else |
|
287 { |
|
288 if (fread(&TheRomHeader,sizeof(TheRomHeader),1,romFile)!=1) |
|
289 return Print(EError,"* Cannot read ROM Image header\n"); |
|
290 if (TheRomHeader.wrapSize!=KRomWrapperSize) |
|
291 return Print(EError,"* Incorrect ROM header - wrong wrapper size\n"); |
|
292 } |
|
293 if (fseek(romFile,0,SEEK_END)!=0) |
|
294 return Print(EError,"* Cannot seek in ROM Image file\n"); |
|
295 FileSize=ftell(romFile); |
|
296 ImageDataSize=FileSize-TheRomHeader.wrapSize; |
|
297 |
|
298 Print(EAlways,"\n* ROM Image %s - 0x%06x bytes\n",imageFileName,ImageDataSize); |
|
299 |
|
300 err=openComPort(); |
|
301 if (err!=KErrNone) |
|
302 return err; |
|
303 |
|
304 if (BootstrapName != NULL) |
|
305 { |
|
306 err=Bootstrap9600(); |
|
307 if (err!=KErrNone) |
|
308 return err; |
|
309 } |
|
310 |
|
311 char romdata[WRITE_BUFFER_SIZE]; |
|
312 if (Kick) |
|
313 { |
|
314 memset(romdata,'!',64); // string of non-numeric characters, won't harm old REPRO |
|
315 WriteToComPort(romdata,64,NULL); |
|
316 } |
|
317 // |
|
318 // Wait around for REPRO on the other end to send us commands |
|
319 // |
|
320 char command[READ_BUFFER_SIZE+1]; |
|
321 char* cp=command; |
|
322 TInt length=READ_BUFFER_SIZE; |
|
323 TUint expectedOffset=0; |
|
324 TInt done=0; |
|
325 while (!done) |
|
326 { |
|
327 TUint32 bytesRead=0,imageBytes=0,offset=0; |
|
328 |
|
329 TUint32 event; |
|
330 if (!WaitCommEvent(comPort,&event,NULL)) |
|
331 { |
|
332 if (GetLastError()!=ERROR_OPERATION_ABORTED) |
|
333 Print(EAlways,"\n* Unexpected WaitCommEvent failure %d event %x\n",GetLastError(),event); |
|
334 TUint32 commError; |
|
335 if (!ClearCommError(comPort,&commError,NULL)) |
|
336 { |
|
337 Print(ESevereError,"\n* Failed to clear CommError - give up now!\n"); |
|
338 return KErrGeneral; |
|
339 } |
|
340 if (commError!=CE_OVERRUN) |
|
341 Print(EAlways,"\n* Unexpected comms error %x\n",commError); |
|
342 } |
|
343 if (!ReadFile(comPort,cp,length,&bytesRead,NULL)) |
|
344 { |
|
345 if (GetLastError()!=ERROR_OPERATION_ABORTED) |
|
346 Print(EAlways,"\n* Unexpected ReadFile failure %d bytes %d\n",GetLastError(),bytesRead); |
|
347 } |
|
348 if (bytesRead==0) |
|
349 continue; |
|
350 |
|
351 char* next; |
|
352 char* end = cp+bytesRead; |
|
353 *end='\0'; // stick a terminator on the end, just in case |
|
354 |
|
355 for (cp=(char*)command; (next=(char*)memchr(cp,'\001',end-cp))!=NULL ;cp=next+1) |
|
356 { |
|
357 *next='\0'; // drop the terminator |
|
358 if (Verbose) |
|
359 Print(EScreen, " * RX=%s\n", cp); |
|
360 switch (cp[0]) |
|
361 { |
|
362 case 'D': // disconnect after successful REPRO |
|
363 Print(EScreen,"* Disconnect\n"); |
|
364 done=1; |
|
365 break; |
|
366 case 'M': // print message |
|
367 Print(EScreen,"%s",cp+1); |
|
368 break; |
|
369 case 'P': // panic |
|
370 Print(ESevereError,"%s",cp+1); |
|
371 break; |
|
372 case 'R': // request for data from the image at specified address |
|
373 if (end-next>1) |
|
374 break; // must be the last command in the buffer |
|
375 offset=strtoul(cp+1,NULL,UseHex?16:10)-KReproWrapperSize; // REPRO assumes wrapSize=256 |
|
376 if ((offset&4095)!=0) |
|
377 { |
|
378 Print(ESevereError,"* Image offset %x not a multiple of 4k (%s)\n", offset,cp); |
|
379 break; |
|
380 } |
|
381 if (offset>expectedOffset) |
|
382 { |
|
383 Print(ESevereError,"* Image offset %x should have been %x\n", offset,expectedOffset); |
|
384 break; |
|
385 } |
|
386 Print(EScreen,"%x \r",offset); // in case we lost the message |
|
387 expectedOffset=offset+WRITE_BUFFER_SIZE; // what we expect next time |
|
388 offset+=TheRomHeader.wrapSize; // offset into the file |
|
389 if (fseek(romFile,offset,SEEK_SET)!=0) |
|
390 { |
|
391 Print(ESevereError,"* Can't seek to file offset %x", offset); |
|
392 break; |
|
393 } |
|
394 |
|
395 memset(romdata,0xff,WRITE_BUFFER_SIZE); |
|
396 imageBytes=fread(romdata,1,WRITE_BUFFER_SIZE,romFile); |
|
397 if (imageBytes!=WRITE_BUFFER_SIZE && offset+imageBytes!=FileSize) |
|
398 { |
|
399 Print(ESevereError,"* Read only %d bytes of image data err=%d\n",imageBytes,ferror(romFile)); |
|
400 break; |
|
401 } |
|
402 if (!WriteToComPort(romdata,WRITE_BUFFER_SIZE,"image data")) |
|
403 Print(ESevereError,"* Wrote only %d bytes of image data err=%x\n",BytesWritten,GetLastError()); |
|
404 break; |
|
405 case 'S': // request for the size of the image |
|
406 if (end-next>1) |
|
407 break; // must be the last command in the buffer |
|
408 if (next-cp==1) |
|
409 { |
|
410 sprintf((char*)romdata,"%010d\n",ImageDataSize+KReproWrapperSize); |
|
411 if (!WriteToComPort(romdata,strlen(romdata),NULL) |
|
412 || BytesWritten!=strlen(romdata)) |
|
413 Print(ESevereError,"* Failed to write file size\n"); |
|
414 expectedOffset=0; // because we are starting again |
|
415 break; |
|
416 } |
|
417 // otherwise fall through |
|
418 default: |
|
419 Print(EAlways,"\n* Unrecognised command >%s<\n", cp); |
|
420 } |
|
421 } |
|
422 if (cp<end) // copy trailing characters back to the start of the buffer |
|
423 memmove(command,cp,end-cp); |
|
424 cp=command+(end-cp); |
|
425 length=command+READ_BUFFER_SIZE-cp; |
|
426 } |
|
427 return KErrNone; |
|
428 } |