Skip to content

Commit

Permalink
Merge pull request #466 from WildernessLabs/bug/deprecated-flash
Browse files Browse the repository at this point in the history
deprecate the flash os command - too complex to bother implementing t…
  • Loading branch information
adrianstevens authored Feb 12, 2024
2 parents 2c8bdc2 + 52e5c98 commit 2e1ac01
Show file tree
Hide file tree
Showing 3 changed files with 8 additions and 329 deletions.
2 changes: 0 additions & 2 deletions Source/v2/Meadow.Cli/Commands/Current/BaseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public async ValueTask ExecuteAsync(IConsole console)
}
catch (Exception ex)
{
Logger?.LogError(ex.Message);
throw new CommandException(
message: ex.Message,
exitCode: (int)CommandErrors.GeneralError,
Expand All @@ -45,7 +44,6 @@ public async ValueTask ExecuteAsync(IConsole console)

if (CancellationToken.IsCancellationRequested)
{
Logger?.LogInformation($"Cancelled");
throw new CommandException(
message: "Cancelled",
exitCode: (int)CommandErrors.UserCancelled);
Expand Down
331 changes: 4 additions & 327 deletions Source/v2/Meadow.Cli/Commands/Legacy/FlashOsCommand.cs
Original file line number Diff line number Diff line change
@@ -1,344 +1,21 @@
using CliFx.Attributes;
using Meadow.CLI.Core.Internals.Dfu;
using Meadow.LibUsb;
using Meadow.Software;
using CliFx.Exceptions;
using Microsoft.Extensions.Logging;

namespace Meadow.CLI.Commands.DeviceManagement;

[Command("flash os", Description = "** Deprecated ** Use `firmware write` instead")]
public class FlashOsCommand : BaseDeviceCommand<FlashOsCommand>
{
[CommandOption("osFile", 'o', Description = "Path to the Meadow OS binary")]
public string OSFile { get; init; } = default!;

[CommandOption("runtimeFile", 'r', Description = "Path to the Meadow Runtime binary")]
public string RuntimeFile { get; init; } = default!;

[CommandOption("skipDfu", 'd', Description = "Skip DFU flash")]
public bool SkipOS { get; init; }

[CommandOption("skipEsp", 'e', Description = "Skip ESP flash")]
public bool SkipEsp { get; init; }

[CommandOption("skipRuntime", 'k', Description = "Skip updating the runtime")]
public bool SkipRuntime { get; init; } = default!;

[CommandOption("dontPrompt", 'p', Description = "Don't show bulk erase prompt")]
public bool DontPrompt { get; init; }

[CommandOption("osVersion", 'v', Description = "Flash a specific downloaded OS version - x.x.x.x")]
public string Version { get; private set; } = default!;

private FirmwareType[]? Files { get; set; } = default!;
private bool UseDfu = true;

private FileManager FileManager { get; }
private ISettingsManager Settings { get; }

private ILibUsbDevice? _libUsbDevice;

public FlashOsCommand(ISettingsManager settingsManager,
FileManager fileManager,
public FlashOsCommand(
MeadowConnectionManager connectionManager,
ILoggerFactory loggerFactory)
: base(connectionManager, loggerFactory)
{
Logger?.LogWarning($"Deprecated command. Use `firmware write` instead");

FileManager = fileManager;
Settings = settingsManager;
}

protected override async ValueTask ExecuteCommand()
{
var package = await GetSelectedPackage();

if (package == null)
{
Logger?.LogError($"Unable to get selected OS package");
return;
}

var files = new List<FirmwareType>();
if (!SkipOS) files.Add(FirmwareType.OS);
if (!SkipEsp) files.Add(FirmwareType.ESP);
if (!SkipRuntime) files.Add(FirmwareType.Runtime);
Files = files.ToArray();

if (Files == null)
{
Logger?.LogInformation($"Writing all firmware for version '{package.Version}'...");

Files = new FirmwareType[]
{
FirmwareType.OS,
FirmwareType.Runtime,
FirmwareType.ESP
};
}

if (!Files.Contains(FirmwareType.OS) && UseDfu)
{
Logger?.LogError($"DFU is only used for OS files - select an OS file or remove the DFU option");
return;
}

bool deviceSupportsOta = false; // TODO: get this based on device OS version

if (package.OsWithoutBootloader == null
|| !deviceSupportsOta
|| UseDfu)
{
UseDfu = true;
}


if (UseDfu && Files.Contains(FirmwareType.OS))
{
// get a list of ports - it will not have our meadow in it (since it should be in DFU mode)
var initialPorts = await MeadowConnectionManager.GetSerialPorts();

// get the device's serial number via DFU - we'll need it to find the device after it resets
try
{
_libUsbDevice = GetLibUsbDeviceForCurrentEnvironment();
}
catch (Exception ex)
{
Logger?.LogError(ex.Message);
return;
}

var serial = _libUsbDevice.GetDeviceSerialNumber();

// no connection is required here - in fact one won't exist
// unless maybe we add a "DFUConnection"?

try
{
await WriteOsWithDfu(package.GetFullyQualifiedPath(package.OSWithBootloader), serial);
}
catch (Exception ex)
{
Logger?.LogError($"Exception type: {ex.GetType().Name}");

// TODO: scope this to the right exception type for Win 10 access violation thing
// TODO: catch the Win10 DFU error here and change the global provider configuration to "classic"
Settings.SaveSetting(SettingsManager.PublicSettings.LibUsb, "classic");

Logger?.LogWarning("This machine requires an older version of libusb. Not to worry, I'll make the change for you, but you will have to re-run this 'firmware write' command.");
return;
}

// now wait for a new serial port to appear
var ports = await MeadowConnectionManager.GetSerialPorts();
var retryCount = 0;

var newPort = ports.Except(initialPorts).FirstOrDefault();
while (newPort == null)
{
if (retryCount++ > 10)
{
throw new Exception("New meadow device not found");
}
await Task.Delay(500);
ports = await MeadowConnectionManager.GetSerialPorts();
newPort = ports.Except(initialPorts).FirstOrDefault();
}

// configure the route to that port for the user
Settings.SaveSetting(SettingsManager.PublicSettings.Route, newPort);

var connection = ConnectionManager.GetCurrentConnection();

if (connection == null || connection.Device == null)
{
return;
}

var cancellationToken = Console?.RegisterCancellationHandler();

if (Files.Any(f => f != FirmwareType.OS))
{
await connection.WaitForMeadowAttach();

await WriteFiles();
}

var deviceInfo = await connection.Device.GetDeviceInfo(cancellationToken);

if (deviceInfo != null)
{
Logger?.LogInformation($"Done.");
Logger?.LogInformation(deviceInfo.ToString());
}
}
else
{
await WriteFiles();
}
}

private ILibUsbDevice GetLibUsbDeviceForCurrentEnvironment()
{
ILibUsbProvider provider;

// TODO: read the settings manager to decide which provider to use (default to non-classic)
var setting = Settings.GetAppSetting(SettingsManager.PublicSettings.LibUsb);
if (setting == "classic")
{
provider = new ClassicLibUsbProvider();
}
else
{
provider = new LibUsbProvider();
}

var devices = provider.GetDevicesInBootloaderMode();

switch (devices.Count)
{
case 0:
throw new Exception("No device found in bootloader mode");
case 1:
return devices[0];
default:
throw new Exception("Multiple devices found in bootloader mode - only connect one device");
}
}

private async Task<FirmwarePackage?> GetSelectedPackage()
{
await FileManager.Refresh();

var collection = FileManager.Firmware["Meadow F7"];
FirmwarePackage package;

if (Version != null)
{
// make sure the requested version exists
var existing = collection.FirstOrDefault(v => v.Version == Version);

if (existing == null)
{
Logger?.LogError($"Requested version '{Version}' not found.");
return null;
}
package = existing;
}
else
{
Version = collection.DefaultPackage?.Version ??
throw new Exception("No default version set");

package = collection.DefaultPackage;
}

return package;
}

private async ValueTask WriteFiles()
{
var connection = await GetCurrentConnection();

if (connection == null || connection.Device == null)
{
return;
}

// the connection passes messages back to us (info about actions happening on-device
connection.DeviceMessageReceived += (s, e) =>
{
if (e.message.Contains("% downloaded"))
{
// don't echo this, as we're already reporting % written
}
else
{
Logger?.LogInformation(e.message);
}
};
connection.ConnectionMessage += (s, message) =>
{
Logger?.LogInformation(message);
};


var pack = await GetSelectedPackage();

if (pack == null)
{
Logger?.LogError($"Unable to get selected OS package");
}
FirmwarePackage package = pack!;

var wasRuntimeEnabled = await connection.Device.IsRuntimeEnabled(CancellationToken);

if (wasRuntimeEnabled)
{
Logger?.LogInformation("Disabling device runtime...");
await connection.Device.RuntimeDisable();
}

connection.FileWriteProgress += (s, e) =>
{
var p = (e.completed / (double)e.total) * 100d;
Console?.Output.Write($"Writing {e.fileName}: {p:0}% \r");
};

if (Files!.Contains(FirmwareType.OS))
{
if (UseDfu)
{
// this would have already happened before now (in ExecuteAsync) so ignore
}
else
{
Logger?.LogInformation($"{Environment.NewLine}Writing OS {package.Version}...");

throw new NotSupportedException("OtA writes for the OS are not yet supported");
}
}
if (Files!.Contains(FirmwareType.Runtime))
{
Logger?.LogInformation($"{Environment.NewLine}Writing Runtime {package.Version}...");

// get the path to the runtime file
var rtpath = package.GetFullyQualifiedPath(package.Runtime);

// TODO: for serial, we must wait for the flash to complete

await connection.Device.WriteRuntime(rtpath, CancellationToken);
}
if (Files!.Contains(FirmwareType.ESP))
{
Logger?.LogInformation($"{Environment.NewLine}Writing Coprocessor files...");

var fileList = new string[]
{
package.GetFullyQualifiedPath(package.CoprocApplication),
package.GetFullyQualifiedPath(package.CoprocBootloader),
package.GetFullyQualifiedPath(package.CoprocPartitionTable),
};

await connection.Device.WriteCoprocessorFiles(fileList, CancellationToken);
}

if (wasRuntimeEnabled)
{
await connection.Device.RuntimeEnable();
}

// TODO: if we're an F7 device, we need to reset
}

private async Task WriteOsWithDfu(string osFile, string serialNumber)
protected override ValueTask ExecuteCommand()
{
await DfuUtils.FlashFile(
osFile,
serialNumber,
logger: Logger,
format: DfuUtils.DfuFlashFormat.ConsoleOut);
throw new CommandException($"Deprecated command. Use `firmware write` instead");
}
}
4 changes: 4 additions & 0 deletions Source/v2/Meadow.Cli/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@
"legacy download os": {
"commandName": "Project",
"commandLineArgs": "download os"
},
"legacy flash os": {
"commandName": "Project",
"commandLineArgs": "flash os"
}
}
}

0 comments on commit 2e1ac01

Please sign in to comment.