internal static async System.Threading.Tasks.Task <ExitCodes> UpdateFirmwareAsync( EspTool espTool, EspTool.DeviceInfo esp32Device, string targetName, bool updateFw, string fwVersion, bool stable, string applicationPath, string deploymentAddress, VerbosityLevel verbosity) { ExitCodes operationResult = ExitCodes.OK; uint address = 0; // if a target name wasn't specified use the default (and only available) ESP32 target if (string.IsNullOrEmpty(targetName)) { targetName = _esp32TargetName; } Esp32Firmware firmware = new Esp32Firmware( targetName, fwVersion, stable) { Verbosity = verbosity }; // need to download update package? if (updateFw) { operationResult = await firmware.DownloadAndExtractAsync(esp32Device.FlashSize); if (operationResult != ExitCodes.OK) { return(operationResult); } // download successful } // need to include application file? if (!string.IsNullOrEmpty(applicationPath)) { // check application file if (File.Exists(applicationPath)) { if (!updateFw) { // this is a deployment operation only // try parsing the deployment address from parameter // need to remove the leading 0x and to specify that hexadecimal values are allowed if (!uint.TryParse(deploymentAddress.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier, System.Globalization.CultureInfo.InvariantCulture, out address)) { return(ExitCodes.E9009); } } string applicationBinary = new FileInfo(applicationPath).FullName; firmware.FlashPartitions = new Dictionary <int, string>() { { updateFw?firmware.DeploymentPartionAddress : (int)address, applicationBinary } }; } else { return(ExitCodes.E9008); } } if (verbosity >= VerbosityLevel.Normal) { Console.Write($"Erasing flash..."); } if (updateFw) { // erase flash operationResult = espTool.EraseFlash(); } else { // erase flash segment // need to get deployment address here // length must both be multiples of the SPI flash erase sector size. This is 0x1000 (4096) bytes for supported flash chips. var flashPartition = firmware.FlashPartitions.First(); var fileStream = File.OpenRead(flashPartition.Value); uint fileLength = (uint)Math.Ceiling((decimal)fileStream.Length / 0x1000) * 0x1000; operationResult = espTool.EraseFlashSegment(address, fileLength); } if (operationResult == ExitCodes.OK) { if (verbosity >= VerbosityLevel.Normal) { Console.WriteLine("OK"); } else { Console.WriteLine(""); } if (verbosity >= VerbosityLevel.Normal) { Console.Write($"Flashing firmware..."); } // write to flash operationResult = espTool.WriteFlash(firmware.FlashPartitions); if (operationResult == ExitCodes.OK) { if (verbosity >= VerbosityLevel.Normal) { Console.WriteLine("OK"); } else { Console.WriteLine(""); } } } return(operationResult); }
static async Task RunOptionsAndReturnExitCodeAsync(Options o) { #region parse verbosity option switch (o.Verbosity) { // quiet case "q": case "quiet": verbosityLevel = VerbosityLevel.Quiet; break; // minimal case "m": case "minimal": verbosityLevel = VerbosityLevel.Minimal; break; // normal case "n": case "normal": verbosityLevel = VerbosityLevel.Normal; break; // detailed case "d": case "detailed": verbosityLevel = VerbosityLevel.Detailed; break; // diagnostic case "diag": case "diagnostic": verbosityLevel = VerbosityLevel.Diagnostic; break; default: throw new ArgumentException("Invalid option for Verbosity"); } #endregion Console.WriteLine(headerInfo); Console.WriteLine(copyrightInfo); Console.WriteLine(); #region target processing // if a target name was specified, try to be smart and set the platform accordingly (in case it wasn't specified) if (string.IsNullOrEmpty(o.Platform) && !string.IsNullOrEmpty(o.TargetName)) { // easiest one: ESP32 if (o.TargetName.Contains("ESP32")) { o.Platform = "esp32"; } else if ( o.TargetName.Contains("ST") || o.TargetName.Contains("MBN_QUAIL") || o.TargetName.Contains("NETDUINO3") || o.TargetName.Contains("GHI FEZ") || o.TargetName.Contains("IngenuityMicro") || o.TargetName.Contains("ORGPAL") ) { // candidates for STM32 o.Platform = "stm32"; } else if ( o.TargetName.Contains("TI_CC1352") ) { // candidates for TI CC13x2 o.Platform = "cc13x2"; } else { // other supported platforms will go here // in case a wacky target is entered by the user, the package name will be checked against Bintray repo } } #endregion #region platform specific options // if an option was specified and has an obvious platform, try to be smart and set the platform accordingly (in case it wasn't specified) if (string.IsNullOrEmpty(o.Platform)) { // JTAG related if ( o.ListJtagDevices || !string.IsNullOrEmpty(o.JtagDeviceId) || o.HexFile.Any() || o.BinFile.Any()) { o.Platform = "stm32"; } // DFU related else if ( o.ListDevicesInDfuMode || !string.IsNullOrEmpty(o.DfuDeviceId) || !string.IsNullOrEmpty(o.DfuFile)) { o.Platform = "stm32"; } // ESP32 related else if ( !string.IsNullOrEmpty(o.SerialPort) || (o.BaudRate != 921600) || (o.Esp32FlashMode != "dio") || (o.Esp32FlashFrequency != 40)) { o.Platform = "esp32"; } } #endregion #region ESP32 platform options if (o.Platform == "esp32") { // COM port is mandatory for ESP32 if (string.IsNullOrEmpty(o.SerialPort)) { _exitCode = ExitCodes.E6001; return; } EspTool espTool; try { espTool = new EspTool( o.SerialPort, o.BaudRate, o.Esp32FlashMode, o.Esp32FlashFrequency); } catch (Exception) { _exitCode = ExitCodes.E4005; return; } EspTool.DeviceInfo esp32Device; if (espTool.ComPortAvailable) { try { esp32Device = espTool.TestChip(); } catch (EspToolExecutionException ex) { _exitCode = ExitCodes.E4000; _extraMessage = ex.Message; return; } } else { // couldn't open COM port // done here, this command has no further processing _exitCode = ExitCodes.E6000; return; } if (verbosityLevel >= VerbosityLevel.Normal) { Console.WriteLine($"Connected to ESP32 { esp32Device.ChipName } with MAC address { esp32Device.MacAddress }"); Console.WriteLine($"features { esp32Device.Features }"); string flashSize = esp32Device.FlashSize >= 0x10000 ? $"{ esp32Device.FlashSize / 0x100000 }MB" : $"{ esp32Device.FlashSize / 0x400 }kB"; Console.WriteLine($"Flash information: manufacturer 0x{ esp32Device.FlashManufacturerId } device 0x{ esp32Device.FlashDeviceModelId } size { flashSize }"); } // set verbosity espTool.Verbosity = verbosityLevel; // backup requested if (!string.IsNullOrEmpty(o.BackupPath) || !string.IsNullOrEmpty(o.BackupFile)) { try { // backup path specified, backup deployment _exitCode = Esp32Operations.BackupFlash(espTool, esp32Device, o.BackupPath, o.BackupFile, verbosityLevel); if (_exitCode != ExitCodes.OK) { // done here return; } } catch (ReadEsp32FlashException ex) { _exitCode = ExitCodes.E4004; _extraMessage = ex.Message; // done here return; } } // update operation requested? if (o.Update) { try { // write flash _exitCode = await Esp32Operations.UpdateFirmwareAsync( espTool, esp32Device, o.TargetName, true, o.FwVersion, o.Stable, o.DeploymentImage, null, verbosityLevel); if (_exitCode != ExitCodes.OK) { // done here return; } // done here _exitCode = ExitCodes.OK; return; } catch (ReadEsp32FlashException ex) { _exitCode = ExitCodes.E4004; _extraMessage = ex.Message; } catch (WriteEsp32FlashException ex) { _exitCode = ExitCodes.E4003; _extraMessage = ex.Message; } catch (EspToolExecutionException ex) { _exitCode = ExitCodes.E4000; _extraMessage = ex.Message; } } // it's OK to deploy after update if (o.Deploy) { // need to take care of flash address string appFlashAddress = null; if (o.FlashAddress.Any()) { // take the first address, it should be the only one valid appFlashAddress = o.FlashAddress.ElementAt(0); } else { _exitCode = ExitCodes.E9009; return; } // this to flash a deployment image without updating the firmware try { // write flash _exitCode = await Esp32Operations.UpdateFirmwareAsync( espTool, esp32Device, null, false, null, false, o.DeploymentImage, appFlashAddress, verbosityLevel); if (_exitCode != ExitCodes.OK) { // done here return; } // done here _exitCode = ExitCodes.OK; return; } catch (ReadEsp32FlashException ex) { _exitCode = ExitCodes.E4004; _extraMessage = ex.Message; } catch (WriteEsp32FlashException ex) { _exitCode = ExitCodes.E4003; _extraMessage = ex.Message; } catch (EspToolExecutionException ex) { _exitCode = ExitCodes.E4000; _extraMessage = ex.Message; } } // done here return; } #endregion #region STM32 platform options if (o.Platform == "stm32") { if (o.ListDevicesInDfuMode) { var connecteDevices = StmDfuDevice.ListDfuDevices(); if (connecteDevices.Count == 0) { Console.WriteLine("No DFU devices found"); } else { Console.WriteLine("-- Connected DFU devices --"); foreach (string deviceId in connecteDevices) { Console.WriteLine(deviceId); } Console.WriteLine("---------------------------"); } // done here, this command has no further processing _exitCode = ExitCodes.OK; return; } if (o.ListJtagDevices) { try { var connecteDevices = StmJtagDevice.ListDevices(); if (connecteDevices.Count == 0) { Console.WriteLine("No JTAG devices found"); } else { Console.WriteLine("-- Connected JTAG devices --"); foreach (string deviceId in connecteDevices) { Console.WriteLine(deviceId); } Console.WriteLine("---------------------------"); } // done here, this command has no further processing _exitCode = ExitCodes.OK; } catch (Exception ex) { // exception with _exitCode = ExitCodes.E5000; _extraMessage = ex.Message; } return; } if (!string.IsNullOrEmpty(o.DfuFile)) { // there is a DFU file argument, so follow DFU path var dfuDevice = new StmDfuDevice(o.DfuDeviceId); if (!dfuDevice.DevicePresent) { // no DFU device found // done here, this command has no further processing _exitCode = ExitCodes.E1000; return; } if (verbosityLevel >= VerbosityLevel.Normal) { Console.WriteLine($"Connected to DFU device with ID { dfuDevice.DeviceId }"); } // set verbosity dfuDevice.Verbosity = verbosityLevel; // get mass erase option dfuDevice.DoMassErase = o.MassErase; try { dfuDevice.FlashDfuFile(o.DfuFile); // done here, this command has no further processing _exitCode = ExitCodes.OK; return; } catch (DfuFileDoesNotExistException) { // DFU file doesn't exist _exitCode = ExitCodes.E1002; } catch (Exception ex) { // exception with DFU operation _exitCode = ExitCodes.E1003; _extraMessage = ex.Message; } } else if ( o.BinFile.Any() && o.HexFile.Any()) { // this has to be a JTAG connected device #region STM32 JTAG options try { var jtagDevice = new StmJtagDevice(o.JtagDeviceId); if (!jtagDevice.DevicePresent) { // no JTAG device found // done here, this command has no further processing _exitCode = ExitCodes.E5001; return; } if (verbosityLevel >= VerbosityLevel.Normal) { Console.WriteLine($"Connected to JTAG device with ID { jtagDevice.DeviceId }"); } // set verbosity jtagDevice.Verbosity = verbosityLevel; // get mass erase option jtagDevice.DoMassErase = o.MassErase; if (o.HexFile.Any()) { _exitCode = jtagDevice.FlashHexFiles(o.HexFile); // done here return; } if (o.BinFile.Any()) { _exitCode = jtagDevice.FlashBinFiles(o.BinFile, o.FlashAddress); // done here return; } } catch (CantConnectToJtagDeviceException) { // done here, this command has no further processing _exitCode = ExitCodes.E5002; } #endregion } else if (!string.IsNullOrEmpty(o.TargetName)) { // update operation requested? if (o.Update) { // this to update the device with fw from Bintray // need to take care of flash address string appFlashAddress = null; if (o.FlashAddress.Any()) { // take the first address, it should be the only one valid appFlashAddress = o.FlashAddress.ElementAt(0); } _exitCode = await Stm32Operations.UpdateFirmwareAsync( o.TargetName, o.FwVersion, o.Stable, true, o.DeploymentImage, appFlashAddress, o.DfuDeviceId, o.JtagDeviceId, verbosityLevel); if (_exitCode != ExitCodes.OK) { // done here return; } } // it's OK to deploy after update if (o.Deploy) { // this to flash a deployment image without updating the firmware // need to take care of flash address string appFlashAddress = null; if (o.FlashAddress.Any()) { // take the first address, it should be the only one valid appFlashAddress = o.FlashAddress.ElementAt(0); } else { _exitCode = ExitCodes.E9009; return; } _exitCode = await Stm32Operations.UpdateFirmwareAsync( o.TargetName, null, false, false, o.DeploymentImage, appFlashAddress, o.DfuDeviceId, o.JtagDeviceId, verbosityLevel); if (_exitCode != ExitCodes.OK) { // done here return; } } // reset MCU requested? if (o.ResetMcu) { _exitCode = Stm32Operations.ResetMcu( o.JtagDeviceId, verbosityLevel); if (_exitCode != ExitCodes.OK) { // done here return; } } } } #endregion #region TI CC13x2 platform options if (o.Platform == "cc13x2") { if (!string.IsNullOrEmpty(o.TargetName)) { // update operation requested? if (o.Update) { // this to update the device with fw from Bintray // need to take care of flash address string appFlashAddress = null; if (o.FlashAddress.Any()) { // take the first address, it should be the only one valid appFlashAddress = o.FlashAddress.ElementAt(0); } _exitCode = await CC13x26x2Operations.UpdateFirmwareAsync( o.TargetName, o.FwVersion, o.Stable, true, o.DeploymentImage, appFlashAddress, verbosityLevel); if (_exitCode != ExitCodes.OK) { // done here return; } } // it's OK to deploy after update if (o.Deploy) { // this to flash a deployment image without updating the firmware // need to take care of flash address string appFlashAddress = null; if (o.FlashAddress.Any()) { // take the first address, it should be the only one valid appFlashAddress = o.FlashAddress.ElementAt(0); } else { _exitCode = ExitCodes.E9009; return; } _exitCode = await CC13x26x2Operations.UpdateFirmwareAsync( o.TargetName, null, false, false, o.DeploymentImage, appFlashAddress, verbosityLevel); if (_exitCode != ExitCodes.OK) { // done here return; } } // reset MCU requested? if (o.ResetMcu) { // can't reset CC13x2 device without configuration file // would require to specify the exact target name and then had to try parsing that _exitCode = ExitCodes.E9000; // done here return; } } if (o.TIInstallXdsDrivers) { _exitCode = CC13x26x2Operations.InstallXds110Drivers(verbosityLevel); if (_exitCode != ExitCodes.OK) { // done here return; } } } #endregion }
public static ExitCodes BackupFlash( EspTool tool, EspTool.DeviceInfo device, string backupPath, string fileName, VerbosityLevel verbosity) { // check for backup file without backup path if (!string.IsNullOrEmpty(fileName) && string.IsNullOrEmpty(backupPath)) { // backup file without backup path return(ExitCodes.E9004); } // check if directory exists, if it doesn't, try to create if (!Directory.Exists(backupPath)) { try { Directory.CreateDirectory(backupPath); } catch { return(ExitCodes.E9002); } } // file name specified if (string.IsNullOrEmpty(fileName)) { fileName = $"{device.ChipName}_0x{device.MacAddress:X}_{DateTime.UtcNow.ToShortDateString()}.bin"; } var backupFilePath = Path.Combine(backupPath, fileName); // check file existence if (File.Exists(fileName)) { try { File.Delete(backupFilePath); } catch { return(ExitCodes.E9003); } } if (verbosity >= VerbosityLevel.Normal) { Console.WriteLine($"Backing up the firmware to \r\n{backupFilePath}..."); } tool.BackupFlash(backupFilePath, device.FlashSize); if (verbosity > VerbosityLevel.Quiet) { Console.WriteLine($"Flash backup saved to {fileName}"); } return(ExitCodes.OK); }