/// <summary>
        /// Initiates the bootloading sequence. Make sure you reboot the board before this function call
        /// </summary>
        public void DoBootload()
        {
            uint ExtAddr = 0;

            byte[] Buffer = new byte[BUFFER_SIZE];

            ProgressForm.Show();

            UpdateForm("Opening source file..", 0); Application.DoEvents();
            try
            {
                SourceFile = new StreamReader(FileWithPath);
            }
            catch (Exception ex) { throw new Exception("File could not be opened\n" + FileWithPath, ex); }


            UpdateForm("Opening COM port..", 0); Application.DoEvents();
            try
            {
                //Open the port
                Port.Open();

                //Send restart packet
                // byte[] Packet = new byte[] { 0x02, 0x00, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03 };
                // Port.Write(Packet, 0, 37);

                //wait for board to restart
                // Thread.Sleep(200);

                //empty characters waiting to be dealt with
                Port.DiscardInBuffer();
            }
            catch (Exception ex) { throw new Exception(Port.PortName + " could not be opened", ex); }

            eFamily Family;

            try
            {
                Family = ReadID();
            }
            catch (Exception ex)
            {
                UpdateForm(ex.Message, 0);
                Thread.Sleep(500);
                Port.Close();
                ProgressForm.Close();
                throw new Exception("x-io board not responding on " + Port.PortName, ex);
            }


            UpdateForm("Reading source file..", 0); Application.DoEvents();

            try
            {
                ppMemory = new memRow[PM_SIZE + EE_SIZE + CM_SIZE];
                for (int Row = 0; Row < PM_SIZE; Row++)
                {
                    ppMemory[Row] = new memRow(memRow.eType.Program, 0, Row, eFamily.dsPIC33F);
                }

                for (int Row = 0; Row < EE_SIZE; Row++)
                {
                    ppMemory[Row + PM_SIZE] = new memRow(memRow.eType.EEprom, 0x7FF000, Row, eFamily.dsPIC33F);
                }

                for (int Row = 0; Row < CM_SIZE; Row++)
                {
                    ppMemory[Row + PM_SIZE + EE_SIZE] = new memRow(memRow.eType.Config, 0xF80000, Row, eFamily.dsPIC33F);
                }

                while (!SourceFile.EndOfStream)             //read the whole hex file, parse and store
                {
                    uint ByteCount  = 0;
                    uint Address    = 0;
                    uint RecordType = 0;

                    string aLine = SourceFile.ReadLine();

                    ByteCount  = (uint)(((CharToUShort(aLine[1]) << 4) & 0xF0) | (CharToUShort(aLine[2]) & 0xF));
                    Address    = (uint)(((CharToUShort(aLine[3]) << 12) & 0xF000) | ((CharToUShort(aLine[4]) << 8) & 0xF00) | ((CharToUShort(aLine[5]) << 4) & 0xF0) | (CharToUShort(aLine[6]) & 0xF));
                    RecordType = (uint)(((CharToUShort(aLine[7]) << 4) & 0xF0) | (CharToUShort(aLine[8]) & 0xF));


                    if (RecordType == 0)
                    {
                        Address = (uint)(Address + ExtAddr) / 2;

                        for (int CharCount = 0; CharCount < ByteCount * 2; CharCount += 4, Address++)
                        {
                            bool bInserted = false;

                            for (int Row = 0; Row < (PM_SIZE + EE_SIZE + CM_SIZE); Row++)
                            {
                                if ((bInserted = ppMemory[Row].InsertData(Address, aLine.Substring(9 + CharCount)) == true))
                                {
                                    break;
                                }
                            }

                            if (bInserted != true)
                            {
                                ProgressForm.Close();
                                Port.Close();
                                throw new Exception("Bad hex file: Address out of range");
                            }
                        }
                    }
                    else if (RecordType == 1)
                    {
                    }
                    else if (RecordType == 4)
                    {
                        ExtAddr   = (uint)(((CharToUShort(aLine[9]) << 12) & 0xF000) | ((CharToUShort(aLine[10]) << 8) & 0xF00) | ((CharToUShort(aLine[11]) << 4) & 0xF0) | (CharToUShort(aLine[12]) & 0xF));
                        ExtAddr <<= 16;
                    }
                    else
                    {
                        //Error
                    }
                }
            }
            catch (Exception ex)
            {
                Port.Close();
                ProgressForm.Close();
                throw ex;
            }


            //Close the source HEX file
            try
            {
                SourceFile.Close();
            }
            catch { }

            //Preserve first two locations for bootloader
            {
                string Data;
                int    RowSize;
                int    i = 0;

                if (Family == eFamily.dsPIC30F)
                {
                    RowSize = PM30F_ROW_SIZE;
                }
                else
                {
                    RowSize = PM33F_ROW_SIZE;
                }

                Buffer[0] = COMMAND_READ_PM;
                Buffer[1] = 0x00;
                Buffer[2] = 0x00;
                Buffer[3] = 0x00;

                Port.Write(Buffer, 0, 4);
                //Thread.Sleep(100);

                UpdateForm("Reading target..", 0); Application.DoEvents();

                try
                {
                    for (i = 0; i < ((RowSize * 3) - 500); i++)
                    {
                        Buffer[i] = (byte)Port.ReadByte();
                    }
                }
                catch (Exception ex)
                {
                    Port.Close();
                    ProgressForm.Close();
                    //throw new Exception("Charcount: " + i.ToString() + " out of " + Convert.ToString((RowSize * 3)) + " -- " + ex.Message);
                    throw new Exception(ex.Message + " on char: " + i.ToString() + " out of " + Convert.ToString((RowSize * 3)));
                }
                //Port.Read(Buffer,0,RowSize * 3);

                Data = String.Format("{0:x2}{1:x2}{2:x2}00{3:x2}{4:x2}{5:x2}00", Buffer[2], Buffer[1], Buffer[0], Buffer[5], Buffer[4], Buffer[3]);

                ppMemory[0].InsertData(0x000000, Data);
                ppMemory[0].InsertData(0x000001, Data.Substring(4));
                ppMemory[0].InsertData(0x000002, Data.Substring(8));
                ppMemory[0].InsertData(0x000003, Data.Substring(12));

                Port.DiscardInBuffer();
            }

            UpdateForm("Formatting data..", 0);
            for (int Row = 0; Row < (PM_SIZE + EE_SIZE + CM_SIZE); Row++)
            {
                ppMemory[Row].FormatData();
            }

            ((ProgressBar)ProgressForm.Controls[1]).Maximum = PM_SIZE + EE_SIZE + CM_SIZE;
            UpdateForm("Uploading firmware...", 0);


            /////////////////////////////////////////////////////
            while (true)
            {
                Application.DoEvents();                         //just in case something else happened, let the program deal with messages

                try
                {
                    ppMemory[LoadRow++].SendData(ref Port);
                }
                catch (Exception ex)
                {
                    Port.Close();
                    ProgressForm.Close();
                    throw ex;
                }

                UpdateForm(String.Format("Uploading firmware... {0:00.00}% done", ((double)LoadRow / (double)(PM_SIZE + EE_SIZE + CM_SIZE)) * 100), LoadRow);

                if (LoadRow >= (PM_SIZE + EE_SIZE + CM_SIZE))
                {
                    UpdateForm("Firmware update complete", LoadRow);

                    byte[] rsBuffer = new byte[] { COMMAND_RESET };
                    Port.Write(rsBuffer, 0, 1);

                    Application.DoEvents();
                    Thread.Sleep(300);
                    Port.Close();
                    ProgressForm.Close();
                    onBootloadFinished();
                    break;
                }
            }
        }
        /// <summary>
        /// Initiates the bootloading sequence. Make sure you reboot the board before this function call
        /// </summary>
        public void DoBootload()
        {
            uint ExtAddr = 0;
            byte[] Buffer = new byte[BUFFER_SIZE];

            ProgressForm.Show();

            UpdateForm("Opening source file..", 0); Application.DoEvents();
            try
            {
                SourceFile = new StreamReader(FileWithPath);
            }
            catch (Exception ex) { throw new Exception("File could not be opened\n" + FileWithPath, ex); }

            UpdateForm("Opening COM port..", 0); Application.DoEvents();
            try
            {
                //Open the port
                Port.Open();

                //Send restart packet
                // byte[] Packet = new byte[] { 0x02, 0x00, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03 };
                // Port.Write(Packet, 0, 37);

                //wait for board to restart
                // Thread.Sleep(200);

                //empty characters waiting to be dealt with
                Port.DiscardInBuffer();

            }
            catch (Exception ex) { throw new Exception(Port.PortName + " could not be opened", ex); }

            eFamily Family;

            try
            {
                Family = ReadID();
            }
            catch (Exception ex)
            {
                UpdateForm(ex.Message, 0);
                Thread.Sleep(500);
                Port.Close();
                ProgressForm.Close();
                throw new Exception("x-io board not responding on " + Port.PortName, ex);
            }

            UpdateForm("Reading source file..", 0); Application.DoEvents();

            try
            {

                ppMemory = new memRow[PM_SIZE + EE_SIZE + CM_SIZE];
                for (int Row = 0; Row < PM_SIZE; Row++)
                {
                    ppMemory[Row] = new memRow(memRow.eType.Program, 0, Row, eFamily.dsPIC33F);
                }

                for (int Row = 0; Row < EE_SIZE; Row++)
                {
                    ppMemory[Row + PM_SIZE] = new memRow(memRow.eType.EEprom, 0x7FF000, Row, eFamily.dsPIC33F);
                }

                for (int Row = 0; Row < CM_SIZE; Row++)
                {
                    ppMemory[Row + PM_SIZE + EE_SIZE] = new memRow(memRow.eType.Config, 0xF80000, Row, eFamily.dsPIC33F);
                }

                while (!SourceFile.EndOfStream)             //read the whole hex file, parse and store
                {
                    uint ByteCount = 0;
                    uint Address = 0;
                    uint RecordType = 0;

                    string aLine = SourceFile.ReadLine();

                    ByteCount = (uint)(((CharToUShort(aLine[1]) << 4) & 0xF0) | (CharToUShort(aLine[2]) & 0xF));
                    Address = (uint)(((CharToUShort(aLine[3]) << 12) & 0xF000) | ((CharToUShort(aLine[4]) << 8) & 0xF00) | ((CharToUShort(aLine[5]) << 4) & 0xF0) | (CharToUShort(aLine[6]) & 0xF));
                    RecordType = (uint)(((CharToUShort(aLine[7]) << 4) & 0xF0) | (CharToUShort(aLine[8]) & 0xF));

                    if (RecordType == 0)
                    {
                        Address = (uint)(Address + ExtAddr) / 2;

                        for (int CharCount = 0; CharCount < ByteCount * 2; CharCount += 4, Address++)
                        {
                            bool bInserted = false;

                            for (int Row = 0; Row < (PM_SIZE + EE_SIZE + CM_SIZE); Row++)
                            {
                                if ((bInserted = ppMemory[Row].InsertData(Address, aLine.Substring(9 + CharCount)) == true))
                                {
                                    break;
                                }
                            }

                            if (bInserted != true)
                            {
                                ProgressForm.Close();
                                Port.Close();
                                throw new Exception("Bad hex file: Address out of range");
                            }
                        }

                    }
                    else if (RecordType == 1)
                    {
                    }
                    else if (RecordType == 4)
                    {
                        ExtAddr = (uint)(((CharToUShort(aLine[9]) << 12) & 0xF000) | ((CharToUShort(aLine[10]) << 8) & 0xF00) | ((CharToUShort(aLine[11]) << 4) & 0xF0) | (CharToUShort(aLine[12]) & 0xF));
                        ExtAddr <<= 16;
                    }
                    else
                    {
                        //Error
                    }

                }
            }
            catch (Exception ex)
            {
                Port.Close();
                ProgressForm.Close();
                throw ex;
            }

            //Close the source HEX file
            try
            {
                SourceFile.Close();
            }
            catch { }

            //Preserve first two locations for bootloader
            {
                string Data;
                int RowSize;
                int i = 0;

                if (Family == eFamily.dsPIC30F)
                {
                    RowSize = PM30F_ROW_SIZE;
                }
                else RowSize = PM33F_ROW_SIZE;

                Buffer[0] = COMMAND_READ_PM;
                Buffer[1] = 0x00;
                Buffer[2] = 0x00;
                Buffer[3] = 0x00;

                Port.Write(Buffer, 0, 4);
                //Thread.Sleep(100);

                UpdateForm("Reading target..", 0); Application.DoEvents();

                try
                {
                    for (i = 0; i < ((RowSize * 3) - 500); i++)
                        Buffer[i] = (byte)Port.ReadByte();
                }
                catch (Exception ex)
                {
                    Port.Close();
                    ProgressForm.Close();
                    //throw new Exception("Charcount: " + i.ToString() + " out of " + Convert.ToString((RowSize * 3)) + " -- " + ex.Message);
                    throw new Exception(ex.Message + " on char: " + i.ToString() + " out of " + Convert.ToString((RowSize * 3)));
                }
                //Port.Read(Buffer,0,RowSize * 3);

                Data = String.Format("{0:x2}{1:x2}{2:x2}00{3:x2}{4:x2}{5:x2}00", Buffer[2], Buffer[1], Buffer[0], Buffer[5], Buffer[4], Buffer[3]);

                ppMemory[0].InsertData(0x000000, Data);
                ppMemory[0].InsertData(0x000001, Data.Substring(4));
                ppMemory[0].InsertData(0x000002, Data.Substring(8));
                ppMemory[0].InsertData(0x000003, Data.Substring(12));

                Port.DiscardInBuffer();
            }

            UpdateForm("Formatting data..", 0);
            for (int Row = 0; Row < (PM_SIZE + EE_SIZE + CM_SIZE); Row++) ppMemory[Row].FormatData();

            ((ProgressBar)ProgressForm.Controls[1]).Maximum = PM_SIZE + EE_SIZE + CM_SIZE;
            UpdateForm("Uploading firmware...", 0);

            /////////////////////////////////////////////////////
            while (true)
            {
                Application.DoEvents();                         //just in case something else happened, let the program deal with messages

                try
                {
                    ppMemory[LoadRow++].SendData(ref Port);
                }
                catch (Exception ex)
                {
                    Port.Close();
                    ProgressForm.Close();
                    throw ex;
                }

                UpdateForm(String.Format("Uploading firmware... {0:00.00}% done", ((double)LoadRow / (double)(PM_SIZE + EE_SIZE + CM_SIZE)) * 100), LoadRow);

                if (LoadRow >= (PM_SIZE + EE_SIZE + CM_SIZE))
                {
                    UpdateForm("Firmware update complete", LoadRow);

                    byte[] rsBuffer = new byte[] { COMMAND_RESET };
                    Port.Write(rsBuffer, 0, 1);

                    Application.DoEvents();
                    Thread.Sleep(300);
                    Port.Close();
                    ProgressForm.Close();
                    onBootloadFinished();
                    break;
                }
            }
        }