Exemplo n.º 1
0
        public static ESP8266BinaryImage MakeBootloaderBasedImageFromELFFile(ELFFile file, ParsedHeader header, int appNumber, bool esptoolSectionOrder = false)
        {
            ESP8266BinaryImage image = new ESP8266BinaryImage();

            image.EntryPoint = file.ELFHeader.e_entry;
            image.Header     = header;

            var flashSections = GetFLASHSections(file);

            if (flashSections.Length != 1)
            {
                throw new Exception($"Unexpected count of SPI FLASH sections: {flashSections.Length}. Cannot detect image type");
            }

            int newSize = ((flashSections[0].Data.Length + 15) & ~15);

            Array.Resize(ref flashSections[0].Data, newSize);

            image.Segments.Add(new Segment {
                Address = 0, Data = flashSections[0].Data
            });
            image.BootloaderImageOffset = flashSections[0].OffsetInFLASH - BootloaderImageHeaderSize;
            image.AppNumber             = (byte)appNumber;

            InsertSections(file, esptoolSectionOrder, image, true);
            return(image);
        }
Exemplo n.º 2
0
        public static int DetectAppMode(ELFFile elfFile, out string status)
        {
            var flashSections = GetFLASHSections(elfFile);

            if (flashSections.Length != 1)
            {
                status = $"Unexpected number of SPI FLASH sections: {flashSections.Length}. Assuming this is not an OTA layout.";
                return(0);
            }
            else if ((flashSections[0].OffsetInFLASH & 0x1FFF) == 0)
            {
                status = string.Format("Found an SPI FLASH section at 0x{0:x8}. This image is a non-OTA image.", flashSections[0].OffsetInFLASH);
                return(0);
            }
            else
            {
                int appMode;
                if (flashSections[0].OffsetInFLASH == 0x1010)
                {
                    appMode = 1;
                }
                else
                {
                    appMode = 2;
                }

                status = string.Format("Found an SPI FLASH section at 0x{0:x8}. This image is an APP{1} image.", flashSections[0].OffsetInFLASH, appMode);
                return(appMode);
            }
        }
Exemplo n.º 3
0
        public static ESP8266BinaryImage MakeNonBootloaderImageFromELFFile(ELFFile file, ParsedHeader header, bool esptoolSectionOrder = false)
        {
            ESP8266BinaryImage image = new ESP8266BinaryImage();

            image.EntryPoint = file.ELFHeader.e_entry;
            image.Header     = header;
            InsertSections(file, esptoolSectionOrder, image, true);
            return(image);
        }
Exemplo n.º 4
0
        public static ESP8266BinaryImage MakeESP32ImageFromELFFile(ELFFile file, ParsedHeader header)
        {
            ESP8266BinaryImage image = new ESP8266BinaryImage(true);

            image.EntryPoint = file.ELFHeader.e_entry;
            image.Header     = header;
            InsertSections(file, false, image, false);
            return(image);
        }
Exemplo n.º 5
0
        public static SPIFLASHSection[] GetFLASHSections(ELFFile file)
        {
            List <SPIFLASHSection> sections = new List <SPIFLASHSection>();

            foreach (var sec in file.AllSections)
            {
                if (sec.VirtualAddress >= SPIFLASHBase && sec.VirtualAddress < SPIFLASHLimit)
                {
                    sections.Add(new SPIFLASHSection {
                        OffsetInFLASH = sec.VirtualAddress - SPIFLASHBase, Data = file.LoadSection(sec)
                    });
                }
            }
            return(sections.ToArray());
        }
