Inheritance: ICustomStartupSequenceBuilder
示例#1
0
        public static List <ProgrammableRegion> BuildProgrammableBlocksFromSettings(IDebugStartService service, IESP32Settings settings)
        {
            List <ProgrammableRegion> blocks;

            if (BuildProgrammableBlocksFromSynthesizedESPIDFVariables(service, out blocks))
            {
                //Nothing to do. Successfully built the block list.
            }
            else
            {
                bool patchBootloader = settings.PatchBootloader;
                blocks = ESP32StartupSequence.BuildFLASHImages(service.TargetPath, service.SystemDictionary, settings.FLASHSettings, patchBootloader);
            }

            if (settings.FLASHResources != null)
            {
                foreach (var r in settings.FLASHResources)
                {
                    if (r.Valid)
                    {
                        blocks.Add(r.ToProgrammableRegion(service));
                    }
                }
            }
            return(blocks);
        }
示例#2
0
        public static List <ProgrammableRegion> BuildProgrammableBlocksFromSettings(IDebugStartService service, IESP32Settings settings)
        {
            List <ProgrammableRegion> blocks;

            if (service.MCU.Configuration.TryGetValue("com.sysprogs.esp32.esptool.binaries.count", out var tmp) && int.TryParse(tmp, out var binaryCount) && binaryCount > 0)
            {
                blocks = new List <ProgrammableRegion>();
                for (int i = 0; i < binaryCount; i++)
                {
                    string fn = service.MCU.Configuration[$"com.sysprogs.esp32.esptool.binaries[{i}].path"];

                    blocks.Add(new ProgrammableRegion
                    {
                        FileName = fn,
                        Size     = File.ReadAllBytes(fn).Length,
                        Offset   = int.Parse(service.MCU.Configuration[$"com.sysprogs.esp32.esptool.binaries[{i}].address"])
                    });
                }
            }
            else
            {
                bool patchBootloader = settings.PatchBootloader;
                blocks = ESP32StartupSequence.BuildFLASHImages(service.TargetPath, service.SystemDictionary, settings.FLASHSettings, patchBootloader);
            }

            if (settings.FLASHResources != null)
            {
                foreach (var r in settings.FLASHResources)
                {
                    if (r.Valid)
                    {
                        blocks.Add(r.ToProgrammableRegion(service));
                    }
                }
            }
            return(blocks);
        }
        public IGDBStubInstance StartGDBStub(IDebugStartService startService, DebugStartContext context)
        {
            var settings = context.Configuration as ESP32GDBStubSettings;

            if (settings == null)
            {
                throw new Exception("Missing ESP32 stub settings");
            }

            int comPort;

            if (context.ResolvedDevices?.BestMatch.COMPortNumber.HasValue == true)
            {
                comPort = context.ResolvedDevices.BestMatch.COMPortNumber ?? 1;
            }
            else
            {
                if (settings.COMPort?.StartsWith("COM", StringComparison.InvariantCultureIgnoreCase) != true)
                {
                    throw new Exception("Invalid COM port specifier: " + settings.COMPort);
                }
                comPort = int.Parse(settings.COMPort.Substring(3));
            }


            var regions = ESP32StartupSequence.BuildFLASHImages(startService.TargetPath, startService.SystemDictionary, settings.FLASHSettings, settings.PatchBootloader);

            if (settings.FLASHResources != null)
            {
                foreach (var r in settings.FLASHResources)
                {
                    if (r.Valid)
                    {
                        regions.Add(r.ToProgrammableRegion(startService));
                    }
                }
            }

            foreach (var r in regions)
            {
                var pythonExe = Path.GetFullPath(context.Method.Directory + @"\..\..\..\..\bin\bash.exe");

                string args = $"python /esp32-bsp/esp-idf/components/esptool_py/esptool/esptool.py --port /dev/ttyS{comPort - 1} {settings.AdditionalToolArguments} write_flash";
                foreach (var region in regions)
                {
                    if (region.FileName.Contains(" "))
                    {
                        throw new Exception($"{region.FileName} contains spaces in path. Cannot program it using esptool.py. Please move your project to a directory without spaces.");
                    }
                    args += $" 0x{region.Offset:x} " + region.FileName.Replace('\\', '/');
                }

                var tool = startService.LaunchCommandLineTool(new CommandLineToolLaunchInfo
                {
                    Command   = pythonExe,
                    Arguments = $"--login -c \"{args}\"",
                });

                return(new GDBStubInstance(context, regions)
                {
                    Tool = tool
                });
            }

            throw new OperationCanceledException();
        }
        public static List <ProgrammableRegion> BuildFLASHImages(BSPEngine.IDebugStartService service, IESP8266Settings settings, BSPEngine.LiveMemoryLineHandler lineHandler)
        {
            var    bspDict       = service.SystemDictionary;
            var    targetPath    = service.TargetPath;
            string bspPath       = bspDict["SYS:BSP_ROOT"];
            string toolchainPath = bspDict["SYS:TOOLCHAIN_ROOT"];

            Regex rgBinFile = new Regex("^" + Path.GetFileName(targetPath) + "-0x([0-9a-fA-F]+)\\.bin$", RegexOptions.IgnoreCase);

            foreach (var fn in Directory.GetFiles(Path.GetDirectoryName(targetPath)))
            {
                if (rgBinFile.IsMatch(Path.GetFileName(fn)))
                {
                    File.Delete(fn);
                }
            }

            int initDataAddress = 0;

            if (!string.IsNullOrEmpty(settings.InitDataAddress))
            {
                initDataAddress = (int)(ESP32StartupSequence.TryParseNumber(settings.InitDataAddress) ?? 0);
            }
            else
            {
                switch (settings.FLASHSettings.Size)
                {
                case ESP8266BinaryImage.FLASHSize.size4M:
                    initDataAddress = 0x7c000;
                    break;

                case ESP8266BinaryImage.FLASHSize.size8M:
                    initDataAddress = 0xfc000;
                    break;

                case ESP8266BinaryImage.FLASHSize.size16M:
                case ESP8266BinaryImage.FLASHSize.size16M_c1:
                    initDataAddress = 0x1fc000;
                    break;

                case ESP8266BinaryImage.FLASHSize.size32M:
                case ESP8266BinaryImage.FLASHSize.size32M_c1:
                case ESP8266BinaryImage.FLASHSize.size32M_c2:
                    initDataAddress = 0x3fc000;
                    break;
                }
            }

            List <ProgrammableRegion> regions = new List <ProgrammableRegion>();

            if (initDataAddress != 0)
            {
                string initFile = settings.InitDataFile;
                if (initFile != "")
                {
                    if (initFile == null)
                    {
                        initFile = ESPxxOpenOCDSettingsEditor.DefaultInitDataFile;
                    }

                    if (initFile.StartsWith("$$SYS:BSP_ROOT$$"))
                    {
                        initFile = bspDict["SYS:BSP_ROOT"] + initFile.Substring("$$SYS:BSP_ROOT$$".Length);
                    }
                    if (!Path.IsPathRooted(initFile))
                    {
                        initFile = Path.Combine(bspDict["SYS:PROJECT_DIR"], initFile);
                    }

                    if (!File.Exists(initFile))
                    {
                        throw new Exception("Missing initialization data file: " + initFile);
                    }
                    regions.Add(new ProgrammableRegion {
                        FileName = initFile, Offset = initDataAddress, Size = File.ReadAllBytes(initFile).Length
                    });
                }
            }

            if (settings.FLASHResources != null)
            {
                foreach (var r in settings.FLASHResources)
                {
                    if (r.Valid)
                    {
                        regions.Add(r.ToProgrammableRegion(service));
                    }
                }
            }

            using (var elfFile = new ELFFile(targetPath))
            {
                string pathBase = Path.Combine(Path.GetDirectoryName(targetPath), Path.GetFileName(targetPath));
                string status;
                int    appMode = ESP8266BinaryImage.DetectAppMode(elfFile, out status);
                if (status != null && lineHandler != null)
                {
                    lineHandler(status, true);
                }

                if (appMode == 0)
                {
                    var img = ESP8266BinaryImage.MakeNonBootloaderImageFromELFFile(elfFile, settings.FLASHSettings);

                    string fn = pathBase + "-0x00000.bin";
                    using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        img.Save(fs);
                        regions.Add(new ProgrammableRegion {
                            FileName = fn, Offset = 0, Size = (int)fs.Length
                        });
                    }

                    foreach (var sec in ESP8266BinaryImage.GetFLASHSections(elfFile))
                    {
                        fn = string.Format("{0}-0x{1:x5}.bin", pathBase, sec.OffsetInFLASH);
                        using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                        {
                            fs.Write(sec.Data, 0, sec.Data.Length);
                            regions.Add(new ProgrammableRegion {
                                FileName = fn, Offset = (int)sec.OffsetInFLASH, Size = sec.Data.Length
                            });
                        }
                    }
                }
                else
                {
                    var img    = ESP8266BinaryImage.MakeBootloaderBasedImageFromELFFile(elfFile, settings.FLASHSettings, appMode);
                    var header = settings.FLASHSettings;

                    string bspRoot, bootloader;
                    if (!bspDict.TryGetValue("SYS:BSP_ROOT", out bspRoot) || !bspDict.TryGetValue("com.sysprogs.esp8266.bootloader", out bootloader))
                    {
                        throw new Exception("Cannot determine bootloader image path. Please check your BSP consistency.");
                    }

                    string fn = Path.Combine(bspRoot, bootloader);
                    if (!File.Exists(fn))
                    {
                        throw new Exception(fn + " not found. Cannot program OTA images.");
                    }

                    byte[] data = File.ReadAllBytes(fn);
                    data[2] = (byte)header.Mode;
                    data[3] = (byte)(((byte)header.Size << 4) | (byte)header.Frequency);
                    fn      = string.Format("{0}-0x00000.bin", pathBase);
                    File.WriteAllBytes(fn, data);

                    regions.Add(new ProgrammableRegion {
                        FileName = fn, Offset = 0, Size = File.ReadAllBytes(fn).Length
                    });


                    fn = string.Format("{0}-0x{1:x5}.bin", pathBase, img.BootloaderImageOffset);
                    using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        img.Save(fs);
                        regions.Add(new ProgrammableRegion {
                            FileName = fn, Offset = (int)img.BootloaderImageOffset, Size = (int)fs.Length
                        });
                    }
                }
            }

            return(regions);
        }
