Skip to content

Commit

Permalink
Implement flashing HEX files with JLink (#201)
Browse files Browse the repository at this point in the history
  • Loading branch information
josesimoes authored Feb 17, 2023
1 parent e50e46e commit 87a4afc
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 4 deletions.
168 changes: 166 additions & 2 deletions nanoFirmwareFlasher.Library/JLinkCli.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,35 @@ public class JLinkCli
/// </summary>
private const string FlashAddressToken = "{FLASH_ADDRESS}";

/// <summary>
/// Token to replace with address to flash.
/// </summary>
private const string LoadFileListToken = "{LOAD_FILE_LIST}";

/// <summary>
/// Template for JLink command file to flash a file.
/// </summary>
private const string FlashFileCommandTemplate = $@"
private const string FlashSingleFileCommandTemplate = $@"
USB
speed auto
Halt
LoadFile {FilePathToken} {FlashAddressToken}
Reset
Go
Exit
";

/// <summary>
/// Template for JLink command file to flash multiple files.
/// </summary>
private const string FlashMultipleFilesCommandTemplate = $@"
USB
speed auto
Halt
{LoadFileListToken}
Reset
Go
Exit
";

/// <summary>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -293,6 +311,152 @@ public ExitCodes ExecuteFlashBinFiles(
return ExitCodes.OK;
}

/// <summary>
/// Executes an operation that flashes a collection of Intel HEX format files to a connected J-Link device.
/// </summary>
/// <param name="files">List of files to flash to the device.</param>
/// <param name="probeId">ID of the J-Link device to execute the operation into. Leave <see langword="null"/> to use the default address.</param>
/// <returns></returns>
public ExitCodes ExecuteFlashHexFiles(
IList<string> files,
string probeId)
{
// check file existence
if (files.Any(f => !File.Exists(f)))
{
return ExitCodes.E5004;
}

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

// 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
Expand Down
11 changes: 11 additions & 0 deletions nanoFirmwareFlasher.Library/JLinkDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,5 +164,16 @@ public ExitCodes FlashBinFiles(IList<string> files, IList<string> addresses)
addresses,
ProbeId);
}

/// <summary>
/// Flash the HEX supplied to the connected device.
/// </summary>
/// <param name="files"></param>
public ExitCodes FlashHexFiles(IList<string> files)
{
return ExecuteFlashHexFiles(
files,
ProbeId);
}
}
}
10 changes: 8 additions & 2 deletions nanoFirmwareFlasher.Library/JLinkOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@ public static async System.Threading.Tasks.Task<ExitCodes> 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)
Expand Down Expand Up @@ -152,6 +152,12 @@ public static async System.Threading.Tasks.Task<ExitCodes> 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
Expand Down

0 comments on commit 87a4afc

Please sign in to comment.