Exemplo n.º 6
0
        private static void InsertSections(ELFFile file, bool esptoolSectionOrder, ESP8266BinaryImage image, bool ramSectionsOnly)
        {
            List <ELFFile.ParsedSection> sections = new List <ELFFile.ParsedSection>();

            if (esptoolSectionOrder)
            {
                foreach (var secN in new string[] { ".text", ".data", ".rodata" })
                {
                    sections.Add(file.FindSectionByName(secN));
                }
            }
            else
            {
                sections = file.AllSections;
            }

            foreach (var sec in sections)
            {
                if (!sec.HasData || !sec.PresentInMemory)
                {
                    if (sec.SectionName != ".rtc.text")
                    {
                        continue;
                    }
                }

                if (!ramSectionsOnly || (sec.VirtualAddress < SPIFLASHBase))
                {
                    var segment = new Segment {
                        Address = sec.VirtualAddress, Data = file.LoadSection(sec), Hint = sec.SectionName
                    };
                    int align = ((segment.Data.Length + 3) & ~3) - segment.Data.Length;
                    if (align > 0)
                    {
                        Array.Resize(ref segment.Data, segment.Data.Length + align);
                    }
                    image.Segments.Add(segment);
                }
            }
        }
Exemplo n.º 7
0
        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);
        }
Exemplo n.º 8
0
        public static CustomStartupSequence BuildSequence(BSPEngine.IDebugStartService service, ESP8266OpenOCDSettings settings, BSPEngine.LiveMemoryLineHandler lineHandler, bool programFLASH)
        {
            List <CustomStartStep> cmds = new List <CustomStartStep>();

            cmds.Add(new CustomStartStep("mon reset halt",
                                         "-exec-next-instruction",
                                         "set $com_sysprogs_esp8266_wdcfg=0",
                                         "set $vecbase=0x40000000",
                                         "$$com.sysprogs.esp8266.interrupt_disable_command$$",
                                         "set $ccompare=0",
                                         "set $intclear=-1",
                                         "set $intenable=0",
                                         "set $eps2=0x20",
                                         "set $icountlevel=0"));

            var result = new CustomStartupSequence {
                Steps = cmds
            };
            var bspDict    = service.SystemDictionary;
            var targetPath = service.TargetPath;

            string val;

            if (bspDict.TryGetValue("com.sysprogs.esp8266.load_flash", out val) && val == "1")  //Not a FLASHless project
            {
                if (programFLASH)
                {
                    string bspPath = bspDict["SYS:BSP_ROOT"];
                    List <ProgrammableRegion> regions = BuildFLASHImages(service, settings, lineHandler);

                    string loader = bspPath + @"\sysprogs\flashprog\ESP8266FlashProg.bin";
                    if (!File.Exists(loader))
                    {
                        throw new Exception("FLASH loader not found: " + loader);
                    }

                    var parsedLoader = new ParsedFLASHLoader(loader);

                    cmds.Add(new CustomStartStep("print *((int *)0x60000900)", "set *((int *)0x60000900)=0"));
                    cmds.Add(parsedLoader.QueueInvocation(0, settings.ProgramSectorSize.ToString(), settings.EraseSectorSize.ToString(), null, 0, 0, true));
                    foreach (var region in regions)
                    {
                        parsedLoader.QueueRegionProgramming(cmds, region);
                    }
                }

                var resetMode = settings.ResetMode;
                if (resetMode == ResetMode.Soft)
                {
                    try
                    {
                        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 (appMode != 0)
                            {
                                if (service.GUIService.Prompt("The soft reset mechanism is not compatible with the OTA images. Use the jump-to-entry reset instead?"))
                                {
                                    resetMode = ResetMode.Hard;
                                }
                            }
                        }
                    }
                    catch
                    {
                    }
                }

                if (resetMode == ResetMode.Soft || resetMode == ResetMode.JumpToEntry)
                {
                    string entry = "0x40000080";

                    if (resetMode == ResetMode.JumpToEntry)
                    {
                        using (ELFFile elf = new ELFFile(targetPath))
                        {
                            foreach (var sec in elf.AllSections)
                            {
                                if (!sec.PresentInMemory || !sec.HasData || sec.Type != ELFFile.SectionType.SHT_PROGBITS)
                                {
                                    continue;
                                }

                                bool isInRAM = false;
                                if (sec.VirtualAddress >= 0x3FFE8000 && sec.VirtualAddress < (0x3FFE8000 + 81920))
                                {
                                    isInRAM = true;
                                }
                                else if (sec.VirtualAddress >= 0x40100000 && sec.VirtualAddress <= (0x40100000 + 32768))
                                {
                                    isInRAM = true;
                                }

                                if (isInRAM)
                                {
                                    cmds.Add(new CustomStartStep(string.Format("restore {0} binary 0x{1:x} 0x{2:x} 0x{3:x}", targetPath.Replace('\\', '/'),
                                                                               sec.VirtualAddress - sec.OffsetInFile, sec.OffsetInFile, sec.OffsetInFile + sec.Size))
                                    {
                                        CheckResult = true, ErrorMessage = "Failed to program the " + sec.SectionName + " section"
                                    });
                                }
                            }
                        }

                        entry = "$$DEBUG:ENTRY_POINT$$";
                    }

                    cmds.Add(new CustomStartStep("set $ps=0x20",
                                                 "set $epc2=" + entry,
                                                 "set $sp=$$DEBUG:INITIAL_STACK_POINTER$$",
                                                 "set $vecbase=0x40000000",
                                                 "$$com.sysprogs.esp8266.interrupt_disable_command$$",
                                                 "set $intclear=-1",
                                                 "set $intenable=0",
                                                 "set $eps2=0x20",
                                                 "set $icountlevel=0"));
                    result.InitialHardBreakpointExpression = "*$$DEBUG:ENTRY_POINT$$";
                }
                else
                {
                    cmds.Add(new CustomStartStep("mon reset halt"));
                }
            }
            else
            {
                cmds.Add(new CustomStartStep("load",
                                             "set $ps=0x20",
                                             "set $epc2=$$DEBUG:ENTRY_POINT$$",
                                             "set $sp=$$DEBUG:INITIAL_STACK_POINTER$$",
                                             "set $vecbase=0x40000000",
                                             "$$com.sysprogs.esp8266.interrupt_disable_command$$",
                                             "set $ccompare=0",
                                             "set $intclear=-1",
                                             "set $intenable=0",
                                             "set $eps2=0x20",
                                             "set $icountlevel=0"));
            }

            return(result);
        }