示例#5
0
        bool LoadFLASH(DebugStartContext context, IDebugStartService service, ISimpleGDBSession session, ESP32OpenOCDSettings settings, ESP32GDBStub stub)
        {
            string val;

            if (!service.SystemDictionary.TryGetValue("com.sysprogs.esp32.load_flash", out val) || val != "1")
            {
                //This is a RAM-only configuration
                return(session.RunGDBCommand("load").IsDone);
            }
            else
            {
                if (settings.ProgramUsingIDF)
                {
                    string bash, bashArgs;
                    if (!service.SystemDictionary.TryGetValue("com.sysprogs.esp32.esptool.bash", out bash) || !service.SystemDictionary.TryGetValue("com.sysprogs.esp32.esptool.bash_args", out bashArgs))
                    {
                        throw new Exception("ESP-IDF did not report esptool arguments");
                    }

                    if (service.SystemDictionary.TryGetValue("com.sysprogs.esp32.esptool.script", out var script) && File.Exists(script))
                    {
                        var lines = File.ReadAllLines(script).ToList();
                        int idx   = Enumerable.Range(0, lines.Count).FirstOrDefault(i => lines[i].Contains("def hard_reset(self):"));
                        if (idx > 0 && idx < (lines.Count - 1))
                        {
                            if (!lines[idx + 1].Contains("self._port.setDTR(False)"))
                            {
                                if (service.GUIService.Prompt("The esptool.py binary used in the current ESP-IDF contains known compatibility issue with Cygwin. Do you want to patch it automatically?"))
                                {
                                    Regex rgIndent = new Regex("^([ \t]*)[^ \t]");
                                    var   m        = rgIndent.Match(lines[idx + 1]);
                                    lines.Insert(idx + 1, m.Groups[1].Value + "self._port.setDTR(False)  # IO0=HIGH");
                                    File.WriteAllLines(script, lines.ToArray());
                                }
                            }
                        }
                    }

                    var tool = service.LaunchCommandLineTool(new CommandLineToolLaunchInfo
                    {
                        Command   = bash,
                        Arguments = bashArgs
                    });

                    ESP32StubDebugController.GDBStubInstance.ReportFLASHProgrammingProgress(tool, service, session);

                    string text       = tool.AllText;
                    int    validLines = text.Split('\n').Count(l => l.Trim() == "Hash of data verified.");
                    int    binCount   = 0;
                    if (service.MCU.Configuration.TryGetValue("com.sysprogs.esp32.esptool.binaries.count", out var tmp))
                    {
                        int.TryParse(tmp, out binCount);
                    }
                    binCount = 0;

                    if (validLines < binCount)
                    {
                        service.GUIService.Report("Warning: some of the FLASH regions could not be programmed. Please examine the stub output for details.", System.Windows.Forms.MessageBoxIcon.Warning);
                    }
                }
                else
                {
                    List <ProgrammableRegion> blocks;
                    if (service.MCU.Configuration.TryGetValue("com.sysprogs.esp32.esptool.binaries.count", out var tmp) && int.TryParse(tmp, out var binaryCount) && binaryCount > 0)
                    {
                        blocks = new List <ProgrammableRegion>();
                        for (int i = 0; i < binaryCount; i++)
                        {
                            string fn = service.MCU.Configuration[$"com.sysprogs.esp32.esptool.binaries[{i}].path"];

                            blocks.Add(new ProgrammableRegion
                            {
                                FileName = fn,
                                Size     = File.ReadAllBytes(fn).Length,
                                Offset   = int.Parse(service.MCU.Configuration[$"com.sysprogs.esp32.esptool.binaries[{i}].address"])
                            });
                        }
                    }
                    else
                    {
                        bool patchBootloader = (settings as IESP32Settings)?.PatchBootloader ?? false;
                        blocks = ESP32StartupSequence.BuildFLASHImages(service.TargetPath, service.SystemDictionary, settings.FLASHSettings, patchBootloader);
                    }

                    if (settings.FLASHResources != null)
                    {
                        foreach (var r in settings.FLASHResources)
                        {
                            if (r.Valid)
                            {
                                blocks.Add(r.ToProgrammableRegion(service));
                            }
                        }
                    }

                    Regex rgFLASHSize = new Regex("Auto-detected flash size ([0-9]+) KB");
                    if (settings.CheckFLASHSize)
                    {
                        var match = stub.Tool.AllText.Split('\n').Select(s => rgFLASHSize.Match(s)).FirstOrDefault(m => m.Success);
                        if (match != null)
                        {
                            int detectedSizeKB  = int.Parse(match.Groups[1].Value);
                            int specifiedSizeMB = 0;
                            switch (settings.FLASHSettings.Size)
                            {
                            case ESP8266BinaryImage.ESP32FLASHSize.size1MB:
                                specifiedSizeMB = 1;
                                break;

                            case ESP8266BinaryImage.ESP32FLASHSize.size2MB:
                                specifiedSizeMB = 2;
                                break;

                            case ESP8266BinaryImage.ESP32FLASHSize.size4MB:
                                specifiedSizeMB = 4;
                                break;

                            case ESP8266BinaryImage.ESP32FLASHSize.size8MB:
                                specifiedSizeMB = 8;
                                break;

                            case ESP8266BinaryImage.ESP32FLASHSize.size16MB:
                                specifiedSizeMB = 16;
                                break;
                            }

                            if (detectedSizeKB < (specifiedSizeMB * 1024) && detectedSizeKB >= 1024)
                            {
                                if (service.GUIService.Prompt($"The FLASH size specified via Project Properties is greater than the actual SPI FLASH size on your device. Please switch FLASH size to {detectedSizeKB / 1024}MB or less.\nDo you want to cancel FLASH programming?", System.Windows.Forms.MessageBoxIcon.Warning))
                                {
                                    throw new OperationCanceledException();
                                }
                            }
                        }
                    }

                    using (var ctx = session.CreateScopedProgressReporter("Programming FLASH...", new[] { "Programming FLASH memory" }))
                    {
                        int   blkNum        = 0;
                        Regex rgWriteXBytes = new Regex("wrote ([0-9]+) bytes from file");
                        foreach (var blk in blocks)
                        {
                            ctx.ReportTaskProgress(blkNum++, blocks.Count);
                            string path      = blk.FileName.Replace('\\', '/');
                            var    result    = session.RunGDBCommand($"mon program_esp32 \"{path}\" 0x{blk.Offset:x}");
                            bool   succeeded = result.StubOutput?.FirstOrDefault(l => l.Contains("** Programming Finished **")) != null;
                            if (!succeeded)
                            {
                                throw new Exception("FLASH programming failed. Please review the gdb/OpenOCD logs for details.");
                            }
                            var m = result.StubOutput.Select(l => rgWriteXBytes.Match(l)).FirstOrDefault(m2 => m2.Success);
                            if (m == null)
                            {
                                throw new Exception("FLASH programming did not report the amount of written bytes. Please review the gdb/OpenOCD logs for details.");
                            }
                            int bytesWritten = int.Parse(m.Groups[1].Value);
                            if (bytesWritten == 0 && blk.Size > 0)
                            {
                                throw new Exception("FLASH programming did not write any data. This is a known bug of ESP32 OpenOCD. Please restart your device and JTAG programmer and try again.");
                            }
                        }
                    }
                }
            }

            if (!session.RunGDBCommand("mon reset halt").IsDone)
            {
                throw new Exception("Failed to reset target after programming");
            }

            return(true);
        }
