diff --git a/nanoFirmwareFlasher.Library/JLinkCli.cs b/nanoFirmwareFlasher.Library/JLinkCli.cs index 1c2fad14..6be0ebf5 100644 --- a/nanoFirmwareFlasher.Library/JLinkCli.cs +++ b/nanoFirmwareFlasher.Library/JLinkCli.cs @@ -29,10 +29,15 @@ public class JLinkCli /// private const string FlashAddressToken = "{FLASH_ADDRESS}"; + /// + /// Token to replace with address to flash. + /// + private const string LoadFileListToken = "{LOAD_FILE_LIST}"; + /// /// Template for JLink command file to flash a file. /// - private const string FlashFileCommandTemplate = $@" + private const string FlashSingleFileCommandTemplate = $@" USB speed auto Halt @@ -40,6 +45,19 @@ speed auto Reset Go Exit +"; + + /// + /// Template for JLink command file to flash multiple files. + /// + private const string FlashMultipleFilesCommandTemplate = $@" +USB +speed auto +Halt +{LoadFileListToken} +Reset +Go +Exit "; /// @@ -240,7 +258,7 @@ public ExitCodes ExecuteFlashBinFiles( } // compose JLink command file - var jlinkCmdContent = FlashFileCommandTemplate.Replace(FilePathToken, binFilePath).Replace(FlashAddressToken, addresses.ElementAt(index++)); + var jlinkCmdContent = FlashSingleFileCommandTemplate.Replace(FilePathToken, binFilePath).Replace(FlashAddressToken, addresses.ElementAt(index++)); var jlinkCmdFilePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.jlink"); // create file @@ -293,6 +311,152 @@ public ExitCodes ExecuteFlashBinFiles( return ExitCodes.OK; } + /// + /// Executes an operation that flashes a collection of Intel HEX format files to a connected J-Link device. + /// + /// List of files to flash to the device. + /// ID of the J-Link device to execute the operation into. Leave to use the default address. + /// + public ExitCodes ExecuteFlashHexFiles( + IList files, + string probeId) + { + // check file existence + if (files.Any(f => !File.Exists(f))) + { + return ExitCodes.E5004; + } + + List shadowFiles = new List(); + + // J-Link can't handle diacritc chars + // developer note: reported to Segger (Case: 60276735) and can be removed if this is fixed/improved + foreach (string hexFile in files) + { + if (!hexFile.IsNormalized(NormalizationForm.FormD) || + hexFile.Contains(' ')) + { + var tempFile = Path.Combine( + Environment.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget.Machine), + Path.GetFileName(hexFile)); + + // copy file to shadow file + File.Copy( + hexFile, + tempFile, + true); + + shadowFiles.Add(tempFile); + } + else + { + // copy file to shadow list + shadowFiles.Add(hexFile); + } + } + + // erase flash + if (DoMassErase) + { + var eraseResult = ExecuteMassErase(probeId); + + if (eraseResult != ExitCodes.OK) + { + return eraseResult; + } + + // toggle mass erase so it's only performed before the first file is flashed + DoMassErase = false; + } + + if (Verbosity < VerbosityLevel.Normal) + { + Console.ForegroundColor = ConsoleColor.White; + Console.Write("Flashing device..."); + } + else + { + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine("Flashing device..."); + } + + // program HEX file(s) + StringBuilder listOfFiles = new StringBuilder(); + + foreach (string hexFile in shadowFiles) + { + // make sure path is absolute + var hexFilePath = Utilities.MakePathAbsolute( + Environment.CurrentDirectory, + hexFile); + + if (Verbosity > VerbosityLevel.Normal) + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine($"{Path.GetFileName(hexFilePath)}"); + } + + listOfFiles.AppendLine($"LoadFile {hexFilePath}"); + } + + // compose JLink command file + var jlinkCmdContent = FlashMultipleFilesCommandTemplate.Replace( + LoadFileListToken, + listOfFiles.ToString()); + + var jlinkCmdFilePath = Path.Combine( + Path.GetTempPath(), + $"{Guid.NewGuid()}.jlink"); + + // create file + var jlinkCmdFile = File.CreateText(jlinkCmdFilePath); + jlinkCmdFile.Write(jlinkCmdContent); + jlinkCmdFile.Close(); + + var cliOutput = RunJLinkCLI(jlinkCmdFilePath); + + // OK to delete the JLink command file + File.Delete(jlinkCmdFilePath); + + if (Verbosity >= VerbosityLevel.Normal + && cliOutput.Contains("Skipped. Contents already match")) + { + Console.ForegroundColor = ConsoleColor.Yellow; + + Console.WriteLine(""); + Console.WriteLine("******************* WARNING *********************"); + Console.WriteLine("Skip flashing. Contents already match the update."); + Console.WriteLine("*************************************************"); + Console.WriteLine(""); + + Console.ForegroundColor = ConsoleColor.White; + } + else if (!(cliOutput.Contains("Flash download: Program & Verify") + && cliOutput.Contains("O.K."))) + { + ShowCLIOutput(cliOutput); + + return ExitCodes.E5006; + } + + ShowCLIOutput(cliOutput); + + if (Verbosity < VerbosityLevel.Normal) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine(" OK"); + } + else + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Flashing completed..."); + } + + Console.ForegroundColor = ConsoleColor.White; + + return ExitCodes.OK; + } + public void ShowCLIOutput(string cliOutput) { // show CLI output, if verbosity is diagnostic diff --git a/nanoFirmwareFlasher.Library/JLinkDevice.cs b/nanoFirmwareFlasher.Library/JLinkDevice.cs index d83eaee7..76e67835 100644 --- a/nanoFirmwareFlasher.Library/JLinkDevice.cs +++ b/nanoFirmwareFlasher.Library/JLinkDevice.cs @@ -164,5 +164,16 @@ public ExitCodes FlashBinFiles(IList files, IList addresses) addresses, ProbeId); } + + /// + /// Flash the HEX supplied to the connected device. + /// + /// + public ExitCodes FlashHexFiles(IList files) + { + return ExecuteFlashHexFiles( + files, + ProbeId); + } } } diff --git a/nanoFirmwareFlasher.Library/JLinkOperations.cs b/nanoFirmwareFlasher.Library/JLinkOperations.cs index 1c19cc62..c71f5da5 100644 --- a/nanoFirmwareFlasher.Library/JLinkOperations.cs +++ b/nanoFirmwareFlasher.Library/JLinkOperations.cs @@ -103,13 +103,13 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync( var connectedSilabsJLinkDevices = JLinkDevice.ListDevices(); - if (connectedSilabsJLinkDevices.Any()) + if (!connectedSilabsJLinkDevices.Any()) { // no device was found return ExitCodes.E9010; } - // JTAG device + // Jlink device jlinkDevice = new JLinkDevice(probeId); if (!jlinkDevice.DevicePresent) @@ -152,6 +152,12 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync( // set verbosity jlinkDevice.Verbosity = verbosity; + // write HEX files to flash + if (filesToFlash.Any(f => f.EndsWith(".hex"))) + { + operationResult = jlinkDevice.FlashHexFiles(filesToFlash); + } + if (operationResult == ExitCodes.OK && isApplicationBinFile) { // now program the application file