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); }
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); } }
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); }
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); }
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()); }
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); } } }
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); }
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); }
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); }
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 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); }
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); }
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); }
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$$"), } }); }