//---------------------------------------------------------------------
        // 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;
        }
        }// 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();
		}//Hex_Validate()	


		//---------------------------------------------------------------------
		// DoParse()
		// Description:
		//---------------------------------------------------------------------
		public void DoParse()
		{	
			int iBootLoaderSizeR = 0;
			clsDevice objDevice = clsDevices.DeviceGet( cboDevice.Text );	
            bool bParseResult = false;

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

             } else if ( cboFamily.Text == "PIC18FJ" ) {
                objHex = new clsHex18FJ( txtFilename.Text );
                iBootLoaderSizeR = 16;
           
            } else if ( cboFamily.Text == "PIC24F" ) {
                objHex = new clsHex24F( txtFilename.Text );
                iBootLoaderSizeR = 4;

            } else if ( cboFamily.Text == "PIC24FJ" ) {
                objHex = new clsHex24FJ( txtFilename.Text );
                iBootLoaderSizeR = 8;
            
            } else if ( cboFamily.Text == "PIC24H" ) {
                objHex = new clsHex24H( txtFilename.Text );
                iBootLoaderSizeR = 8;

            } else if ( cboFamily.Text == "dsPIC30F" ) {				
				objHex = new clsHex30F( txtFilename.Text );
				iBootLoaderSizeR = 4;				
			
            } else if ( cboFamily.Text == "dsPIC33FJ" ) {
				objHex = new clsHex33FJ( txtFilename.Text );				
				iBootLoaderSizeR = 8;
            
            } else {
				return;
			}
	        
            // Check file existence
            if ( File.Exists(txtFilename.Text) == false ) {
                return;
            }

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

            // Parse settings
            clsParseSettings objParseSettings = new clsParseSettings(  iBootLoaderSizeR, objDevice, chkAllowBlOverwrite.Checked, chkNoGoto.Checked );

            // Parse
			if ( objDevice != null ) {
				txtInfo.Text = "";
				objHex.ParseHexFile( objParseSettings, 0, ref bParseResult );
				
				if ( objHex.hasValidProgram ) {
					chkWriteProgram.Enabled = true;
				} else {
					chkWriteProgram.Enabled = false;
					chkWriteProgram.Checked = false;
				}
				if ( objHex.hasValidEEPROM ) {
					chkWriteEEPROM.Enabled = true;
				} else {
					chkWriteEEPROM.Enabled = false;
					chkWriteEEPROM.Checked = false;
				}
				
				if ( objHex.hasValidConfigs ) {
					chkWriteConfigs.Enabled = true;
				} else {
					chkWriteConfigs.Enabled = false;
					chkWriteConfigs.Checked = false;
				}										
			}		
		}//DoParse();