Exemplo n.º 9
0
        public static List <ProgrammableRegion> BuildFLASHImages(string targetPath, Dictionary <string, string> bspDict, Dictionary <string, string> debugMethodConfig, LiveMemoryLineHandler lineHandler)
        {
            string bspPath       = bspDict["SYS:BSP_ROOT"];
            string toolchainPath = bspDict["SYS:TOOLCHAIN_ROOT"];

            string freq, mode, size;

            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_freq", out freq);
            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_mode", out mode);
            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_size", out size);

            string partitionTable, bootloader, txtAppOffset;

            bspDict.TryGetValue("com.sysprogs.esp32.partition_table_file", out partitionTable);
            bspDict.TryGetValue("com.sysprogs.esp32.bootloader_file", out bootloader);
            bspDict.TryGetValue("com.sysprogs.esp32.app_offset", out txtAppOffset);

            uint appOffset;

            if (txtAppOffset == null)
            {
                appOffset = 0;
            }
            else if (txtAppOffset.StartsWith("0x"))
            {
                uint.TryParse(txtAppOffset.Substring(2), NumberStyles.HexNumber, null, out appOffset);
            }
            else
            {
                uint.TryParse(txtAppOffset, out appOffset);
            }

            if (appOffset == 0)
            {
                throw new Exception("Application FLASH offset not defined. Please check your settings.");
            }

            partitionTable = VariableHelper.ExpandVariables(partitionTable, bspDict, debugMethodConfig);
            bootloader     = VariableHelper.ExpandVariables(bootloader, bspDict, debugMethodConfig);

            if (!string.IsNullOrEmpty(partitionTable) && !Path.IsPathRooted(partitionTable))
            {
                partitionTable = Path.Combine(bspDict["SYS:PROJECT_DIR"], partitionTable);
            }
            if (!string.IsNullOrEmpty(bootloader) && !Path.IsPathRooted(bootloader))
            {
                bootloader = Path.Combine(bspDict["SYS:PROJECT_DIR"], bootloader);
            }

            if (string.IsNullOrEmpty(partitionTable) || !File.Exists(partitionTable))
            {
                throw new Exception("Unspecified or missing partition table file: " + partitionTable);
            }
            if (string.IsNullOrEmpty(bootloader) || !File.Exists(bootloader))
            {
                throw new Exception("Unspecified or missing bootloader file: " + bootloader);
            }

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

            using (var elfFile = new ELFFile(targetPath))
            {
                string pathBase = Path.Combine(Path.GetDirectoryName(targetPath), Path.GetFileName(targetPath));

                var img = ESP8266BinaryImage.MakeESP32ImageFromELFFile(elfFile, new ESP8266BinaryImage.ParsedHeader(freq, mode, size));

                //Bootloader/partition table offsets are hardcoded in ESP-IDF
                regions.Add(new ProgrammableRegion {
                    FileName = bootloader, Offset = 0x1000, Size = GetFileSize(bootloader)
                });
                regions.Add(new ProgrammableRegion {
                    FileName = partitionTable, Offset = 0x8000, Size = GetFileSize(partitionTable)
                });

                string fn = pathBase + "-esp32.bin";
                using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    img.Save(fs);
                    regions.Add(new ProgrammableRegion {
                        FileName = fn, Offset = (int)appOffset, Size = (int)fs.Length
                    });
                }
            }
            return(regions);
        }