示例#6
0
        bool LoadFLASH(DebugStartContext context, IDebugStartService service, ISimpleGDBSession session, ESP32OpenOCDSettings settings, ESP32GDBStub stub)
        {
            string val;

            if (!service.SystemDictionary.TryGetValue("com.sysprogs.esp32.load_flash", out val) || val != "1")
            {
                //This is a RAM-only configuration
                return(session.RunGDBCommand("load").IsDone);
            }
            else
            {
                var blocks = ESP32StartupSequence.BuildFLASHImages(service.TargetPath, service.SystemDictionary, settings.FLASHSettings, (settings as IESP32Settings)?.PatchBootloader ?? false);

                if (settings.FLASHResources != null)
                {
                    foreach (var r in settings.FLASHResources)
                    {
                        if (r.Valid)
                        {
                            blocks.Add(r.ToProgrammableRegion(service));
                        }
                    }
                }

                Regex rgFLASHSize = new Regex("Auto-detected flash size ([0-9]+) KB");
                if (settings.CheckFLASHSize)
                {
                    var match = stub.Tool.AllText.Split('\n').Select(s => rgFLASHSize.Match(s)).FirstOrDefault(m => m.Success);
                    if (match != null)
                    {
                        int detectedSizeKB  = int.Parse(match.Groups[1].Value);
                        int specifiedSizeMB = 0;
                        switch (settings.FLASHSettings.Size)
                        {
                        case ESP8266BinaryImage.ESP32FLASHSize.size1MB:
                            specifiedSizeMB = 1;
                            break;

                        case ESP8266BinaryImage.ESP32FLASHSize.size2MB:
                            specifiedSizeMB = 2;
                            break;

                        case ESP8266BinaryImage.ESP32FLASHSize.size4MB:
                            specifiedSizeMB = 4;
                            break;

                        case ESP8266BinaryImage.ESP32FLASHSize.size8MB:
                            specifiedSizeMB = 8;
                            break;

                        case ESP8266BinaryImage.ESP32FLASHSize.size16MB:
                            specifiedSizeMB = 16;
                            break;
                        }

                        if (detectedSizeKB < (specifiedSizeMB * 1024) && detectedSizeKB >= 1024)
                        {
                            if (service.GUIService.Prompt($"The FLASH size specified via Project Properties is greater than the actual SPI FLASH size on your device. Please switch FLASH size to {detectedSizeKB / 1024}MB or less.\nDo you want to cancel FLASH programming?", System.Windows.Forms.MessageBoxIcon.Warning))
                            {
                                throw new OperationCanceledException();
                            }
                        }
                    }
                }

                using (var ctx = session.CreateScopedProgressReporter("Programming FLASH...", new[] { "Programming FLASH memory" }))
                {
                    int   blkNum        = 0;
                    Regex rgWriteXBytes = new Regex("wrote ([0-9]+) bytes from file");
                    foreach (var blk in blocks)
                    {
                        ctx.ReportTaskProgress(blkNum++, blocks.Count);
                        string path      = blk.FileName.Replace('\\', '/');
                        var    result    = session.RunGDBCommand($"mon program_esp32 \"{path}\" 0x{blk.Offset:x}");
                        bool   succeeded = result.StubOutput?.FirstOrDefault(l => l.Contains("** Programming Finished **")) != null;
                        if (!succeeded)
                        {
                            throw new Exception("FLASH programming failed. Please review the gdb/OpenOCD logs for details.");
                        }
                        var m = result.StubOutput.Select(l => rgWriteXBytes.Match(l)).FirstOrDefault(m2 => m2.Success);
                        if (m == null)
                        {
                            throw new Exception("FLASH programming did not report the amount of written bytes. Please review the gdb/OpenOCD logs for details.");
                        }
                        int bytesWritten = int.Parse(m.Groups[1].Value);
                        if (bytesWritten == 0 && blk.Size > 0)
                        {
                            throw new Exception("FLASH programming did not write any data. This is a known bug of ESP32 OpenOCD. Please restart your device and JTAG programmer and try again.");
                        }
                    }
                }
            }

            if (!session.RunGDBCommand("mon reset halt").IsDone)
            {
                throw new Exception("Failed to reset target after programming");
            }

            return(true);
        }