Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deprecate the flash os command - too complex to bother implementing t… #466

Merged
merged 1 commit into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
}
}
}
Loading