toolsandutils/e32tools/w32repro/w32repro.cpp
changeset 0 83f4b4db085c
child 2 99082257a271
equal deleted inserted replaced
-1:000000000000 0:83f4b4db085c
       
     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 the License "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 	}