Exemplo n.º 10
0
            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.");
                        }
                    }
                }
            }
Exemplo n.º 11
0
        public static List <ProgrammableRegion> BuildFLASHImages(string targetPath, Dictionary <string, string> bspDict, ESP8266BinaryImage.ESP32ImageHeader flashSettings, bool patchBootloader)
        {
            string bspPath       = bspDict["SYS:BSP_ROOT"];
            string toolchainPath = bspDict["SYS:TOOLCHAIN_ROOT"];

            string partitionTable, bootloader, txtAppOffset;

            bspDict.TryGetValue("com.sysprogs.esp32.partition_table_file", out partitionTable);
            bspDict.TryGetValue("com.sysprogs.esp32.bootloader_file", out bootloader);
            bspDict.TryGetValue("com.sysprogs.esp32.app_offset", out txtAppOffset);

            uint appOffset;

            if (txtAppOffset == null)
            {
                appOffset = 0;
            }
            else if (txtAppOffset.StartsWith("0x"))
            {
                uint.TryParse(txtAppOffset.Substring(2), NumberStyles.HexNumber, null, out appOffset);
            }
            else
            {
                uint.TryParse(txtAppOffset, out appOffset);
            }

            if (appOffset == 0)
            {
                throw new Exception("Application FLASH offset not defined. Please check your settings.");
            }

            partitionTable = VariableHelper.ExpandVariables(partitionTable, bspDict);
            bootloader     = VariableHelper.ExpandVariables(bootloader, bspDict);

            if (!string.IsNullOrEmpty(partitionTable) && !Path.IsPathRooted(partitionTable))
            {
                partitionTable = Path.Combine(bspDict["SYS:PROJECT_DIR"], partitionTable);
            }
            if (!string.IsNullOrEmpty(bootloader) && !Path.IsPathRooted(bootloader))
            {
                bootloader = Path.Combine(bspDict["SYS:PROJECT_DIR"], bootloader);
            }

            if (string.IsNullOrEmpty(partitionTable) || !File.Exists(partitionTable))
            {
                throw new Exception("Unspecified or missing partition table file: " + partitionTable);
            }
            if (string.IsNullOrEmpty(bootloader) || !File.Exists(bootloader))
            {
                throw new Exception("Unspecified or missing bootloader file: " + bootloader);
            }

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

            using (var elfFile = new ELFFile(targetPath))
            {
                string pathBase = Path.Combine(Path.GetDirectoryName(targetPath), Path.GetFileName(targetPath));

                var img = ESP8266BinaryImage.MakeESP32ImageFromELFFile(elfFile, flashSettings);

                //Bootloader/partition table offsets are hardcoded in ESP-IDF

                var bootloaderCopy     = pathBase + "-bootloader.bin";
                var bootloaderContents = File.ReadAllBytes(bootloader);

                if (patchBootloader)
                {
                    if (bootloaderContents.Length < 16)
                    {
                        throw new Exception("Bootloader image too small: " + bootloader);
                    }

                    if (bootloaderContents[0] != 0xe9)
                    {
                        throw new Exception("Invalid ESP32 bootloader signature in  " + bootloader);
                    }

                    bootloaderContents[2] = (byte)flashSettings.Mode;
                    bootloaderContents[3] = (byte)(((byte)flashSettings.Size << 4) | (byte)flashSettings.Frequency);
                }

                File.WriteAllBytes(bootloaderCopy, bootloaderContents);

                regions.Add(new ProgrammableRegion {
                    FileName = bootloaderCopy, Offset = 0x1000, Size = bootloaderContents.Length
                });
                regions.Add(new ProgrammableRegion {
                    FileName = partitionTable, Offset = 0x8000, Size = GetFileSize(partitionTable)
                });

                string fn = pathBase + "-esp32.bin";
                using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    img.Save(fs);
                    regions.Add(new ProgrammableRegion {
                        FileName = fn, Offset = (int)appOffset, Size = (int)fs.Length
                    });
                }
            }
            return(regions);
        }
