toolsandutils/e32tools/w32repro/w32repro.cpp
changeset 0 83f4b4db085c
child 2 99082257a271
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolsandutils/e32tools/w32repro/w32repro.cpp	Tue Feb 02 01:39:43 2010 +0200
@@ -0,0 +1,428 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Based on PREPRO.CPP and ROMBUILD.CPP
+// 
+//
+
+#define WIN32_LEAN_AND_MEAN
+#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
+#include <windows.h>
+#include <winbase.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "h_utl.h"
+#include "h_ver.h"
+
+// need to pretend we've done e32image.h, to avoid clashes with winnt.h
+#define __E32IMAGE_H__
+struct E32ImageFile
+	{
+	};
+class CBytePair;
+#include "r_rom.h"
+
+#define READ_BUFFER_SIZE 0x1000		// allows for exuberant T_REPRO without delays in it
+#define WRITE_BUFFER_SIZE 0x1000
+
+TRomLoad TheRomHeader;
+TUint ImageDataSize=0;
+TUint FileSize=0;
+TText PortNumber='1';
+TUint BaudRate=115200;
+TBool Kick=EFalse;
+TBool UseHex=EFalse;
+TBool Verbose=EFalse;
+TBool RawImage=EFalse;
+TText* BootstrapName=NULL;
+
+const TUint KReproWrapperSize = 0x100;	// REPRO protocol assumes a wrapper size of 256 bytes
+
+HANDLE comPort;
+TUint32 BytesWritten;
+
+TText *processCommandLine(int argc, char *argv[])
+//
+// Process the command line arguments, printing a helpful message if none are supplied
+//
+	{
+
+	char HelpText[] = 
+		"* Syntax: W32REPRO [options] filename[.bin]\n"
+		"* \n"
+		"* Option: -P<n>        port number, defaults to COM1,\n"
+		"* Option: -K           kick the other end, to force another repro attempt\n"
+		"* Option: -B<rate>     baud rate, minimum 9600, defaults to 115200\n"
+		"* Option: -RAW         raw image with no header\n"
+		"* Option: -BOOT <file> bootstrap with <file> transmitted at 9600 baud\n"
+		"* Option: -HEX         use base 16 (for use with ReproC)\n"
+		"* Option: -V           display raw protocol messages\n"
+		"* \n"
+		"* All messages from W32REPRO begin with '*', every thing else comes from the\n"
+		"* machine being reprogrammed.\n";
+
+	TText *filename=NULL;
+	if (argc == 1)
+		{
+		cout << HelpText;
+		return NULL;
+		}
+	for (int i=1; i<argc; i++)
+		{
+		strupr(argv[i]);
+		if ((argv[i][0] == '-') || (argv[i][0] == '/'))
+			{
+			if (strcmp(argv[i],"-RAW")==0)
+				{
+				RawImage=ETrue;
+				}
+			else if (strcmp(argv[i],"-HEX")==0)
+				{
+				UseHex=ETrue;
+				}
+			else if (strcmp(argv[i],"-BOOT")==0)
+				{
+				if (++i==argc)
+					{
+					cout << "**** Missing argument for -BOOT\n*\n";
+					cout << HelpText;
+					return NULL;
+					}
+				BootstrapName=(TText*)argv[i];
+				}
+			else if (argv[i][1] == 'P')
+				{
+				PortNumber=argv[i][2];
+				}
+			else if (argv[i][1] == 'K')
+				{
+				Kick=ETrue;
+				}
+			else if (argv[i][1] == 'V')
+				{
+				Verbose=ETrue;
+				}
+			else if (argv[i][1] == 'B')
+				{
+				TInt rate=atoi(argv[i]+2);
+				if (rate>=9600)
+					{
+					BaudRate=rate;
+					}
+				else
+					{
+					cout << "**** Invalid baud rate: " << argv[i] << "\n*\n";
+					cout << HelpText;
+					return NULL;
+					}
+				}
+			else if (argv[i][1] == '?')
+				{
+				cout << HelpText;
+				return NULL;
+				}
+			else
+				{
+				cout << "**** Unrecognised argument " << argv[i] << "\n*\n";
+				cout << HelpText;
+				return NULL;
+				}
+			}
+		else // Must be the image filename
+			filename=(TText *)argv[i];
+		}
+	if (filename==NULL)
+		{
+		cout << "**** Missing image filename\n*\n";
+		cout << HelpText;
+		}
+	return filename;
+	}
+
+TInt openComPort()
+//
+// Open the com port and configure it
+//
+	{
+	char port[5]="COM1";
+	port[3]=PortNumber;
+	comPort=CreateFile(port,GENERIC_READ+GENERIC_WRITE,0,0,OPEN_EXISTING,0,NULL);
+	if (comPort==INVALID_HANDLE_VALUE)
+		return Print(EError,"* Cannot open %s\n",port);
+
+	DCB settings;
+	if (!GetCommState(comPort,&settings))
+		return Print(EError,"* Cannot read settings for %s\n",port);
+
+	if (!SetupComm(comPort,READ_BUFFER_SIZE,WRITE_BUFFER_SIZE))
+		return Print(EError,"* Cannot set buffer sizes for %s\n",port);
+
+	settings.fBinary=TRUE;
+	settings.fParity=FALSE;
+	settings.fAbortOnError=TRUE;	// overrides EV_ERR
+	settings.BaudRate=BaudRate;
+	settings.ByteSize=8;
+	settings.Parity=NOPARITY;
+	settings.StopBits=ONESTOPBIT;
+	settings.fRtsControl=RTS_CONTROL_ENABLE;
+	settings.fDtrControl=DTR_CONTROL_ENABLE;
+	settings.fOutxCtsFlow=FALSE;
+	settings.fOutxDsrFlow=FALSE;
+	settings.fDsrSensitivity=FALSE;
+	settings.fOutX=FALSE;		// no XON/XOFF for transmission
+	settings.fInX=FALSE;		// no XON/XOFF for reception
+	settings.fNull=FALSE;		// don't discard null bytes
+
+	settings.EvtChar='\001';	// REPRO command separator
+
+	if (!SetCommState(comPort,&settings))
+		return Print(EError,"* Cannot configure %s\n",port);
+	
+	if (!SetCommMask(comPort,EV_RXFLAG+EV_ERR))
+		return Print(EError,"* Cannot set CommMask for %s\n",port);
+
+	COMMTIMEOUTS timeouts = {
+		//20,0,0,	// allow up to 20 milliseconds between characters, i.e. buffer them properly
+		MAXDWORD,0,0,	// return immediately
+		0,0	// no write timeouts
+		};
+	if (!SetCommTimeouts(comPort,&timeouts))
+		return Print(EError,"* Cannot set timeouts for %s\n",port);
+
+	if (!SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_HIGHEST))
+		Print(EError,"* Failed to raise priority of this thread err=%d\n",GetLastError());
+	if (!SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS))
+		Print(EError,"* Failed to raise priority of this process err=%d\n",GetLastError());
+
+	Print(EScreen,"* Using %s at %d baud\n\n",port,BaudRate);
+	return KErrNone;
+	}
+
+BOOL WriteToComPort(char* data, DWORD length, char* comment)
+	{
+	if (Verbose)
+		{
+		if (comment==NULL)
+			Print(EScreen, "* TX=%*s\n", length, data);
+		else
+			Print(EScreen, "* TX <%d bytes of %s>\n", length, comment);
+		}
+	return WriteFile(comPort, data, length, &BytesWritten, NULL);
+	}
+
+TInt Bootstrap9600()
+	{
+	DCB settings;
+	if (!GetCommState(comPort,&settings))
+		return Print(EError,"* Cannot read COM settings\n");
+
+	settings.BaudRate=9600;
+	if (!SetCommState(comPort,&settings))
+		return Print(EError,"* Cannot reconfigure to 9600 baud\n");
+	
+	FILE* bootstrapFile=fopen((const char*)BootstrapName,"rb");
+	if (bootstrapFile==NULL)
+		return Print(EError,"* Cannot open bootstrap file %s for input (errno=%d)\n",BootstrapName,errno);
+
+	Print(EScreen,"* Sending bootstrap %s at 9600 baud\n",BootstrapName,BaudRate);
+
+	char bootdata[WRITE_BUFFER_SIZE];
+	TUint32 imageBytes=0;
+
+	while (!feof(bootstrapFile))
+		{
+		imageBytes=fread(bootdata,1,WRITE_BUFFER_SIZE,bootstrapFile);
+		if (imageBytes==0 && feof(bootstrapFile))
+			break;
+		if (imageBytes!=WRITE_BUFFER_SIZE && ferror(bootstrapFile))
+			{
+			return Print(ESevereError,"* Read only %d bytes of bootstrap err=%d\n",imageBytes,ferror(bootstrapFile));
+			}
+		if (!WriteToComPort(bootdata,imageBytes,"bootstrap data"))
+			return Print(ESevereError,"* Wrote only %d of %d bytes of bootstrap err=%d\n",
+				BytesWritten,imageBytes,GetLastError());
+		}
+	fclose(bootstrapFile);
+
+	settings.BaudRate=BaudRate;
+	if (!SetCommState(comPort,&settings))
+		return Print(EError,"* Cannot reconfigure to %d baud\n",BaudRate);
+	
+	Print(EScreen,"* Bootstrap downloaded\n\n");
+
+	return KErrNone;
+	}
+
+TInt main(int argc, char *argv[])
+	{
+	TInt err=KErrNone;
+
+	Print(EScreen,"\n* W32REPRO - Win32 version of PREPRO");
+  	Print(EScreen," V%02d.%02d (Build %03d)\n",MajorVersion,MinorVersion,Build);
+  	Print(EScreen,"* %s",Copyright);
+
+	TText *imageFileName = processCommandLine(argc, argv);
+	if (imageFileName==NULL)
+		return KErrGeneral;
+
+	FILE* romFile=fopen((const char*)imageFileName,"rb");
+	if (romFile==NULL)
+		return Print(EError,"* Cannot open ROM Image file %s for input (errno=%d)\n",imageFileName,errno);
+
+	if (RawImage)
+		TheRomHeader.wrapSize=0;
+	else
+		{
+		if (fread(&TheRomHeader,sizeof(TheRomHeader),1,romFile)!=1)
+			return Print(EError,"* Cannot read ROM Image header\n");
+		if (TheRomHeader.wrapSize!=KRomWrapperSize)
+			return Print(EError,"* Incorrect ROM header - wrong wrapper size\n");
+		}
+	if (fseek(romFile,0,SEEK_END)!=0)
+		return Print(EError,"* Cannot seek in ROM Image file\n");
+	FileSize=ftell(romFile);
+	ImageDataSize=FileSize-TheRomHeader.wrapSize;
+
+	Print(EAlways,"\n* ROM Image %s - 0x%06x bytes\n",imageFileName,ImageDataSize);
+
+	err=openComPort();
+	if (err!=KErrNone)
+		return err;
+
+	if (BootstrapName != NULL)
+		{
+		err=Bootstrap9600();
+		if (err!=KErrNone)
+			return err;
+		}
+
+	char romdata[WRITE_BUFFER_SIZE];
+	if (Kick)
+		{
+		memset(romdata,'!',64);		// string of non-numeric characters, won't harm old REPRO
+		WriteToComPort(romdata,64,NULL);
+		}
+	//
+	// Wait around for REPRO on the other end to send us commands
+	//
+	char command[READ_BUFFER_SIZE+1];
+	char* cp=command;
+	TInt length=READ_BUFFER_SIZE;
+	TUint expectedOffset=0;
+	TInt done=0;
+	while (!done)
+		{
+		TUint32 bytesRead=0,imageBytes=0,offset=0;
+
+		TUint32 event;
+		if (!WaitCommEvent(comPort,&event,NULL))
+			{
+			if (GetLastError()!=ERROR_OPERATION_ABORTED)
+				Print(EAlways,"\n* Unexpected WaitCommEvent failure %d event %x\n",GetLastError(),event);
+			TUint32 commError;
+			if (!ClearCommError(comPort,&commError,NULL))
+				{
+				Print(ESevereError,"\n* Failed to clear CommError - give up now!\n");
+				return KErrGeneral;
+				}
+			if (commError!=CE_OVERRUN)
+				Print(EAlways,"\n* Unexpected comms error %x\n",commError);
+			}
+		if (!ReadFile(comPort,cp,length,&bytesRead,NULL))
+			{
+			if (GetLastError()!=ERROR_OPERATION_ABORTED)
+				Print(EAlways,"\n* Unexpected ReadFile failure %d bytes %d\n",GetLastError(),bytesRead);
+			}
+		if (bytesRead==0)
+			continue;
+
+		char* next;
+		char* end = cp+bytesRead;
+		*end='\0';	// stick a terminator on the end, just in case
+
+		for (cp=(char*)command; (next=(char*)memchr(cp,'\001',end-cp))!=NULL ;cp=next+1)
+			{
+			*next='\0';	// drop the terminator
+			if (Verbose)
+				Print(EScreen, " * RX=%s\n", cp);
+			switch (cp[0])
+				{
+			case 'D':	// disconnect after successful REPRO
+				Print(EScreen,"* Disconnect\n");
+				done=1;
+				break;
+			case 'M':	// print message
+				Print(EScreen,"%s",cp+1);
+				break;
+			case 'P':	// panic
+				Print(ESevereError,"%s",cp+1);
+				break;
+			case 'R':	// request for data from the image at specified address
+				if (end-next>1)
+					break;	// must be the last command in the buffer
+				offset=strtoul(cp+1,NULL,UseHex?16:10)-KReproWrapperSize; // REPRO assumes wrapSize=256	
+				if ((offset&4095)!=0)
+					{
+					Print(ESevereError,"* Image offset %x not a multiple of 4k (%s)\n", offset,cp);
+					break;
+					}
+				if (offset>expectedOffset)
+					{
+					Print(ESevereError,"* Image offset %x should have been %x\n", offset,expectedOffset);
+					break;
+					}
+				Print(EScreen,"%x       \r",offset);		// in case we lost the message
+				expectedOffset=offset+WRITE_BUFFER_SIZE;	// what we expect next time
+				offset+=TheRomHeader.wrapSize;	// offset into the file
+				if (fseek(romFile,offset,SEEK_SET)!=0)
+					{
+					Print(ESevereError,"* Can't seek to file offset %x", offset);
+					break;
+					}
+
+				memset(romdata,0xff,WRITE_BUFFER_SIZE);
+				imageBytes=fread(romdata,1,WRITE_BUFFER_SIZE,romFile);
+				if (imageBytes!=WRITE_BUFFER_SIZE && offset+imageBytes!=FileSize)
+					{
+					Print(ESevereError,"* Read only %d bytes of image data err=%d\n",imageBytes,ferror(romFile));
+					break;
+					}
+				if (!WriteToComPort(romdata,WRITE_BUFFER_SIZE,"image data"))
+					Print(ESevereError,"* Wrote only %d bytes of image data err=%x\n",BytesWritten,GetLastError());
+				break;
+			case 'S':	// request for the size of the image
+				if (end-next>1)
+					break;	// must be the last command in the buffer
+				if (next-cp==1)
+					{
+					sprintf((char*)romdata,"%010d\n",ImageDataSize+KReproWrapperSize);
+					if (!WriteToComPort(romdata,strlen(romdata),NULL) 
+							|| BytesWritten!=strlen(romdata))
+						Print(ESevereError,"* Failed to write file size\n");
+					expectedOffset=0;	// because we are starting again
+					break;
+					}
+				// otherwise fall through
+			default:
+				Print(EAlways,"\n* Unrecognised command >%s<\n", cp);
+				}
+			}
+		if (cp<end)	// copy trailing characters back to the start of the buffer
+			memmove(command,cp,end-cp);
+		cp=command+(end-cp);
+		length=command+READ_BUFFER_SIZE-cp;
+		}
+	return KErrNone;
+	}