public CustomStartupSequence BuildSequence(string targetPath, Dictionary<string, string> bspDict, Dictionary<string, string> debugMethodConfig, LiveMemoryLineHandler lineHandler)
            {
                if (!File.Exists(targetPath))
                    throw new Exception(targetPath + " not found. Debugging will not be possible.");

                bool stubFound = false;
                using (var elf = new ELFFile(targetPath))
                {
                    foreach (var sym in elf.LoadAllSymbols())
                    {
                        if (sym.Name == "gdbstub_init")
                        {
                            stubFound = true;
                            break;
                        }
                    }
                }

                if (!stubFound)
                {
                    var wrp = new ResultWrapper();
                    _SyncContext.Send(o => ((ResultWrapper)o).Result = MessageBox.Show("The programmed image does not contain the GDB stub. Do you want to open instructions on debugging with ESP8266 GDB stub?", "VisualGDB", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information), wrp);
                    switch(wrp.Result)
                    {
                        case DialogResult.Yes:
                            Process.Start("http://visualgdb.com/KB/esp8266gdbstub");
                            goto case DialogResult.Cancel;
                        case DialogResult.No:
                            break;
                        case DialogResult.Cancel:
                            throw new OperationCanceledException();
                    }
                }

                string val;
                if (!debugMethodConfig.TryGetValue("com.sysprogs.esp8266.program_flash", out val) || val != "0")
                {
                    var wrp = new ResultWrapper();
                    _SyncContext.Send(o => ((ResultWrapper)o).Result = MessageBox.Show("Please reboot your ESP8266 into the bootloader mode and press OK.", "VisualGDB", MessageBoxButtons.OKCancel, MessageBoxIcon.Information), wrp);
                    if (wrp.Result != DialogResult.OK)
                        throw new OperationCanceledException();

                    using (var serialPort = new SerialPortStream(debugMethodConfig["com.sysprogs.esp8266.gdbstub.com_port"], int.Parse(debugMethodConfig["com.sysprogs.esp8266.gdbstub.bl_baud"]), System.IO.Ports.Handshake.None))
                    {
                        serialPort.AllowTimingOutWithZeroBytes = true;
                        int resetDelay;
                        if (!debugMethodConfig.TryGetValue("com.sysprogs.esp8266.reset_delay", out val) || !int.TryParse(val, out resetDelay))
                            resetDelay = 25;

                        string seq;
                        debugMethodConfig.TryGetValue("com.sysprogs.esp8266.gdbstub.reset_sequence", out seq);
                        ESP8266BootloaderClient client = new ESP8266BootloaderClient(serialPort, resetDelay, seq);
                        client.Sync();
                        var regions = ESP8266StartupSequence.BuildFLASHImages(targetPath, bspDict, debugMethodConfig, lineHandler);

                        ProgramProgressForm frm = null;
                        _SyncContext.Post(o => { frm = new ProgramProgressForm(); frm.ShowDialog(); }, null);
                        int totalSize = 0;
                        foreach (var r in regions)
                            totalSize += r.Size;

                        ESP8266BootloaderClient.BlockWrittenHandler handler = (s, a, len) => frm.UpdateProgressAndThrowIfCanceled(a, len, totalSize);
                        bool useDIO = false;

                        try
                        {
                            client.BlockWritten += handler;
                            foreach (var r in regions)
                            {
                                var data = File.ReadAllBytes(r.FileName);
                                if (r.Offset == 0 && data.Length >= 4)
                                    useDIO = (data[2] == 2);

                                client.ProgramFLASH((uint)r.Offset, data);
                            }
                        }
                        finally
                        {
                            client.BlockWritten -= handler;
                            _SyncContext.Post(o => { frm.Close(); frm.Dispose(); }, null);
                        }

                        client.RunProgram(useDIO, false);
                    }
                }

                string tmp = null;
                if (debugMethodConfig?.TryGetValue("SYS:PROGRAM_WITHOUT_DEBUGGING", out tmp) == true && tmp == "1")
                    return null;    //Suppress connecting to gdb

                return new CustomStartupSequence
                {
                    Steps = new List<CustomStartStep> {
                        new CustomStartStep("set serial baud $$com.sysprogs.esp8266.gdbstub.baud$$"),
                        new CustomStartStep(@"target remote \\.\$$com.sysprogs.esp8266.gdbstub.com_port$$"),
                    }
                };
            }
            static void DoConnect(IDebugStartService service, ISimpleGDBSession session, ESP8266GDBStubSettings settings, string comPort, bool programFLASH)
            {
                var targetPath = service.TargetPath;

                if (targetPath != null) //When doing connection test without an active project, the targetPath will be NULL
                {
                    if (!File.Exists(targetPath))
                    {
                        throw new Exception(targetPath + " not found. Debugging will not be possible.");
                    }

                    bool stubFound = false;
                    using (var elf = new ELFFile(targetPath))
                    {
                        foreach (var sym in elf.LoadAllSymbols())
                        {
                            if (sym.Name == "gdbstub_init")
                            {
                                stubFound = true;
                                break;
                            }
                        }
                    }


                    if (!stubFound)
                    {
                        if (service.GUIService.Prompt("The programmed image does not contain the GDB stub. Do you want to open instructions on debugging with ESP8266 GDB stub?", MessageBoxIcon.Warning))
                        {
                            Process.Start("http://visualgdb.com/KB/esp8266gdbstub");
                            throw new OperationCanceledException();
                        }
                    }
                }

                List <string> steps = new List <string>();

                if (programFLASH)
                {
                    steps.Add("Connecting to bootloader");
                    steps.Add("Programming FLASH memory");
                }
                if (service.Mode != EmbeddedDebugMode.ProgramWithoutDebugging)
                {
                    steps.Add("Connecting to GDB stub");
                }

                using (var ctx = session.CreateScopedProgressReporter("Connecting to target device", steps.ToArray()))
                {
                    if (programFLASH)
                    {
                        if (!settings.SuppressResetConfirmation)
                        {
                            service.GUIService.Report("Please reboot your ESP8266 into the bootloader mode and press OK.");
                        }

                        using (var serialPort = new SerialPortStream(comPort, settings.BootloaderBaudRate, System.IO.Ports.Handshake.None))
                        {
                            serialPort.AllowTimingOutWithZeroBytes = true;

                            ESP8266BootloaderClient client = new ESP8266BootloaderClient(serialPort, settings.BootloaderResetDelay, settings.BootloaderActivationSequence);
                            client.Sync();
                            var regions = ESP8266StartupSequence.BuildFLASHImages(service, settings, (l, t) => session.SendInformationalOutput(l));

                            ctx.ReportTaskCompletion(true);

                            int totalSize = 0, writtenSize = 0;
                            foreach (var r in regions)
                            {
                                totalSize += r.Size;
                            }

                            ESP8266BootloaderClient.BlockWrittenHandler handler = (s, addr, len) => ctx.ReportTaskProgress(writtenSize += len, totalSize, $"Writing FLASH at 0x{addr:x8}...");
                            bool useDIO = false;

                            try
                            {
                                client.BlockWritten += handler;
                                foreach (var r in regions)
                                {
                                    var data = File.ReadAllBytes(r.FileName);
                                    if (r.Offset == 0 && data.Length >= 4)
                                    {
                                        useDIO = (data[2] == 2);
                                    }

                                    client.ProgramFLASH((uint)r.Offset, data);
                                }
                            }
                            finally
                            {
                                client.BlockWritten -= handler;
                            }

                            client.RunProgram(useDIO, false);
                        }
                    }

                    ctx.ReportTaskCompletion(true);

                    if (service.Mode != EmbeddedDebugMode.ProgramWithoutDebugging)
                    {
                        ctx.ReportTaskCompletion(true);
                        session.RunGDBCommand("set serial baud " + settings.StubBaudRate);
                        var result = session.RunGDBCommand(@"target remote \\.\" + comPort);
                        if (!result.IsDone)
                        {
                            throw new Exception("Failed to connect to the gdb stub. Please check your settings.");
                        }
                    }
                }
            }
            public CustomStartupSequence BuildSequence(string targetPath, Dictionary <string, string> bspDict, Dictionary <string, string> debugMethodConfig, LiveMemoryLineHandler lineHandler)
            {
                if (!File.Exists(targetPath))
                {
                    throw new Exception(targetPath + " not found. Debugging will not be possible.");
                }

                bool stubFound = false;

                using (var elf = new ELFFile(targetPath))
                {
                    foreach (var sym in elf.LoadAllSymbols())
                    {
                        if (sym.Name == "gdbstub_init")
                        {
                            stubFound = true;
                            break;
                        }
                    }
                }

                if (!stubFound)
                {
                    var wrp = new ResultWrapper();
                    _SyncContext.Send(o => ((ResultWrapper)o).Result = MessageBox.Show("The programmed image does not contain the GDB stub. Do you want to open instructions on debugging with ESP8266 GDB stub?", "VisualGDB", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information), wrp);
                    switch (wrp.Result)
                    {
                    case DialogResult.Yes:
                        Process.Start("http://visualgdb.com/KB/esp8266gdbstub");
                        goto case DialogResult.Cancel;

                    case DialogResult.No:
                        break;

                    case DialogResult.Cancel:
                        throw new OperationCanceledException();
                    }
                }

                string val;

                if (!debugMethodConfig.TryGetValue("com.sysprogs.esp8266.program_flash", out val) || val != "0")
                {
                    var wrp = new ResultWrapper();
                    _SyncContext.Send(o => ((ResultWrapper)o).Result = MessageBox.Show("Please reboot your ESP8266 into the bootloader mode and press OK.", "VisualGDB", MessageBoxButtons.OKCancel, MessageBoxIcon.Information), wrp);
                    if (wrp.Result != DialogResult.OK)
                    {
                        throw new OperationCanceledException();
                    }

                    using (var serialPort = new SerialPortStream(debugMethodConfig["com.sysprogs.esp8266.gdbstub.com_port"], int.Parse(debugMethodConfig["com.sysprogs.esp8266.gdbstub.bl_baud"]), System.IO.Ports.Handshake.None))
                    {
                        serialPort.AllowTimingOutWithZeroBytes = true;
                        int resetDelay;
                        if (!debugMethodConfig.TryGetValue("com.sysprogs.esp8266.reset_delay", out val) || !int.TryParse(val, out resetDelay))
                        {
                            resetDelay = 25;
                        }

                        string seq;
                        debugMethodConfig.TryGetValue("com.sysprogs.esp8266.gdbstub.reset_sequence", out seq);
                        ESP8266BootloaderClient client = new ESP8266BootloaderClient(serialPort, resetDelay, seq);
                        client.Sync();
                        var regions = ESP8266StartupSequence.BuildFLASHImages(targetPath, bspDict, debugMethodConfig, lineHandler);

                        ProgramProgressForm frm = null;
                        _SyncContext.Post(o => { frm = new ProgramProgressForm(); frm.ShowDialog(); }, null);
                        int totalSize = 0;
                        foreach (var r in regions)
                        {
                            totalSize += r.Size;
                        }

                        ESP8266BootloaderClient.BlockWrittenHandler handler = (s, a, len) => frm.UpdateProgressAndThrowIfCanceled(a, len, totalSize);
                        bool useDIO = false;

                        try
                        {
                            client.BlockWritten += handler;
                            foreach (var r in regions)
                            {
                                var data = File.ReadAllBytes(r.FileName);
                                if (r.Offset == 0 && data.Length >= 4)
                                {
                                    useDIO = (data[2] == 2);
                                }

                                client.ProgramFLASH((uint)r.Offset, data);
                            }
                        }
                        finally
                        {
                            client.BlockWritten -= handler;
                            _SyncContext.Post(o => { frm.Close(); frm.Dispose(); }, null);
                        }

                        client.RunProgram(useDIO, false);
                    }
                }

                string tmp = null;

                if (debugMethodConfig?.TryGetValue("SYS:PROGRAM_WITHOUT_DEBUGGING", out tmp) == true && tmp == "1")
                {
                    return(null);    //Suppress connecting to gdb
                }
                return(new CustomStartupSequence
                {
                    Steps = new List <CustomStartStep> {
                        new CustomStartStep("set serial baud $$com.sysprogs.esp8266.gdbstub.baud$$"),
                        new CustomStartStep(@"target remote \\.\$$com.sysprogs.esp8266.gdbstub.com_port$$"),
                    }
                });
            }