UINT32 MicroBooter_PrepareForExecution(UINT32 physicalEntryPointAddress)
{
    if (physicalEntryPointAddress == CODE_BASEADDRESS)
    {
        BlockStorageDevice *device;
        ByteAddress ByteAddress;
        UINT32 physicalAddress = CODE_BASEADDRESS;
        
        if (BlockStorageList::FindDeviceForPhysicalAddress( &device, physicalAddress, ByteAddress)) 
        {
            BlockStorageStream stream;
    
            if(stream.Initialize(BlockUsage::CODE, device))
            {
                BYTE *dst;

                if(stream.CurrentAddress() != CODE_BASEADDRESS)
                {
                    hal_fprintf( STREAM_LCD, "Warn: at wrong offset: 0x%08x\r\n", (UINT32)stream.CurrentAddress());
                    debug_printf( "Warn: at wrong offset: 0x%08x\r\n", (UINT32)stream.CurrentAddress());
                    stream.Seek(CODE_BASEADDRESS - stream.CurrentAddress(), BlockStorageStream::SeekCurrent);
                }

                // load ER_FLASH only
                dst =(BYTE *) EXCODE_BASEADDRESS  ;
                
                
                stream.Read( &dst, CODE_SIZE );
                

                CPU_DrainWriteBuffers();
            }
            
        }
    
    }

    return EXCODE_BASEADDRESS;
}
////////////////////////////////////////////////////////////////////////////////
// The TinyBooter_OnStateChange method is an event handler for state changes in 
// the TinyBooter.  It is designed to help porting kit users control the tinybooter
// execution and allow them to add diagnostics.
////////////////////////////////////////////////////////////////////////////////
void TinyBooter_OnStateChange(TinyBooterState state, void* data, void ** retData)
{
	switch (state)
	{
		////////////////////////////////////////////////////////////////////////////////////
		// State_EnterBooterMode - TinyBooter has entered upload mode
		////////////////////////////////////////////////////////////////////////////////////
	case State_EnterBooterMode:
		hal_fprintf(STREAM_LCD, "Waiting\r");
		break;

		////////////////////////////////////////////////////////////////////////////////////
		// State_ButtonPress - A button was pressed while Tinybooter 
		// The data parameter is a pointer to the timeout value for the booter mode.
		////////////////////////////////////////////////////////////////////////////////////
	case State_ButtonPress:
		if (NULL != data)
		{
			UINT32 down, up;
			INT32* timeout_ms = (INT32*)data;

			// wait forever if a button was pressed
			*timeout_ms = -1;

			// process buttons
			while (Buttons_GetNextStateChange(down, up))
			{
				// leave a way to exit boot mode incase it was accidentally entered
				if (0 != (down & BUTTON_ENTR))
				{
					// force an enumerate and launch
					*timeout_ms = 0;
				}
			}
		}
		break;

		////////////////////////////////////////////////////////////////////////////////////
		// State_ValidCommunication - TinyBooter has received valid communication from the host
		// The data parameter is a pointer to the timeout value for the booter mode.
		////////////////////////////////////////////////////////////////////////////////////
	case State_ValidCommunication:
		if (NULL != data)
		{
			INT32* timeout_ms = (INT32*)data;

			// if we received any com/usb data then let's change the timeout to at least 20 seconds
			if (*timeout_ms != -1 && *timeout_ms < 20000)
			{
				*timeout_ms = 20000;
			}
		}
		break;

		////////////////////////////////////////////////////////////////////////////////////
		// State_Timeout - The default timeout for TinyBooter has expired and TinyBooter will 
		// perform an EnumerateAndLaunch
		////////////////////////////////////////////////////////////////////////////////////
	case State_Timeout:
		break;

		////////////////////////////////////////////////////////////////////////////////////
		// State_MemoryXXX - Identifies memory accesses.
		////////////////////////////////////////////////////////////////////////////////////
	case State_MemoryWrite:
		hal_fprintf(STREAM_LCD, "Wr: 0x%08x\r", (UINT32)data);
		break;
	case State_MemoryErase:
		hal_fprintf(STREAM_LCD, "Er: 0x%08x\r", (UINT32)data);
		break;


		////////////////////////////////////////////////////////////////////////////////////
		// State_CryptoXXX - Start and result of Crypto signature check
		////////////////////////////////////////////////////////////////////////////////////
	case State_CryptoStart:
		hal_fprintf(STREAM_LCD, "Chk signature \r");
		hal_printf("Chk signature \r");
		break;
		// The data parameter is a boolean that represents signature PASS/FAILURE
	case State_CryptoResult:
		if ((bool)data)
		{
			hal_fprintf(STREAM_LCD, "Signature PASS\r\n\r\n");
			hal_printf("Signature PASS\r\n\r\n");
		}
		else
		{
			hal_fprintf(STREAM_LCD, "Signature FAIL\r\n\r\n");
			hal_printf("Signature FAIL\r\n\r\n");
		}
		DebuggerPort_Flush(HalSystemConfig.DebugTextPort);
		break;

		////////////////////////////////////////////////////////////////////////////////////
		// State_Launch - The host has requested to launch an application at a given address, 
		//                or a timeout has occured and TinyBooter is about to launch the 
		//                first application it finds in FLASH.
		//
		// The data parameter is a UINT32 value representing the launch address
		////////////////////////////////////////////////////////////////////////////////////
	case State_Launch:
		UINT32 address = (UINT32)data;

		if (NULL != data)
		{
			hal_fprintf(STREAM_LCD, "Starting application at 0x%08x\r\n", address);
			debug_printf("Starting application at 0x%08x\r\n", address);

			if (address == CODE_BASEADDRESS || address == EXCODE_BASEADDRESS)
			{
				BlockStorageDevice *device;
				ByteAddress ByteAddress;
				UINT32 physicalAddress = CODE_BASEADDRESS;

				if (BlockStorageList::FindDeviceForPhysicalAddress(&device, physicalAddress, ByteAddress))
				{
					BlockStorageStream stream;

					if (stream.Initialize(BlockUsage::CODE, device))
					{
						if (stream.CurrentAddress() != CODE_BASEADDRESS)
						{
							hal_fprintf(STREAM_LCD, "Warn: at wrong offset: 0x%08x\r\n", (UINT32)stream.CurrentAddress());
							debug_printf("Warn: at wrong offset: 0x%08x\r\n", (UINT32)stream.CurrentAddress());
							stream.Seek(CODE_BASEADDRESS - stream.CurrentAddress(), BlockStorageStream::SeekCurrent);
						}

						BYTE *dst;
						dst = (BYTE *)EXCODE_BASEADDRESS;

						stream.Read(&dst, CODE_SIZE);

						if (retData != NULL)
						{
							*retData = (void*)EXCODE_BASEADDRESS;
						}

						CPU_DrainWriteBuffers();
					}
				}
			}
			else if (retData != NULL)
			{
				*retData = (void*)data;
			}
		}
		break;
	}

}