/// <summary> /// Runs a command with arguments. /// </summary> /// <param name="flashMulti">An instance of the <see cref="FlashMulti"/> class.</param> /// <param name="command">The command to run.</param> /// <param name="args">Arguments for the command.</param> /// <returns>The exit code returned by the command.</returns> public static int Run(FlashMulti flashMulti, string command, string args) { Debug.WriteLine("\n" + command + " " + args + "\n"); flashMulti.AppendVerbose(command + " " + args + "\r\n"); // Check if the file exists if (!File.Exists(command)) { flashMulti.AppendVerbose(string.Format("{0} does not exist", command)); return(-1); } Process myProcess = new Process(); // Process process = new Process(); myProcess.StartInfo.FileName = command; myProcess.StartInfo.Arguments = args; myProcess.StartInfo.UseShellExecute = false; myProcess.StartInfo.RedirectStandardOutput = true; myProcess.StartInfo.RedirectStandardError = true; myProcess.StartInfo.CreateNoWindow = true; // Set your output and error (asynchronous) handlers myProcess.OutputDataReceived += new DataReceivedEventHandler(flashMulti.OutputHandler); myProcess.ErrorDataReceived += new DataReceivedEventHandler(flashMulti.OutputHandler); // Start process and handlers myProcess.Start(); // Read the output myProcess.BeginOutputReadLine(); myProcess.BeginErrorReadLine(); // Loop until the process finishes myProcess.WaitForExit(); // Return the exit code from the process return(myProcess.ExitCode); }
/// <summary> /// Runs a command with arguments. /// </summary> /// <param name="flashMulti">An instance of the <see cref="FlashMulti"/> class.</param> /// <param name="command">The command to run.</param> /// <param name="args">Arguments for the command.</param> /// <returns>The exit code returned by the command.</returns> public static int Run(FlashMulti flashMulti, string command, string args) { Debug.WriteLine("\n" + command + " " + args + "\n"); flashMulti.AppendVerbose(command + " " + args + "\r\n"); // Check if the file exists if (!File.Exists(command)) { flashMulti.AppendVerbose(string.Format("{0} does not exist", command)); return(-1); } Process myProcess = new Process(); // Process process = new Process(); myProcess.StartInfo.FileName = command; myProcess.StartInfo.Arguments = args; myProcess.StartInfo.UseShellExecute = false; myProcess.StartInfo.RedirectStandardOutput = true; myProcess.StartInfo.RedirectStandardError = true; myProcess.StartInfo.CreateNoWindow = true; // avrdude sends all output to stderr, so reverse the sync/async processing if (command.EndsWith("avrdude.exe")) { // Handle standard output asynchronously myProcess.OutputDataReceived += new DataReceivedEventHandler(flashMulti.OutputHandler); // Start process and handlers myProcess.Start(); // Read the standard output asynchronously, handle it by line myProcess.BeginOutputReadLine(); // Read the error output synchronously, handle it character-by-character while (!myProcess.StandardError.EndOfStream) { var data = myProcess.StandardError.Read(); flashMulti.CharOutputHandler((char)data); } } else { // Hande error output asynchronously myProcess.ErrorDataReceived += new DataReceivedEventHandler(flashMulti.OutputHandler); // Start process and handlers myProcess.Start(); // Read the error output asynchronously, handle it by line myProcess.BeginErrorReadLine(); // Read the standard output synchronously, handle it character-by-character while (!myProcess.StandardOutput.EndOfStream) { var data = myProcess.StandardOutput.Read(); flashMulti.CharOutputHandler((char)data); } } // Loop until the process finishes myProcess.WaitForExit(); int returnCode = myProcess.ExitCode; myProcess.Dispose(); // Return the exit code from the process return(returnCode); }
/// <summary> /// Resets the Maple USB Serial device to DFU mode. /// </summary> /// <param name="flashMulti">An instance of the <see cref="FlashMulti"/> class.</param> /// <param name="comPort">The COM port where the Maple USB device can be found.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public static async Task <bool> ResetToDfuMode(FlashMulti flashMulti, string comPort) { string command; string commandArgs; int returnCode = -1; // Stop the serial monitor if it's active SerialMonitor serialMonitor = null; if (Application.OpenForms.OfType <SerialMonitor>().Any()) { Debug.WriteLine("Serial monitor window is open"); serialMonitor = Application.OpenForms.OfType <SerialMonitor>().First(); if (serialMonitor != null && serialMonitor.SerialPort != null && serialMonitor.SerialPort.IsOpen) { Debug.WriteLine($"Serial monitor is connected to {serialMonitor.SerialPort.PortName}"); Debug.WriteLine($"Closing serial monitor connection to {serialMonitor.SerialPort.PortName}"); serialMonitor.SerialDisconnect(); } } else { Debug.WriteLine("Serial monitor is not open"); } // Check if the port can be opened if (!ComPort.CheckPort(comPort)) { flashMulti.AppendLog($"{Strings.failedToOpenPort} {comPort}"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show($"{Strings.failedToOpenPort} {comPort}", Strings.dialogTitleRead, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } string mapleMode = MapleDevice.FindMaple().Mode; if (mapleMode == "USB") { flashMulti.AppendLog($"{Strings.progressSwitchingToDfuMode}"); command = ".\\tools\\maple-reset.exe"; commandArgs = $"{comPort} 2000"; await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode == 0) { flashMulti.AppendLog($" {Strings.done}\r\n"); flashMulti.AppendVerbose(string.Empty); } else { if (MapleDevice.FindMaple().DfuMode == false) { flashMulti.AppendLog($" {Strings.failed}\r\n"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.failedToReadModule, Strings.dialogTitleRead, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } } } return(true); }
/// <summary> /// Upgrades the bootloader of a Maple serial or DFU device. /// </summary> /// <param name="flashMulti">An instance of the <see cref="FlashMulti"/> class.</param> /// <param name="comPort">The COM port where the Maple USB device can be found.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public static async Task <bool> UpgradeBootloader(FlashMulti flashMulti, string comPort) { string command; string commandArgs; int returnCode = -1; flashMulti.AppendLog($"{Strings.modeBootloaderUpgrade} {Strings.viaNativeUSB}\r\n"); // Stop the serial monitor if it's active SerialMonitor serialMonitor = null; if (Application.OpenForms.OfType <SerialMonitor>().Any()) { Debug.WriteLine("Serial monitor window is open"); serialMonitor = Application.OpenForms.OfType <SerialMonitor>().First(); if (serialMonitor != null && serialMonitor.SerialPort != null && serialMonitor.SerialPort.IsOpen) { Debug.WriteLine($"Serial monitor is connected to {serialMonitor.SerialPort.PortName}"); Debug.WriteLine($"Closing serial monitor connection to {serialMonitor.SerialPort.PortName}"); serialMonitor.SerialDisconnect(); } } else { Debug.WriteLine("Serial monitor is not open"); } // Check if the port can be opened if (!ComPort.CheckPort(comPort)) { flashMulti.AppendLog($"{Strings.failedToOpenPort} {comPort}"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show($"{Strings.failedToOpenPort} {comPort}", Strings.dialogTitleBootloaderUpgrade, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } string mapleMode = MapleDevice.FindMaple().Mode; if (mapleMode == "USB") { flashMulti.AppendLog(Strings.progressSwitchingToDfuMode); command = ".\\tools\\maple-reset.exe"; commandArgs = $"{comPort} 2000"; await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode == 0) { flashMulti.AppendLog($" {Strings.done}\r\n"); flashMulti.AppendVerbose(string.Empty); } else { if (MapleDevice.FindMaple().DfuMode == false) { flashMulti.AppendLog($" {Strings.failed}\r\n"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.failedToWriteBootReloader, Strings.dialogTitleBootloaderUpgrade, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } } } // The bootreloader.bin file string fileName; if (Properties.Settings.Default.ErrorIfNoUSB) { fileName = ".\\tools\\bootreloader_legacy.bin"; } else { fileName = ".\\tools\\bootreloader_stickydfu.bin"; } // Erase the the flash flashMulti.AppendLog(Strings.progressWritingBootReloader); command = ".\\tools\\dfu-util-multi.exe"; commandArgs = string.Format("-a 2 -d 1EAF:0003 -D \"{0}\" -v -R", fileName, comPort); await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode != 0) { // First attempt failed so we need to try bootloader recovery flashMulti.AppendLog($" {Strings.failed}\r\n"); flashMulti.AppendLog($"{Strings.dfuAttemptingRecovery}\r\n"); // Show the recovery mode dialog DfuRecoveryDialog recoveryDialog = new DfuRecoveryDialog(flashMulti); var recoveryResult = recoveryDialog.ShowDialog(); // If we made it into recovery mode, flash the module if (recoveryResult == DialogResult.OK) { // Run the recovery flash command flashMulti.AppendLog(Strings.progressWritingBootReloader); await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode != 0) { flashMulti.AppendLog($" {Strings.failed}!\r\n"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.failedToWriteFirmware, Strings.dialogTitleWrite, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } } else if (recoveryResult == DialogResult.Cancel) { flashMulti.AppendLog(Strings.dfuRecoveryCancelled); flashMulti.EnableControls(true); return(false); } else { flashMulti.AppendLog(Strings.dfuRecoveryFailed); flashMulti.EnableControls(true); return(false); } } // Write a success message to the log flashMulti.AppendLog($" {Strings.done}\r\n"); flashMulti.AppendLog($"\r\n{Strings.succeededWritingBootReloader}"); // Re-enable the form controls flashMulti.EnableControls(true); return(true); }
/// <summary> /// Writes the firmware to a Maple serial or DFU device. /// </summary> /// <param name="flashMulti">An instance of the <see cref="FlashMulti"/> class.</param> /// <param name="fileName">The path of the file to flash.</param> /// <param name="comPort">The COM port where the Maple USB device can be found.</param> /// <param name="runAfterUpload">Indicates if the firmware should be run when the upload is finished.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public static async Task WriteFlash(FlashMulti flashMulti, string fileName, string comPort, bool runAfterUpload) { string command; string commandArgs; int returnCode = -1; flashMulti.AppendLog($"{Strings.modeWriting} {Strings.viaNativeUSB}\r\n"); // Stop the serial monitor if it's active SerialMonitor serialMonitor = null; bool reconnectSerialMonitor = false; if (Application.OpenForms.OfType <SerialMonitor>().Any()) { Debug.WriteLine("Serial monitor window is open"); serialMonitor = Application.OpenForms.OfType <SerialMonitor>().First(); if (serialMonitor != null && serialMonitor.SerialPort != null && serialMonitor.SerialPort.IsOpen) { reconnectSerialMonitor = true; Debug.WriteLine($"Serial monitor is connected to {serialMonitor.SerialPort.PortName}"); Debug.WriteLine($"Closing serial monitor connection to {serialMonitor.SerialPort.PortName}"); serialMonitor.SerialDisconnect(); } } else { Debug.WriteLine("Serial monitor is not open"); } // Check if the port can be opened if (!ComPort.CheckPort(comPort)) { flashMulti.AppendLog($"{Strings.failedToOpenPort} {comPort}"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show($"{Strings.failedToOpenPort} {comPort}", Strings.dialogTitleWrite, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return; } string mapleMode = MapleDevice.FindMaple().Mode; if (mapleMode == "USB") { flashMulti.AppendLog(Strings.progressSwitchingToDfuMode); command = ".\\tools\\maple-reset.exe"; commandArgs = $"{comPort} 2000"; await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode == 0) { flashMulti.AppendLog($" {Strings.done}\r\n"); flashMulti.AppendVerbose(string.Empty); } else { if (MapleDevice.FindMaple().DfuMode == false) { flashMulti.AppendLog($" {Strings.failed}\r\n"); flashMulti.AppendLog($"{Strings.dfuAttemptingRecovery}\r\n"); // Show the recovery mode dialog DfuRecoveryDialog recoveryDialog = new DfuRecoveryDialog(flashMulti); var recoveryResult = recoveryDialog.ShowDialog(); // Stop if we didn't make it into recovery mode if (recoveryResult == DialogResult.Cancel) { flashMulti.AppendLog(Strings.dfuRecoveryCancelled); flashMulti.EnableControls(true); return; } else if (recoveryResult == DialogResult.Abort) { flashMulti.AppendLog(Strings.dfuRecoveryFailed); flashMulti.EnableControls(true); return; } } else { flashMulti.AppendLog($" {Strings.done}\r\n"); flashMulti.AppendVerbose(string.Empty); } } } if (!Properties.Settings.Default.DisableFlashVerification) { // Check that the STM32 MCU supports 128KB flashMulti.AppendLog($"{Strings.progressCheckingFlashSize}"); // Create a temporary file name to read into string tempFileName = Path.GetTempFileName(); // Read the flash memory into a temp file command = ".\\tools\\dfu-util-multi.exe"; commandArgs = string.Format("-a 2 -d 1EAF:0003 -U \"{0}\" -v", tempFileName, comPort); await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); // If we failed we need to try DFU Recovery Mode if (returnCode != 0) { // First attempt failed so we need to try bootloader recovery flashMulti.AppendLog($" {Strings.failed}\r\n"); flashMulti.AppendLog($"{Strings.dfuAttemptingRecovery}\r\n"); // Show the recovery mode dialog DfuRecoveryDialog recoveryDialog = new DfuRecoveryDialog(flashMulti); var recoveryResult = recoveryDialog.ShowDialog(); // If we made it into recovery mode, flash the module if (recoveryResult == DialogResult.OK) { // Run the recovery flash command flashMulti.AppendLog(Strings.progressCheckingFlashSize); await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode != 0) { flashMulti.AppendLog($" {Strings.failed}!\r\n"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.failedToWriteFirmware, Strings.dialogTitleWrite, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return; } } else if (recoveryResult == DialogResult.Cancel) { flashMulti.AppendLog(Strings.dfuRecoveryCancelled); flashMulti.EnableControls(true); return; } else { flashMulti.AppendLog(Strings.dfuRecoveryFailed); flashMulti.EnableControls(true); return; } } flashMulti.AppendLog($" {Strings.done}\r\n"); // Get the file size long length = new FileInfo(tempFileName).Length; // Compare the size of the data we read to the size we expect if (length < 122880) { // Throw a message and stop flashMulti.EnableControls(true); using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.failedToVerifyMcuFlash, Strings.dialogTitleWrite, MessageBoxButtons.OK, MessageBoxIcon.Error); } return; } } // First attempt to flash the firmware flashMulti.AppendLog(Strings.progressWritingFirmware); command = ".\\tools\\dfu-util-multi.exe"; commandArgs = string.Format("-a 2 -d 1EAF:0003 -D \"{0}\" -v", fileName, comPort); if (runAfterUpload) { commandArgs += " -R"; } await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode != 0) { // First attempt failed so we need to try bootloader recovery flashMulti.AppendLog($" {Strings.failed}\r\n"); flashMulti.AppendLog($"{Strings.dfuAttemptingRecovery}\r\n"); // Show the recovery mode dialog DfuRecoveryDialog recoveryDialog = new DfuRecoveryDialog(flashMulti); var recoveryResult = recoveryDialog.ShowDialog(); // If we made it into recovery mode, flash the module if (recoveryResult == DialogResult.OK) { // Run the recovery flash command flashMulti.AppendLog(Strings.progressWritingFirmware); await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode != 0) { flashMulti.AppendLog($" {Strings.failed}!\r\n"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.failedToWriteFirmware, Strings.dialogTitleWrite, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return; } } else if (recoveryResult == DialogResult.Cancel) { flashMulti.AppendLog(Strings.dfuRecoveryCancelled); flashMulti.EnableControls(true); return; } else { flashMulti.AppendLog(Strings.dfuRecoveryFailed); flashMulti.EnableControls(true); return; } } flashMulti.AppendLog($" {Strings.done}\r\n"); flashMulti.AppendLog($"\r\n{Strings.succeededWritingFirmware}"); // Reconnect the serial monitor if (serialMonitor != null && reconnectSerialMonitor) { Thread.Sleep(1000); serialMonitor.SerialConnect(comPort); } // Re-enable the form controls flashMulti.EnableControls(true); // Show a success message box using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.succeededWritingFirmware, Strings.dialogTitleWrite, MessageBoxButtons.OK, MessageBoxIcon.Information); } }
/// <summary> /// Reads the flash memory of a Maple USB device. /// </summary> /// <param name="flashMulti">An instance of the <see cref="FlashMulti"/> class.</param> /// <param name="fileName">The path of the file to write to.</param> /// <param name="comPort">The COM port where the Maple USB device can be found.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public static async Task <bool> ReadFlash(FlashMulti flashMulti, string fileName, string comPort) { string command; string commandArgs; int returnCode = -1; flashMulti.AppendLog($"{Strings.modeReading} {Strings.viaNativeUSB}\r\n"); // Stop the serial monitor if it's active SerialMonitor serialMonitor = null; bool reconnectSerialMonitor = false; if (Application.OpenForms.OfType <SerialMonitor>().Any()) { Debug.WriteLine("Serial monitor window is open"); serialMonitor = Application.OpenForms.OfType <SerialMonitor>().First(); if (serialMonitor != null && serialMonitor.SerialPort != null && serialMonitor.SerialPort.IsOpen) { reconnectSerialMonitor = true; Debug.WriteLine($"Serial monitor is connected to {serialMonitor.SerialPort.PortName}"); Debug.WriteLine($"Closing serial monitor connection to {serialMonitor.SerialPort.PortName}"); serialMonitor.SerialDisconnect(); } } else { Debug.WriteLine("Serial monitor is not open"); } // Check if the port can be opened if (!ComPort.CheckPort(comPort)) { flashMulti.AppendLog($"{Strings.failedToOpenPort} {comPort}"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show($"{Strings.failedToOpenPort} {comPort}", Strings.dialogTitleRead, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } string mapleMode = MapleDevice.FindMaple().Mode; if (mapleMode == "USB") { flashMulti.AppendLog($"{Strings.progressSwitchingToDfuMode}"); command = ".\\tools\\maple-reset.exe"; commandArgs = $"{comPort} 2000"; await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode == 0) { flashMulti.AppendLog($" {Strings.done}\r\n"); flashMulti.AppendVerbose(string.Empty); } else { if (MapleDevice.FindMaple().DfuMode == false) { flashMulti.AppendLog($" {Strings.failed}\r\n"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.failedToReadModule, Strings.dialogTitleRead, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } } } // Read the flash memory flashMulti.AppendLog(Strings.progressReadingFlash); command = ".\\tools\\dfu-util-multi.exe"; commandArgs = string.Format("-a 2 -d 1EAF:0003 -U \"{0}\" -v", fileName, comPort); await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode != 0) { flashMulti.AppendLog($" {Strings.failed}\r\n"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.failedToReadModule, Strings.dialogTitleRead, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } // Write a success message to the log flashMulti.AppendLog($" {Strings.done}\r\n\r\n"); // Reconnect the serial monitor if (serialMonitor != null && reconnectSerialMonitor) { Thread.Sleep(1000); serialMonitor.SerialConnect(comPort); } // Re-enable the form controls flashMulti.EnableControls(true); return(true); }
/// <summary> /// Erases the flash memory of a Maple USB device. /// </summary> /// <param name="flashMulti">An instance of the <see cref="FlashMulti"/> class.</param> /// <param name="comPort">The COM port where the Maple USB device can be found.</param> /// <param name="eraseEeprom">Flag indicating if the EEPROM should be erased.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public static async Task <bool> EraseFlash(FlashMulti flashMulti, string comPort, bool eraseEeprom) { string command; string commandArgs; int returnCode = -1; flashMulti.AppendLog($"{Strings.modeErasing} {Strings.viaNativeUSB}\r\n"); // Stop the serial monitor if it's active SerialMonitor serialMonitor = null; if (Application.OpenForms.OfType <SerialMonitor>().Any()) { Debug.WriteLine("Serial monitor window is open"); serialMonitor = Application.OpenForms.OfType <SerialMonitor>().First(); if (serialMonitor != null && serialMonitor.SerialPort != null && serialMonitor.SerialPort.IsOpen) { Debug.WriteLine($"Serial monitor is connected to {serialMonitor.SerialPort.PortName}"); Debug.WriteLine($"Closing serial monitor connection to {serialMonitor.SerialPort.PortName}"); serialMonitor.SerialDisconnect(); } } else { Debug.WriteLine("Serial monitor is not open"); } // Check if the port can be opened if (!ComPort.CheckPort(comPort)) { flashMulti.AppendLog($"{Strings.failedToOpenPort} {comPort}"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show($"{Strings.failedToOpenPort} {comPort}", Strings.dialogTitleErase, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } string mapleMode = MapleDevice.FindMaple().Mode; if (mapleMode == "USB") { flashMulti.AppendLog(Strings.progressSwitchingToDfuMode); command = ".\\tools\\maple-reset.exe"; commandArgs = $"{comPort} 2000"; await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode == 0) { flashMulti.AppendLog($" {Strings.done}\r\n"); flashMulti.AppendVerbose(string.Empty); } else { if (MapleDevice.FindMaple().DfuMode == false) { flashMulti.AppendLog($" {Strings.failed}\r\n"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.failedtoEraseModule, Strings.dialogTitleErase, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } } } // It's not actually possible to erase a device with dfu-util so we write a file full of FF bytes. string fileName = string.Empty; if (eraseEeprom) { // 120KB file overwrites the EEPROM fileName = ".\\tools\\erase120.bin"; } else { // 118KB file preserves the EEPROM fileName = ".\\tools\\erase118.bin"; } // Erase the the flash flashMulti.AppendLog(Strings.progressErasingFlash); command = ".\\tools\\dfu-util-multi.exe"; commandArgs = string.Format("-a 2 -d 1EAF:0003 -D \"{0}\" -v", fileName, comPort); await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode != 0) { flashMulti.AppendLog($" {Strings.failed}\r\n"); using (new CenterWinDialog(flashMulti)) { MessageBox.Show(Strings.failedtoEraseModule, Strings.dialogTitleErase, MessageBoxButtons.OK, MessageBoxIcon.Error); } flashMulti.EnableControls(true); return(false); } // Write a success message to the log flashMulti.AppendLog($" {Strings.done}\r\n"); flashMulti.AppendLog($"\r\n{Strings.succeededErasing}"); // Re-enable the form controls flashMulti.EnableControls(true); return(true); }
/// <summary> /// Writes the firmware to a Maple serial or DFU device. /// </summary> /// <param name="flashMulti">An instance of the <see cref="FlashMulti"/> class.</param> /// <param name="fileName">The path of the file to flash.</param> /// <param name="comPort">The COM port where the Maple USB device can be found.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public static async Task WriteFlash(FlashMulti flashMulti, string fileName, string comPort) { string command; string commandArgs; int returnCode = -1; flashMulti.AppendLog("Starting MULTI-Module update via native USB\r\n"); // Stop the serial monitor if it's active SerialMonitor serialMonitor = null; bool reconnectSerialMonitor = false; if (Application.OpenForms.OfType <SerialMonitor>().Any()) { Debug.WriteLine("Serial monitor window is open"); serialMonitor = Application.OpenForms.OfType <SerialMonitor>().First(); if (serialMonitor != null && serialMonitor.SerialPort != null && serialMonitor.SerialPort.IsOpen) { reconnectSerialMonitor = true; Debug.WriteLine($"Serial monitor is connected to {serialMonitor.SerialPort.PortName}"); Debug.WriteLine($"Closing serial monitor connection to {serialMonitor.SerialPort.PortName}"); serialMonitor.SerialDisconnect(); } } else { Debug.WriteLine("Serial monitor is not open"); } // Check if the port can be opened if (!ComPort.CheckPort(comPort)) { flashMulti.AppendLog(string.Format("Couldn't open port {0}", comPort)); MessageBox.Show(string.Format("Couldn't open port {0}", comPort), "Write Firmware", MessageBoxButtons.OK, MessageBoxIcon.Error); flashMulti.EnableControls(true); return; } string mapleMode = MapleDevice.FindMaple().Mode; if (mapleMode == "USB") { flashMulti.AppendLog("Switching MULTI-Module into DFU mode ..."); command = ".\\tools\\maple-reset.exe"; commandArgs = $"{comPort} 2000"; await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode == 0) { flashMulti.AppendLog(" done\r\n"); flashMulti.AppendVerbose(string.Empty); } else { if (MapleDevice.FindMaple().DfuMode == false) { flashMulti.AppendLog(" failed!\r\n"); flashMulti.AppendLog("Attempting DFU Recovery Mode.\r\n"); // Show the recovery mode dialog DfuRecoveryDialog recoveryDialog = new DfuRecoveryDialog(flashMulti); var recoveryResult = recoveryDialog.ShowDialog(); // Stop if we didn't make it into recovery mode if (recoveryResult == DialogResult.Cancel) { flashMulti.AppendLog("DFU Recovery cancelled."); flashMulti.EnableControls(true); return; } else if (recoveryResult == DialogResult.Abort) { flashMulti.AppendLog("DFU Recovery failed."); flashMulti.EnableControls(true); return; } } else { flashMulti.AppendLog(" done\r\n"); flashMulti.AppendVerbose(string.Empty); } } } // First attempt to flash the firmware flashMulti.AppendLog("Writing firmware to MULTI-Module ..."); command = ".\\tools\\dfu-util.exe"; commandArgs = string.Format("-R -a 2 -d 1EAF:0003 -D \"{0}\"", fileName, comPort); await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode != 0) { // First attempt failed so we need to try bootloader recovery flashMulti.AppendLog(" failed!\r\n"); flashMulti.AppendLog("Attempting DFU Recovery Mode.\r\n"); // Show the recovery mode dialog DfuRecoveryDialog recoveryDialog = new DfuRecoveryDialog(flashMulti); var recoveryResult = recoveryDialog.ShowDialog(); // If we made it into recovery mode, flash the module if (recoveryResult == DialogResult.OK) { // Run the recovery flash command flashMulti.AppendLog("Writing firmware to MULTI-Module ..."); await Task.Run(() => { returnCode = RunCommand.Run(flashMulti, command, commandArgs); }); if (returnCode != 0) { flashMulti.AppendLog(" failed!\r\n"); MessageBox.Show("Failed to write the firmware.", "Firmware Update", MessageBoxButtons.OK, MessageBoxIcon.Error); flashMulti.EnableControls(true); return; } } else if (recoveryResult == DialogResult.Cancel) { flashMulti.AppendLog("DFU Recovery cancelled."); flashMulti.EnableControls(true); return; } else { flashMulti.AppendLog("DFU Recovery failed."); flashMulti.EnableControls(true); return; } } flashMulti.AppendLog(" done\r\n"); flashMulti.AppendLog("\r\nMULTI-Module updated successfully"); // Reconnect the serial monitor if (serialMonitor != null && reconnectSerialMonitor) { Thread.Sleep(1000); serialMonitor.SerialConnect(comPort); } MessageBox.Show("MULTI-Module updated successfully.", "Firmware Update", MessageBoxButtons.OK, MessageBoxIcon.Information); flashMulti.EnableControls(true); }
/// <summary> /// Uses the temporary file read from the module to extract and save a firmware backup. /// </summary> /// <param name="flashMulti">An instance of the <see cref="FlashMulti"/> class.</param> /// <param name="flashFileName">The temporary file containing the module's flash data.</param> /// <param name="eepromFileName">The temporary file containing an Atmega328p module's EEPROM data.</param> internal static void SaveFirmwareBackup(FlashMulti flashMulti, string flashFileName, string eepromFileName) { Debug.WriteLine($"Flash backup file: {flashFileName}"); // Stop if the backup file isn't found or the type isn't valid if (!File.Exists(flashFileName) || flashMulti.BackupModuleType < 1) { MessageBox.Show("Backup file not found. Please read the MULTI-Module again.", "Save Backup", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // Ask the user if they want to include the EEPROM DialogResult includeEeprom = DialogResult.Cancel; if (flashMulti.BackupModuleType == FlashMulti.Stm32BackupDfuUtil || flashMulti.BackupModuleType == FlashMulti.Stm32BackupStm32Flash) { // STM32 backup - ask if EEPROM data should be included in the backup includeEeprom = MessageBox.Show("Include the EEPROM data in the backup?", "Include EEPROM", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); } else if (flashMulti.BackupModuleType == FlashMulti.AtmegaBackup) { // Atmega328p backup - ask if the EEPROM should be save seperately Debug.WriteLine($"EEPROM backup file: {eepromFileName}"); includeEeprom = MessageBox.Show("Save the EEPROM data? It will be saved in a separate file.", "Include EEPROM", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); } // Stop if the user cancelled if (includeEeprom == DialogResult.Cancel) { return; } // Get the size of the back up file long flashFileSize = new System.IO.FileInfo(flashFileName).Length; Debug.WriteLine($"Flash file is {flashFileSize} bytes."); // Get the maximum file size for each backup type long firmwareSizeMax = 0; switch (flashMulti.BackupModuleType) { case FlashMulti.AtmegaBackup: firmwareSizeMax = 32 * 1024; break; case FlashMulti.Stm32BackupDfuUtil: firmwareSizeMax = 120 * 1024; break; case FlashMulti.Stm32BackupStm32Flash: firmwareSizeMax = 128 * 1024; break; } // Stop if the file is bigger than we expect if (flashFileSize > firmwareSizeMax) { MessageBox.Show($"Unexpected backup file size. File is {flashFileSize} bytes, maximum size is {firmwareSizeMax} bytes.", "Save Backup", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // Get the start byte long backupStartByte = 0; // Skip the first 8KB if the backup includes the bootloader if (flashMulti.BackupModuleType == FlashMulti.Stm32BackupStm32Flash && FirmwareContainsBootloader(flashFileName) && flashFileSize == 128 * 1024) { backupStartByte = 8192; } // Get the end byte - default to the entire file long backupEndByte = flashFileSize; // If this is an STM32 backup and the EEPROM is not being included we don't need the last 2KB of the backup if (flashMulti.BackupModuleType != FlashMulti.AtmegaBackup && includeEeprom == DialogResult.No) { // Discard the last 2KB of the flash backup backupEndByte = flashFileSize - 2048; } // Create the file save dialog for the flash backup using (SaveFileDialog saveFileDialog = new SaveFileDialog()) { // Title for the dialog saveFileDialog.Title = "Location to save the flash backup"; // Filter for .bin files saveFileDialog.Filter = ".bin File|*.bin"; // Return if the dialog was cancelled if (saveFileDialog.ShowDialog() != DialogResult.OK) { return; } // Extract the firmware from the backup file byte[] firmwareData; // Read the last firmware from the binary file using (BinaryReader b = new BinaryReader(File.Open(flashFileName, FileMode.Open, FileAccess.Read))) { // Length of data to read long byteLength = backupEndByte - backupStartByte; Debug.WriteLine($"Capturing {byteLength} bytes between {backupStartByte} and {backupEndByte}"); // Seek to the start position b.BaseStream.Seek(backupStartByte, SeekOrigin.Begin); // Read the firmware data firmwareData = b.ReadBytes((int)byteLength); } // Save the file using (BinaryWriter b = new BinaryWriter(File.Open(saveFileDialog.FileName, FileMode.Create, FileAccess.Write))) { // Write the data b.Write(firmwareData); } flashMulti.AppendLog($"\r\n\r\nMULTI-Module firmware saved successfully"); flashMulti.AppendVerbose($"Firmware saved to '{saveFileDialog.FileName}'"); } // Save the Atmega328p EEPROM to a separate file if (flashMulti.BackupModuleType == FlashMulti.AtmegaBackup && includeEeprom == DialogResult.Yes) { // Create the file save dialog for the flash backup using (SaveFileDialog saveFileDialog = new SaveFileDialog()) { // Title for the dialog saveFileDialog.Title = "Location to save the EEPROM backup"; // Filter for .eep files saveFileDialog.Filter = ".eep File|*.eep"; // Return if the dialog was cancelled if (saveFileDialog.ShowDialog() != DialogResult.OK) { return; } // Extract the firmware from the backup file byte[] firmwareData; // Read the last firmware from the binary file using (BinaryReader b = new BinaryReader(File.Open(eepromFileName, FileMode.Open, FileAccess.Read))) { // Seek to the start position b.BaseStream.Seek(0, SeekOrigin.Begin); // Read the firmware data firmwareData = b.ReadBytes(1024); } // Save the file using (BinaryWriter b = new BinaryWriter(File.Open(saveFileDialog.FileName, FileMode.Create, FileAccess.Write))) { // Write the data b.Write(firmwareData); } flashMulti.AppendLog($"\r\nMULTI-Module EEPROM saved successfully"); flashMulti.AppendVerbose($"EEPROM saved to '{saveFileDialog.FileName}'"); } } }