Exemplo n.º 12
0
        public static List <ProgrammableRegion> BuildFLASHImages(string targetPath, Dictionary <string, string> bspDict, Dictionary <string, string> debugMethodConfig, LiveMemoryLineHandler lineHandler)
        {
            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);
                }
            }

            string freq, mode, size;

            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_freq", out freq);
            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_mode", out mode);
            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_size", out size);

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

            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, new ESP8266BinaryImage.ParsedHeader(freq, mode, size));

                    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, new ESP8266BinaryImage.ParsedHeader(freq, mode, size), appMode);

                    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)img.Header.Mode;
                    data[3] = (byte)(((byte)img.Header.Size << 4) | (byte)img.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);
        }
Exemplo n.º 13
0
        public CustomStartupSequence BuildSequence(string targetPath, Dictionary <string, string> bspDict, Dictionary <string, string> debugMethodConfig, LiveMemoryLineHandler lineHandler)
        {
            bool isOpenOCD = debugMethodConfig.ContainsKey("com.sysprogs.esp8266.openocd.iface_script");

            List <CustomStartStep> cmds = new List <CustomStartStep>();

            cmds.Add(new CustomStartStep(isOpenOCD ? "mon reset halt" : "maint packet R",
                                         "-exec-next-instruction",
                                         "set $com_sysprogs_esp8266_wdcfg=0",
                                         "set $vecbase=0x40000000",
                                         "$$com.sysprogs.esp8266.interrupt_disable_command$$",
                                         "set $ccompare=0",
                                         "set $intclear=-1",
                                         "set $intenable=0",
                                         "set $eps2=0x20",
                                         "set $icountlevel=0"));

            var result = new CustomStartupSequence {
                Steps = cmds
            };

            string val;

            if (bspDict.TryGetValue("com.sysprogs.esp8266.load_flash", out val) && val == "1")  //Not a FLASHless project
            {
                if (debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.program_flash", out val) && val != "0")
                {
                    string bspPath = bspDict["SYS:BSP_ROOT"];
                    List <ProgrammableRegion> regions = BuildFLASHImages(targetPath, bspDict, debugMethodConfig, lineHandler);

                    string loader = bspPath + @"\sysprogs\flashprog\ESP8266FlashProg.bin";
                    if (!File.Exists(loader))
                    {
                        throw new Exception("FLASH loader not found: " + loader);
                    }

                    var parsedLoader = new ParsedFLASHLoader(loader);

                    cmds.Add(new CustomStartStep("print *((int *)0x60000900)", "set *((int *)0x60000900)=0"));
                    cmds.Add(parsedLoader.QueueInvocation(0, "$$com.sysprogs.esp8266.xt-ocd.prog_sector_size$$", "$$com.sysprogs.esp8266.xt-ocd.erase_sector_size$$", null, 0, 0, true));
                    foreach (var region in regions)
                    {
                        parsedLoader.QueueRegionProgramming(cmds, region);
                    }
                }

                if (!debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_start_mode", out val))
                {
                    val = "soft_reset";
                }

                if (val == "soft_reset")
                {
                    try
                    {
                        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 (appMode != 0)
                            {
                                if (System.Windows.Forms.MessageBox.Show("The soft reset mechanism is not compatible with the OTA images. Use the jump-to-entry reset instead?", "VisualGDB", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.Yes)
                                {
                                    val = "entry_point";
                                }
                            }
                        }
                    }
                    catch
                    {
                    }
                }

                if (val == "soft_reset" || val == "entry_point")
                {
                    string entry = "0x40000080";

                    if (val == "entry_point")
                    {
                        using (ELFFile elf = new ELFFile(targetPath))
                        {
                            foreach (var sec in elf.AllSections)
                            {
                                if (!sec.PresentInMemory || !sec.HasData || sec.Type != ELFFile.SectionType.SHT_PROGBITS)
                                {
                                    continue;
                                }

                                bool isInRAM = false;
                                if (sec.VirtualAddress >= 0x3FFE8000 && sec.VirtualAddress < (0x3FFE8000 + 81920))
                                {
                                    isInRAM = true;
                                }
                                else if (sec.VirtualAddress >= 0x40100000 && sec.VirtualAddress <= (0x40100000 + 32768))
                                {
                                    isInRAM = true;
                                }

                                if (isInRAM)
                                {
                                    cmds.Add(new CustomStartStep(string.Format("restore {0} binary 0x{1:x} 0x{2:x} 0x{3:x}", targetPath.Replace('\\', '/'),
                                                                               sec.VirtualAddress - sec.OffsetInFile, sec.OffsetInFile, sec.OffsetInFile + sec.Size))
                                    {
                                        CheckResult = true, ErrorMessage = "Failed to program the " + sec.SectionName + " section"
                                    });
                                }
                            }
                        }

                        entry = "$$DEBUG:ENTRY_POINT$$";
                    }

                    cmds.Add(new CustomStartStep("set $ps=0x20",
                                                 "set $epc2=" + entry,
                                                 "set $sp=$$DEBUG:INITIAL_STACK_POINTER$$",
                                                 "set $vecbase=0x40000000",
                                                 "$$com.sysprogs.esp8266.interrupt_disable_command$$",
                                                 "set $intclear=-1",
                                                 "set $intenable=0",
                                                 "set $eps2=0x20",
                                                 "set $icountlevel=0"));
                    result.InitialHardBreakpointExpression = "*$$DEBUG:ENTRY_POINT$$";
                }
                else
                {
                    cmds.Add(new CustomStartStep(isOpenOCD ? "mon reset halt" : "maint packet R"));
                }
            }
            else
            {
                cmds.Add(new CustomStartStep("load",
                                             "set $ps=0x20",
                                             "set $epc2=$$DEBUG:ENTRY_POINT$$",
                                             "set $sp=$$DEBUG:INITIAL_STACK_POINTER$$",
                                             "set $vecbase=0x40000000",
                                             "$$com.sysprogs.esp8266.interrupt_disable_command$$",
                                             "set $ccompare=0",
                                             "set $intclear=-1",
                                             "set $intenable=0",
                                             "set $eps2=0x20",
                                             "set $icountlevel=0"));
            }

            return(result);
        }
Exemplo n.º 14
0
            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$$"),
                    }
                });
            }