}// PrintHelp()


        //-------------------------------------------------------------------------
        // ValidateParseArgs()
        //-------------------------------------------------------------------------
        private void ValidateParseArgs( string[] pstrArgs, clsParseSettings pobjParseSettings, clsDownloadSettings pobjDownloadSettings, ref bool pbResult ) 
        {
            pbResult = false;

            //
            string [] strSplitArgs;
            string strOption;
            string strOptionValue;
            string strArgument;

            //
            bool bFileSpecified = false;
            bool bPortSpecified = false;
            bool bBaudrateSpecified = false;
            bool bDeviceSpecified = false;


            foreach ( string strArg in pstrArgs ) {
                //
                strArgument = strArg;
                if ( strArg.EndsWith("=") ) {
                    strArgument += "0";
                }
                strSplitArgs = strArgument.Split('=');
                
                // Argument                
                strOption = strSplitArgs[0].ToLower();
                
                // Argument value
                if ( strSplitArgs.Length == 2 ) {
                    strOptionValue = strSplitArgs[1];
                } else if (strSplitArgs.Length == 1 ) {
                    strOptionValue = "";
                } else {
                    Console.WriteLine( "Invalid argument: " + strArg );
                    return;
                }

                switch ( strOption ) {
                    //---------------------------------------------------------
                    // Misc
                    //---------------------------------------------------------

                    // Help
                    case "-h":
                    case "--help":
                        PrintHelp();
                        return;

                    // Debugmode
                    case "-l":
                    case "--debugmode":
                        clsds30Loader.debugMode = true;
                        return;

                    // Non-interactive
                    case "-o":
                    case "--non-interactive":
                        bNonInteractive = true;
                        return;

                    
                    //---------------------------------------------------------
                    // Basic
                    //---------------------------------------------------------

                    // Devicename
                    case "-d":
                    case "--device":
                        objDevice = clsDevices.DeviceGet( strOptionValue );
                        if ( objDevice == null ) {
                            Console.WriteLine( "Unknown device specified." );
                            return;
                        }
                        bDeviceSpecified = true;
                        break;

                    // Hex-file
                    case "-f":
                    case "--file":
                        strFile = strOptionValue;    
                        if ( File.Exists(strFile) == false ) {
                            Console.WriteLine( "Non-existing file specified." );
                            return;
                        }
                        bFileSpecified = true;
                        
                        break;                        

                    // Portname
                    case "-k":
                    case "--port":
                        strPort = strOptionValue;
                        bPortSpecified = true;
                        break; 
                    
                    // Baudrate
                    case "-r":
                    case "--baudrate":
                        try {
                            iBaudrate = int.Parse( strOptionValue );
                        } catch {
                            Console.WriteLine( "Invalid baudrate specified." );
                            return;
                        }
                        if ( iBaudrate <= 0 ) {
                            Console.WriteLine( "Invalid baudrate specified." );
                            return;
                        }
                        bBaudrateSpecified = true;
                        break;
                    
                    // Write program
                    case "-p":
                    case "--write-program":
                        pobjDownloadSettings.writeProgram = true;
                        break;
                    
                    // Write eeprom
                    case "-e":
                    case "--write-eeprom":
                        pobjDownloadSettings.writeEEPROM = true;
                        break;                    
                    

                    //---------------------------------------------------------
                    // Advanced
                    //---------------------------------------------------------

                    // Write configs
                    case "-c":
                    case "--write-configs":
                        pobjDownloadSettings.writeConfigs = true;
                        break;
                    
                    // Don't write goto
                    case "-g":
                    case "--no-goto":
                        pobjParseSettings.noGoto = true;
                        pobjDownloadSettings.noGoto = true;
                        break;
                     
                    // Allow overwrite of bootloader
                    case "-s":
                    case "--allow-bl-overwrite":
                        pobjParseSettings.allowBlOverwrite = true;
                        pobjDownloadSettings.allowBlOverwrite = true;
                        break;
                   

                    //---------------------------------------------------------
                    // Timing
                    //---------------------------------------------------------

                    // Polltime
                    case "-a":
                    case "--polltime":
                        int iPolltime;
                        try {
                            iPolltime = int.Parse( strOptionValue );
                        } catch {
                            Console.WriteLine( "Invalid polltime specified." );
                            return;
                        }
                        if ( iPolltime <= 0 ) {
                            Console.WriteLine( "Invalid polltime specified." );
                            return;
                        }
                        pobjDownloadSettings.polltime = iPolltime;
                        break;
                    
                    // Timeout
                    case "-t":
                    case "--timeout":
                        int iTimeout;
                        try {
                            iTimeout = int.Parse( strOptionValue );
                        } catch {
                            Console.WriteLine( "Invalid timeout specified." );
                            return;
                        }
                        if ( iTimeout <= 0 ) {
                            Console.WriteLine( "Invalid timeout specified." );
                            return;
                        }
                        pobjDownloadSettings.timeout = iTimeout;
                        break;


                    //---------------------------------------------------------
                    // Reset
                    //---------------------------------------------------------

                    // Reset by command
                    case "-q":
                    case "--reset-command":
                        pobjDownloadSettings.resetCommand = true;
                        pobjDownloadSettings.resetCommandSequence = strOptionValue;
                        break;

                     // Reset baudrate
                    case "-u":
                    case "--reset-baudrate":
                        int iResetBaudrate;
                        try {
                            iResetBaudrate = int.Parse( strOptionValue );
                        } catch {
                            Console.WriteLine( "Invalid reset baudrate specified." );
                            return;
                        }
                        if ( iResetBaudrate <= 0 ) {
                            Console.WriteLine( "Invalid reset baudrate specified." );
                            return;
                        }
                        pobjDownloadSettings.resetBaudrate = iResetBaudrate;
                        break;
                   
                    // Reset by dtr
                    case "-m":
                    case "--reset-dtr":
                        pobjDownloadSettings.resetDtr = true;
                        break;

                    // Reset by rts
                    case "-n":
                    case "--reset-rts":
                        pobjDownloadSettings.resetRts = true;
                        break;
                    
                    // Resettime
                    case "-b":
                    case "--resettime":
                        int iResettime;
                        try {
                            iResettime = int.Parse( strOptionValue );
                        } catch {
                            Console.WriteLine( "Invalid resettime specified." );
                            return;
                        }
                        if ( iResettime <= 0 ) {
                            Console.WriteLine( "Invalid resettime specified." );
                            return;
                        }
                        pobjDownloadSettings.resetTime = iResettime;
                        break;


                    //---------------------------------------------------------
                    // Activation
                    //---------------------------------------------------------

                    // Activate by dtr
                    case "-i":
                    case "--activate-dtr":
                        pobjDownloadSettings.activateDTR = true;
                        break;

                    // Activate by rts
                    case "-j":
                    case "--activate-rts":
                        pobjDownloadSettings.activateRTS = true;
                        break;


                    //---------------------------------------------------------
                    // Unknown option
                    //---------------------------------------------------------
                    default:
                        Console.WriteLine( "Unknown option \"" + strArg + "\"" );
                        Console.WriteLine( "" );
                        return;

                }
            }

            if ( bFileSpecified == false ) {
                Console.WriteLine( "File not specified" );
                return;
            }
            if ( bPortSpecified == false ) {
                Console.WriteLine( "Port not specified" );
                return;
            }
            if ( bBaudrateSpecified == false ) {
                Console.WriteLine( "Baudrate not specified" );
                return;
            }
            if ( bDeviceSpecified == false ) {
                Console.WriteLine( "Device not specified" );
                return;
            }

            pbResult = true;
        }// ValidateParseArgs()
        }//ds30L_Downloading()	

        
        //---------------------------------------------------------------------
        // Constructor
        //---------------------------------------------------------------------
        public void DoMagic( string[] pstrArgs, ref bool pbResult ) 
        {
            pbResult = false;            

            
            //-----------------------------------------------------------------
            // If no argumentsa are specified, display help
            //-----------------------------------------------------------------
            if ( pstrArgs.Length == 0 ) {
                PrintHelp();
                return;
            }


            //-----------------------------------------------------------------
            // Validate arguments
            //-----------------------------------------------------------------
            bool bResult = false;
            clsParseSettings objParseSettings = new clsParseSettings();
            clsDownloadSettings objDownloadSettings = new clsDownloadSettings();
            ValidateParseArgs( pstrArgs, objParseSettings, objDownloadSettings, ref bResult );
            if ( bResult == false ) {
                return;
            }


            //-----------------------------------------------------------------
            // Nothing to do?
            //-----------------------------------------------------------------
			if ( objDownloadSettings.writeProgram == false && objDownloadSettings.writeEEPROM == false && objDownloadSettings.writeConfigs == false  ) {
				Console.WriteLine( "Nothing to do." );
				return;
			}


            //-----------------------------------------------------------------
            // Parse
            //-----------------------------------------------------------------
            objParseSettings.device = objDevice;
            DoParse( objParseSettings, objDownloadSettings );

            
            //-----------------------------------------------------------------
            // Create port
            //-----------------------------------------------------------------
            objPort = new clsSerialPort();
            objPort.Setup( strPort, iBaudrate );


            //-----------------------------------------------------------------
            // Increase process priority if polltime is low
            //-----------------------------------------------------------------
            if ( objDownloadSettings.polltime < 100 ) {
                try {
                    System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.AboveNormal;
                } catch {
                    clsDebugTextbox.OutputInfo( "Setting proccess priority failed." );
                }
            }


            //-----------------------------------------------------------------
            // Print settings
            //-----------------------------------------------------------------
            Console.WriteLine( "" );
            Console.WriteLine( "" );
            Console.WriteLine( "{0,-10} {1, -8}", "File:", strFile );
            Console.WriteLine( "{0,-10} {1, -8}", "Port:", strPort );
            Console.WriteLine( "{0,-10} {1, -8}", "Baudrate:", iBaudrate.ToString() );
            Console.WriteLine( "{0,-10} {1, -8}", "Device:", objDevice.name );


            //-----------------------------------------------------------------
            // 
            //-----------------------------------------------------------------            
            Console.WriteLine( "" );
            Console.WriteLine( "" );
            if ( bNonInteractive == false ) {
                Console.WriteLine( "Press any key to begin download" );
                Console.WriteLine( "" );
                Console.ReadKey();
            }
            

            //-----------------------------------------------------------------
            // Download
            //-----------------------------------------------------------------
            bool bDownloadResult = false;
            int iStartTime = Environment.TickCount;
            clsds30Loader.Download( objDevice, objPort, objHex, objDownloadSettings, 0, ref bDownloadResult );
            int iEndTime = Environment.TickCount;


            //-----------------------------------------------------------------
            // Restore process priority
            //-----------------------------------------------------------------
            if ( objDownloadSettings.polltime < 100 ) {
                try {
                    System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.Normal;
                } catch {
                    clsDebugTextbox.OutputInfo( "Setting proccess priority failed." );
                }
            }

            //-----------------------------------------------------------------
            // Download finished
            //-----------------------------------------------------------------            
            objPort.Close();
            if ( clsds30Loader.debugMode ) {
                clsDebugTextbox.OutputInfo( "Elapsed time: " + String.Format( "{0:0.#}", Convert.ToSingle(iEndTime - iStartTime) / 1000.0 ) + " seconds", 1 );			
            } 
            pbResult = bDownloadResult;
        }// DoMagic()
        }// DoMagic()


		//---------------------------------------------------------------------
		// DoParse()
		// Description:
		//---------------------------------------------------------------------
		private void DoParse( clsParseSettings pobjParseSettings, clsDownloadSettings pobjDownloadSettings )
		{	
			int iBootLoaderSizeR = 0;
            bool bParseResult = false;

            // Here we only assume a bootloader size to be able to parse the hex-file            
            if ( objDevice.family.name == "PIC18F" ) {
                objHex = new clsHex18F( strFile );
                iBootLoaderSizeR = 5 * objDevice.pageSizeR;

             } else if ( objDevice.family.name == "PIC18FJ" ) {
                objHex = new clsHex18FJ( strFile );
                iBootLoaderSizeR = 16;
           
            } else if ( objDevice.family.name == "PIC24F" ) {
                objHex = new clsHex24F( strFile );
                iBootLoaderSizeR = 4;

            } else if ( objDevice.family.name == "PIC24FJ" ) {
                objHex = new clsHex24FJ( strFile );
                iBootLoaderSizeR = 8;
            
            } else if ( objDevice.family.name == "PIC24H" ) {
                objHex = new clsHex24H( strFile );
                iBootLoaderSizeR = 8;

            } else if ( objDevice.family.name == "dsPIC30F" ) {				
				objHex = new clsHex30F( strFile );
				iBootLoaderSizeR = 4;				
			
            } else if ( objDevice.family.name == "dsPIC33FJ" ) {
				objHex = new clsHex33FJ( strFile );				
				iBootLoaderSizeR = 8;
            
            } else {
				return;
			}
	        
            // Check file existence
            if ( File.Exists(strFile) == false ) {
                return;
            }

            // Enum events
            objHex.HexFileValidate += new clsHex.HexFileValidateDelegate( Hex_Validate );
            objHex.HexFileParse += new clsHex.HexFileParseDelegate( Hex_Parse );

            // Parse
			if ( objDevice != null ) {
				objHex.ParseHexFile( pobjParseSettings, 0, ref bParseResult );
				
				pobjDownloadSettings.writeProgram &= objHex.hasValidProgram;
                pobjDownloadSettings.writeEEPROM &= objHex.hasValidEEPROM;
                pobjDownloadSettings.writeConfigs &= objHex.hasValidConfigs;
			}		
		}//DoParse();
        //---------------------------------------------------------------------
        // ResetDevice()
        //---------------------------------------------------------------------
        private static void ResetDevice( clsSerialPort pobjPort, clsDownloadSettings pobjSettings, int iTabLevel, ref bool pbResult )
        {
            pbResult = false;

            //--------------------------------------------------------------------------
            // Reset - command
            //--------------------------------------------------------------------------
            if ( pobjSettings.resetCommand == true ) {
                // Inform user
                OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.info, "Sending reset command", iTabLevel) );

                // Parse resetcommand
                bool bSplitResult = false;
                byte[] bBytes = pobjPort.SplitHexStringToBytes( pobjSettings.resetCommandSequence, ref bSplitResult );
                if ( bSplitResult == false ) {
                    OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Couldn't parse reset command sequence", iTabLevel) );
                    return;
                }
                /*string[] strBytes = pobjSettings.resetCommandSequence.Split( ';' );
                byte[] bBytes = new byte[ strBytes.Length ];
                int iIndex = 0;
                foreach ( string strByte in strBytes ) {
                    bBytes[iIndex] = byte.Parse( strByte, System.Globalization.NumberStyles.HexNumber );
                    ++iIndex;
                }*/

                // Open port
                int iOldBaudrate = pobjPort.baudrate;
                pobjPort.baudrate = pobjSettings.resetBaudrate;
                bool bOpenPortResult = false;
                PortOpen( pobjPort, pobjSettings, ref bOpenPortResult );

                // Send reset command and close port
                pobjPort.SendBytes( ref bBytes, bBytes.Length );
                while ( pobjPort.outBufferCount > 0 );
                pobjPort.Close();

                // Restore baudrate
                pobjPort.baudrate = iOldBaudrate;

                SleepResponsive( pobjSettings.resetTime );

            //--------------------------------------------------------------------------
            // Reset - dtr
            //--------------------------------------------------------------------------
            } else if ( pobjSettings.resetDtr == true ) {
                OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.info, "Resetting by dtr", iTabLevel) );
                pobjPort.dtrEnable = true;
                SleepResponsive( pobjSettings.resetTime );
                pobjPort.dtrEnable = false;

            //--------------------------------------------------------------------------
            // Reset - rts
            //--------------------------------------------------------------------------
            } else if ( pobjSettings.resetRts == true ) {
                OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.info, "Resetting by rts", iTabLevel) );
                pobjPort.rtsEnable = true;
                SleepResponsive( pobjSettings.resetTime );
                pobjPort.rtsEnable = false;
            }

            pbResult = true;
        }
        //---------------------------------------------------------------------
        // PortOpen()
        //---------------------------------------------------------------------
        private static void PortOpen( clsSerialPort pobjPort, clsDownloadSettings pobjSettings, ref bool pbResult )
        {
            pbResult = false;

            // Activate device when we open port
            try {
                pobjPort.objPort.DtrEnable = pobjSettings.activateDTR;
                pobjPort.objPort.RtsEnable = pobjSettings.activateRTS;
            } catch {
                OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "failed setting dtr & rts", -1) );
            }

            // Allready open?
            if ( pobjPort.isOpen == true ) {
                pbResult = true;
                return;
            }

            try {
                pobjPort.Open();
            } catch {
            }

            if ( pobjPort.isOpen == false ) {
                OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "failed to open port", -1) );
            }

            pbResult = pobjPort.isOpen;
        }
        //---------------------------------------------------------------------
        // FindLoader()
        //---------------------------------------------------------------------
        public static void FindLoader( clsDevice pobjDevice, clsSerialPort pobjPort , clsDownloadSettings pobjSettings, int iTabLevel, ref bool pbResult )
        {
            int iDeviceIdFound = -1;
            bool bGetResponseResult = false;
            bool bPortWasOpened = false;

            pbResult = false;

            //-----------------------------------------------------------------
            // Test-mode
            //-----------------------------------------------------------------
            if ( bTestMode == true ) {
                iFWVerMaj = iTestVerMaj;
                iFWVerMin = iTestVerMin;
                iFWVerRev = iTestVerRev;
                iDeviceIdFound = iTestDeviceID;
                //return true;

            //-----------------------------------------------------------------
            // Real-mode
            //-----------------------------------------------------------------
            } else {

                int iVerMaj = 0, iVerMinRev = 0;
                int iTimeIdReceived = 0;

                OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.info, "Searching for bl ", iTabLevel) );

                //--------------------------------------------------------------------------
                // Open port if not open
                //--------------------------------------------------------------------------
                if ( pobjPort.isOpen == false ) {
                    pobjPort.Open();
                    if ( pobjPort.isOpen == false ) {
                        OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Failed to open port", iTabLevel) );
                        return;
                    }
                    bPortWasOpened = true;
                }

                // Empty buffers prior to hello command incase there's some crap
                pobjPort.EmptyBuffers( true, false );

                //--------------------------------------------------------------------------
                // Send hello to bootloader
                //--------------------------------------------------------------------------
                bool bDeviceIDReceived = false;
                {
                    int iLastSend = Environment.TickCount - pobjSettings.polltime;
                    int iLastPoll = Environment.TickCount - pobjSettings.polltime;
                    int iStartTime = Environment.TickCount;

                    bool bByteReceived = false;

                    bool bTimedOut = false;

                    do {
                        // Check first byte, discard if null
                        if ( Environment.TickCount - iLastPoll >= pobjSettings.polltime/10) {
                            iLastPoll = Environment.TickCount;

                            if ( bByteReceived == false && pobjPort.inBufferCount > 0 ) {
                                bByteReceived = true;
                                iDeviceIdFound = GetResponse( pobjPort, ref bGetResponseResult );
                                if ( bGetResponseResult == false ) {
                                    if ( bPortWasOpened == true ) pobjPort.Close();
                                    return;
                                }
                                if ( iDeviceIdFound == 0 ) {
                                    OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.info, "(discarded null byte)", -1) );
                                } else {
                                    bDeviceIDReceived = true;
                                    iTimeIdReceived = Environment.TickCount;
                                    break;
                                }

                            }
                        }

                        // Send hello
                       if ( Environment.TickCount - iLastSend >= pobjSettings.polltime ) {
                            iLastSend = Environment.TickCount;
                            pobjPort.SendByte( cHello );
                            OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.info, ". ", -1) );
                        }

                        // Check for timeout
                        bTimedOut = ( Environment.TickCount - iStartTime >= pobjSettings.timeout );

                        // Handle message queue
                        Application.DoEvents();
                    } while (
                        bAbort == false &&
                        bTimedOut == false &&
                        (bByteReceived == false || pobjPort.inBufferCount == 0)
                    );

                    if ( bAbort == true  ) {
                        OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "aborted", -1) );
                        bAbort = false;
                        if ( bPortWasOpened == true ) pobjPort.Close();
                        return;
                    } else if ( bTimedOut == true ) {
                        OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "timed out", -1) );
                        if ( bPortWasOpened == true ) pobjPort.Close();
                        return;
                    }
                }

                //--------------------------------------------------------------------------
                // Read device id
                //--------------------------------------------------------------------------
                if ( bDeviceIDReceived == false ) {
                    iDeviceIdFound = GetResponse( pobjPort, ref bGetResponseResult );
                    if ( bGetResponseResult == false ) {
                        iTimeIdReceived = Environment.TickCount;
                        if ( bPortWasOpened == true ) pobjPort.Close();
                        return;
                    }
                }

                //--------------------------------------------------------------------------
                // Delay to receive firmware version if any
                //--------------------------------------------------------------------------
                int iTime = 1 + 30000 / pobjPort.baudrate;
                while ( Environment.TickCount - iTimeIdReceived < iTime && pobjPort.inBufferCount < 3 ) {
                }

                //--------------------------------------------------------------------------
                // Firmware doesn´t send version, assume 0.9.4
                //--------------------------------------------------------------------------
                if ( pobjPort.inBufferCount == 1 ) {
                        iFWVerMaj = 0;
                        iFWVerMin = 9;
                        iFWVerRev = 4;

                //--------------------------------------------------------------------------
                // Firmware that sends major and minor
                //--------------------------------------------------------------------------
                } else if ( pobjPort.inBufferCount == 2 ) {
                    iVerMaj = GetResponse( pobjPort, ref bGetResponseResult );
                    if ( bGetResponseResult == false ) {
                        if ( bPortWasOpened == true ) pobjPort.Close();
                        return;
                    }
                    iFWVerMaj = ( (iVerMaj & 0x70) >> 4 );
                    iFWVerMin = ( iVerMaj & 0xF );
                    iFWVerRev = 0;

                //--------------------------------------------------------------------------
                // Firmware that sends major, minor and revision
                //--------------------------------------------------------------------------
                } else if ( pobjPort.inBufferCount == 3 ) {
                    iVerMaj = GetResponse( pobjPort, ref bGetResponseResult );
                    if ( bGetResponseResult == false ) {
                        if ( bPortWasOpened == true ) pobjPort.Close();
                        return;
                    }
                    iVerMinRev = GetResponse( pobjPort, ref bGetResponseResult );
                    if ( bGetResponseResult == false ) {
                        if ( bPortWasOpened == true ) pobjPort.Close();
                        return;
                    }

                    iFWVerMaj = ( iVerMaj & 0x7F );
                    iFWVerMin = ( (iVerMinRev & 0xF0) >> 4 );
                    iFWVerRev = ( iVerMinRev & 0xF );
                }

                //--------------------------------------------------------------------------
                // PIC18 indicated by msb in fw ver major
                //--------------------------------------------------------------------------
                if ( (iVerMaj & 0x80) > 0 ) {
                    iDeviceIdFound += 300;
                }
            }//Test-/real-mode

            //--------------------------------------------------------------------------
            // Find device from device id
            //--------------------------------------------------------------------------
            clsDevice objFoundDevice = clsDevices.DeviceGet( iDeviceIdFound );

            //--------------------------------------------------------------------------
            // Invalid ID returned
            //--------------------------------------------------------------------------
            if ( objFoundDevice == null ) {
                OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Found unknown device id(" + iDeviceIdFound.ToString() + ") fw ver. " + iFWVerMaj.ToString() + "." + iFWVerMin.ToString() + "." + iFWVerRev.ToString(), iTabLevel) );
                if ( bPortWasOpened == true ) pobjPort.Close();
                return;
            }

            //--------------------------------------------------------------------------
            // Bootloader found
            //--------------------------------------------------------------------------
            OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.success, "Found " + objFoundDevice.name + " fw ver. " + iFWVerMaj.ToString() + "." + iFWVerMin.ToString() + "." + iFWVerRev.ToString(), iTabLevel) );

            //--------------------------------------------------------------------------
            // Different device found from choosen
            //--------------------------------------------------------------------------
            if ( objFoundDevice.id != pobjDevice.id ) {
                OnDownloading(new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Wrong pic detected(" + objFoundDevice.id.ToString() + ")/selected(" + pobjDevice.id.ToString() + "), aborting", iTabLevel));
                if ( bPortWasOpened == true ) pobjPort.Close();
                return;
            }

            pbResult = true;

            // Close port if it was openeed
            if ( bPortWasOpened == true ) {
                pobjPort.Close();
            }
        }
        //---------------------------------------------------------------------
        // Download()
        //---------------------------------------------------------------------
        public static void Download( clsDevice pobjDevice, clsSerialPort pobjPort, clsHex pobjHex, clsDownloadSettings pobjSettings, int iTabLevel, ref bool pbResult )
        {
            //
            bool bWriteSuccess = false;
            bool bParseResult = false;

            pbResult = false;
            bAbort = false;
            OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.started, "Initiating download...", iTabLevel++) );

            // Test-mode
            if ( bTestMode == true ) {
                OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.warning, "Test-mode is active", iTabLevel) );
            }

            //--------------------------------------------------------------------------
            // Reset device
            //--------------------------------------------------------------------------
            bool bResetResult = false;
            ResetDevice( pobjPort, pobjSettings, iTabLevel, ref bResetResult );
            if ( bResetResult == false ) {
                return;
            }

            //--------------------------------------------------------------------------
            // Open port
            //--------------------------------------------------------------------------
            bool bOpenPortResult = false;
            PortOpen( pobjPort, pobjSettings, ref bOpenPortResult );

            //--------------------------------------------------------------------------
            // Find loader
            //--------------------------------------------------------------------------
            bool bFindLoaderResult = false;
            FindLoader( pobjDevice, pobjPort, pobjSettings, iTabLevel, ref bFindLoaderResult );
            if ( bFindLoaderResult == false ) {
                PortClose( pobjPort );
                return;
            }

            //--------------------------------------------------------------------------
            // Init progressbar
            //--------------------------------------------------------------------------
            OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.progressStarted, "", 0) );

            //--------------------------------------------------------------------------
            // Determine size of the bootloader found
            //--------------------------------------------------------------------------
            bool bGetBLSizeResult = false;
            iBootloaderSizeR = GetBLSize( pobjDevice, ref bGetBLSizeResult );
            if ( bGetBLSizeResult == false ) {
                OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Unknown firmware version", iTabLevel) );
                PortClose( pobjPort );
                return;
            }

            //--------------------------------------------------------------------------
            //
            //--------------------------------------------------------------------------
            bool WaitBLReadyResponseResult = false;
            WaitBLReadyResponse( pobjPort, iTabLevel, ref WaitBLReadyResponseResult );
            if ( WaitBLReadyResponseResult == false ) {
                PortClose( pobjPort );
                return;
            }

            //--------------------------------------------------------------------------
            // Setup parse settings
            //--------------------------------------------------------------------------
            clsParseSettings objParseSettings = new clsParseSettings( iBootloaderSizeR, pobjDevice, false, pobjSettings.noGoto );

            //--------------------------------------------------------------------------
            // PIC18F
            //--------------------------------------------------------------------------
            if ( pobjDevice.family.name == "PIC18F" ) {
                clsHex18F objHex18F = (clsHex18F)pobjHex;

                // Parse
                objHex18F.ParseHexFile( objParseSettings, iTabLevel, ref bParseResult );
                if ( bParseResult == false ) {
                    PortClose( pobjPort );
                    return;
                }

                // Write versions 0.9.0 - 1.0.0
                if (
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 2 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 1 )
                ) {
                    bWriteSuccess = WriteFlash18F_0_9_0( pobjPort, pobjDevice, objHex18F, pobjSettings.writeProgram, pobjSettings.writeEEPROM, pobjSettings.writeConfigs, iTabLevel );

                    // Write versions 1.5
                } else if (
                    ( iFWVerMaj == 1 && iFWVerMin == 5 )
                ) {
                    bWriteSuccess = WriteFlash18F_0_9_0( pobjPort, pobjDevice, objHex18F, pobjSettings.writeProgram, false, false, iTabLevel );

                // Unkown version
                } else {
                    OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Unknown firmware version", iTabLevel) );
                    PortClose( pobjPort );
                    return;
                }

            //--------------------------------------------------------------------------
            // PIC18FJ
            //--------------------------------------------------------------------------
            } else if ( pobjDevice.family.name == "PIC18FJ" ) {
                clsHex18FJ objHex18FJ = (clsHex18FJ)pobjHex;

                // Parse
                objHex18FJ.ParseHexFile( objParseSettings, iTabLevel, ref bParseResult );
                if ( bParseResult == false ) {
                    PortClose( pobjPort );
                    return;
                }

                // Write versions 0.9.0 - 0.9.1
                if (
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 1 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 0 )
                ) {
                    bWriteSuccess = WriteFlash18FJ_0_9_0( pobjPort, pobjDevice, objHex18FJ, pobjSettings.writeProgram, iTabLevel );

                // Unkown version
                } else {
                    OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Unknown firmware version", iTabLevel) );
                    PortClose( pobjPort );
                    return;
                }

            //--------------------------------------------------------------------------
            // PIC24F
            //--------------------------------------------------------------------------
            } else if ( pobjDevice.family.name == "PIC24F" ) {
                clsHex24F objHex24F = (clsHex24F)pobjHex;

                // Parse
                objHex24F.ParseHexFile( objParseSettings, iTabLevel, ref bParseResult );
                if ( bParseResult == false ) {
                    PortClose( pobjPort );
                    return;
                }

                // Write versions 0.9.0 - 0.9.0
                if (
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 1 )
                ) {
                    bWriteSuccess = WriteFlash24F_0_9_0( pobjPort, pobjDevice, objHex24F, pobjSettings.writeProgram, pobjSettings.writeEEPROM, pobjSettings.writeConfigs, iTabLevel );

                // Unkown version
                } else {
                    OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Unknown firmware version", iTabLevel) );
                    PortClose( pobjPort );
                    return;
                }

            //--------------------------------------------------------------------------
            // PIC24FJ
            //--------------------------------------------------------------------------
            } else if ( pobjDevice.family.name == "PIC24FJ" ) {
                clsHex24FJ objHex24FJ = (clsHex24FJ)pobjHex;

                // Parse
                objHex24FJ.ParseHexFile( objParseSettings, iTabLevel, ref bParseResult );
                if ( bParseResult == false ) {
                    PortClose( pobjPort );
                    return;
                }

                // Write versions 0.9.0 - 1.0.1
                if (
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 1 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 1 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 2 )
                ) {
                    bWriteSuccess = WriteFlash24FJ_1_0_0( pobjPort, pobjDevice, objHex24FJ, pobjSettings.writeProgram, pobjSettings.writeEEPROM, pobjSettings.writeConfigs, iTabLevel );

                // Unkown version
                } else {
                    OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Unknown firmware version", iTabLevel) );
                    PortClose( pobjPort );
                    return;
                }

            //--------------------------------------------------------------------------
            // PIC24H
            //--------------------------------------------------------------------------
            } else if ( pobjDevice.family.name == "PIC24H" ) {
                clsHex24H objHex24H = (clsHex24H)pobjHex;

                // Parse
                objHex24H.ParseHexFile( objParseSettings, iTabLevel, ref bParseResult );
                if ( bParseResult == false ) {
                    PortClose( pobjPort );
                    return;
                }

                // Write versions 0.9.0 - 0.9.1
                if (
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 1 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 0 )
                ) {
                    bWriteSuccess = WriteFlash24H_0_9_0( pobjPort, pobjDevice, objHex24H, pobjSettings.writeProgram, pobjSettings.writeConfigs, iTabLevel );

                // Unkown version
                } else {
                    OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Unknown firmware version", iTabLevel) );
                    PortClose( pobjPort );
                    return;
                }

            //--------------------------------------------------------------------------
            // dsPIC30F
            //--------------------------------------------------------------------------
            } else if ( pobjDevice.family.name == "dsPIC30F" ) {
                clsHex30F objHex30F = (clsHex30F)pobjHex;

                // Parse
                objHex30F.ParseHexFile( objParseSettings, iTabLevel, ref bParseResult );
                if ( bParseResult == false ) {
                    PortClose( pobjPort );
                    return;
                }

                // Write versions 0.9.4 - 1.0.1
                if (
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 4 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 1 )
                ) {
                    bWriteSuccess = WriteFlash30_1_0_1( pobjPort, pobjDevice, objHex30F, pobjSettings.writeProgram, pobjSettings.writeEEPROM, pobjSettings.writeConfigs, iTabLevel );

                // Versions 2.0.0 - 2.0.2
                } else if (
                    ( iFWVerMaj == 2 && iFWVerMin == 0 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 2 && iFWVerMin == 0 && iFWVerRev == 1 ) ||
                    ( iFWVerMaj == 2 && iFWVerMin == 0 && iFWVerRev == 2 )
                ) {
                    bWriteSuccess = WriteFlash30_2_0_0( pobjPort, pobjDevice, objHex30F, pobjSettings.writeProgram, pobjSettings.writeEEPROM, pobjSettings.writeConfigs, iTabLevel );

                // Unkown version
                } else {
                    OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Unknown firmware version", iTabLevel) );
                    PortClose( pobjPort );
                    return;
                }

            //--------------------------------------------------------------------------
            // dsPIC33F
            //--------------------------------------------------------------------------
            } else if ( pobjDevice.family.name == "dsPIC33FJ" ) {
                clsHex33FJ objHex33F = (clsHex33FJ)pobjHex;

                // Parse
                objHex33F.ParseHexFile( objParseSettings, iTabLevel, ref bParseResult );
                if ( bParseResult == false ) {
                    PortClose( pobjPort );
                    return;
                }

                // Write vrsions 0.9.0 - 1.0.0
                if (
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 1 ) ||
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 2 ) ||
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 3 ) ||
                    ( iFWVerMaj == 0 && iFWVerMin == 9 && iFWVerRev == 4 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 0 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 1 ) ||
                    ( iFWVerMaj == 1 && iFWVerMin == 0 && iFWVerRev == 2 )
                ) {
                    bWriteSuccess = WriteFlash33_1_0_0( pobjPort, pobjDevice, objHex33F, pobjSettings.writeProgram, pobjSettings.writeConfigs, iTabLevel );

                // Unkown version
                } else {
                    OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.error, "Unknown firmware version", iTabLevel) );
                    PortClose( pobjPort );
                    return;
                }
            }

            //--------------------------------------------------------------------------
            // Download completed
            //--------------------------------------------------------------------------
            pobjPort.Close();

            if ( bWriteSuccess == true ) {
                OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.completed, "Download finished", iTabLevel) );
            }

            OnDownloading( new clsDownloadingEventArgs(clsDownloadingEventArgs.EventType.progressEnded, "", 0) );
            pbResult = bWriteSuccess;
        }
		//---------------------------------------------------------------------
		// Constructor()
		//---------------------------------------------------------------------	
		public frmDS30Loader()
		{
			bStartup = true;
            InitializeComponent();

            //---------------------------------------------------------------------	
            // Create objects
            //---------------------------------------------------------------------	
            verGUI = new Version( strVersion );            
            sizeBeforeMicro = new Size();
			objPort = new clsSerialPort();	
		    objds30LSettings = new clsDownloadSettings();
            
            
            //---------------------------------------------------------------------	
            // Init
            //---------------------------------------------------------------------	
            ResetSettingsToDefault();
            clsDebugTextbox.SetTextbox( this.txtInfo );            
            progressBar.Visible = false;
            toolStrip1.Visible = false;			
            progressBar.Minimum = 0;
            progressBar.Maximum = 100;
            lblVersion.Text = clsds30Loader.strVersion + " / " + verGUI.ToString();
            

            //---------------------------------------------------------------------	
			// Enum comports
            //---------------------------------------------------------------------	
			string[] ports = System.IO.Ports.SerialPort.GetPortNames();
			foreach ( string strPort in ports ) {
				cboCOMPort.Items.Add( strPort );
			}
			
			// If no comports were found, add a few default
			if ( cboCOMPort.Items.Count == 0 ) {
				for ( int iIter = 1; iIter <= 4; iIter++ ) {
					cboCOMPort.Items.Add( "COM" + iIter.ToString() );
				}
			}
			if ( cboCOMPort.Items.Count > 0 ) {
				cboCOMPort.SelectedIndex = 0;
			} else {
				cboCOMPort.Text = "COM1";
			}
			
			cboBaudrate.SelectedIndex = 0;
            cboResetBaudrate.SelectedIndex = 0;
            cboTermBaudrate.SelectedIndex = 0;
			

            //---------------------------------------------------------------------	
			// Add device families to combobox
            //---------------------------------------------------------------------	
			clsDevices.Init();
            Hashtable htDeviceFamilys = clsDevices.DeviceFamiliesGet();
			foreach ( clsDeviceFamily objDeviceFamily in htDeviceFamilys.Values ) {
				cboFamily.Items.Add( objDeviceFamily.name );
			}
			
			//
			if ( cboFamily.Items.Count > 0 ) cboFamily.SelectedIndex = 0;
			
            
            //---------------------------------------------------------------------	
            // Load setttings
			//---------------------------------------------------------------------	
            LoadSettings();			


            //---------------------------------------------------------------------	
            // 
			//---------------------------------------------------------------------	            
            clsds30Loader.Downloading += new clsds30Loader.DownloadingDelegate( ds30L_Downloading );


            //---------------------------------------------------------------------	
            // Startup finished
            //---------------------------------------------------------------------	
			bStartup = false;
			DoParse();
		}//Constructor