Skip to content

Commit

Permalink
Merge pull request #514 from WildernessLabs/firmware_write_cleanup
Browse files Browse the repository at this point in the history
Firmware write refactor
  • Loading branch information
ctacke authored Mar 6, 2024
2 parents e26f0ec + 3b6ab9a commit 15ef96f
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 41 deletions.
19 changes: 17 additions & 2 deletions Source/v2/Meadow.Cli/Commands/Current/BaseDeviceCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,24 @@ protected async Task<IMeadowDevice> GetCurrentDevice()
return (await GetCurrentConnection()).Device ?? throw CommandException.MeadowDeviceNotFound;
}

protected async Task<IMeadowConnection> GetCurrentConnection(bool forceReconnect = false)
protected Task<IMeadowConnection> GetCurrentConnection(bool forceReconnect = false)
=> GetConnection(null, forceReconnect);

protected Task<IMeadowConnection> GetConnectionForRoute(string route, bool forceReconnect = false)
=> GetConnection(route, forceReconnect);

private async Task<IMeadowConnection> GetConnection(string? route, bool forceReconnect = false)
{
var connection = ConnectionManager.GetCurrentConnection(forceReconnect);
IMeadowConnection? connection = null;

if (route != null)
{
connection = ConnectionManager.GetConnectionForRoute(route, forceReconnect);
}
else
{
connection = ConnectionManager.GetCurrentConnection(forceReconnect);
}

if (connection != null)
{
Expand Down
120 changes: 84 additions & 36 deletions Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareWriteCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,30 @@ public FirmwareWriteCommand(ISettingsManager settingsManager, FileManager fileMa

private int _lastWriteProgress = 0;

private async Task<IMeadowConnection?> GetConnectionAndDisableRuntime()
private async Task<IMeadowConnection?> GetConnectionAndDisableRuntime(string? route = null)
{
var connection = await GetCurrentConnection(true);
IMeadowConnection? connection = null;

if (route != null)
{
connection = await GetConnectionForRoute(route, true);
}
else
{
connection = await GetCurrentConnection(true);
}

if (await connection.Device.IsRuntimeEnabled())
{
Logger?.LogInformation($"{Strings.DisablingRuntime}...");
await connection.Device.RuntimeDisable();
}

_lastWriteProgress = 0;

connection.FileWriteProgress += (s, e) =>
{
var p = (int)((e.completed / (double)e.total) * 100d);
var p = (int)(e.completed / (double)e.total * 100d);
// don't report < 10% increments (decrease spew on large files)
if (p - _lastWriteProgress < 10) { return; }
Expand All @@ -72,12 +87,6 @@ public FirmwareWriteCommand(ISettingsManager settingsManager, FileManager fileMa
Logger?.LogInformation(message);
};

if (await connection.Device.IsRuntimeEnabled())
{
Logger?.LogInformation($"{Strings.DisablingRuntime}...");
await connection.Device.RuntimeDisable();
}

return connection;
}

Expand Down Expand Up @@ -179,6 +188,9 @@ protected override async ValueTask ExecuteCommand()

if (UseDfu || dfuDevice != null || osFileWithoutBootloader == null || RequiresDfuForRuntimeUpdates(deviceInfo!))
{
// 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();

if (await WriteOsWithDfu(dfuDevice, osFileWithBootloader) == false)
{
throw new CommandException(Strings.DfuWriteFailed);
Expand All @@ -188,7 +200,7 @@ protected override async ValueTask ExecuteCommand()

await Task.Delay(1500);

connection = await GetConnectionAndDisableRuntime();
connection = await FindMeadowConnection(initialPorts);

await connection.WaitForMeadowAttach();
}
Expand Down Expand Up @@ -236,6 +248,52 @@ protected override async ValueTask ExecuteCommand()
Logger?.LogInformation(Strings.FirmwareUpdatedSuccessfully);
}

async Task<IMeadowConnection> FindMeadowConnection(IList<string> portsToIgnore)
{
IMeadowConnection? connection = null;

var newPorts = await WaitForNewSerialPorts(portsToIgnore);
string newPort = string.Empty;

if (newPorts == null)
{
throw CommandException.MeadowDeviceNotFound;
}

if (newPorts.Count == 1)
{
connection = await GetConnectionAndDisableRuntime(newPorts[0]);
newPort = newPorts[0];
}
else
{
foreach (var port in newPorts)
{
try
{
connection = await GetConnectionAndDisableRuntime(port);
newPort = port;
break;
}
catch
{
throw CommandException.MeadowDeviceNotFound;
}
}
}

Logger?.LogInformation($"Meadow found at {newPort}");

connection = await GetConnectionAndDisableRuntime();

await connection.WaitForMeadowAttach();

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

return connection;
}

private async Task<IMeadowConnection?> WriteRuntime(IMeadowConnection? connection, DeviceInfo? deviceInfo, FirmwarePackage package)
{
Logger?.LogInformation($"{Environment.NewLine}Getting runtime for {package.Version}...");
Expand All @@ -248,10 +306,7 @@ protected override async ValueTask ExecuteCommand()

private async Task<IMeadowConnection?> WriteRuntime(IMeadowConnection? connection, DeviceInfo? deviceInfo, string runtimePath, string destinationFilename)
{
if (connection == null)
{
connection = await GetConnectionAndDisableRuntime();
}
connection ??= await GetConnectionAndDisableRuntime();

Logger?.LogInformation($"{Environment.NewLine}Writing Runtime ...");

Expand Down Expand Up @@ -280,6 +335,8 @@ protected override async ValueTask ExecuteCommand()
throw CommandException.MeadowDeviceNotFound;
}

connection = await GetCurrentConnection(true);

Logger?.LogInformation($"Meadow found at {newPort}");

// configure the route to that port for the user
Expand Down Expand Up @@ -318,10 +375,7 @@ private async Task WriteEspFiles(IMeadowConnection? connection, DeviceInfo? devi
};
}

if (deviceInfo == null)
{
deviceInfo = await connection.GetDeviceInfo(CancellationToken);
}
deviceInfo ??= await connection.GetDeviceInfo(CancellationToken);

if (UseDfu || RequiresDfuForEspUpdates(deviceInfo))
{
Expand Down Expand Up @@ -405,9 +459,6 @@ private async Task WriteEspFiles(IMeadowConnection? connection, DeviceInfo? devi

private async Task<bool> WriteOsWithDfu(ILibUsbDevice? libUsbDevice, string osFile)
{
// 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
if (libUsbDevice == null)
{
Expand Down Expand Up @@ -442,7 +493,7 @@ await DfuUtils.FlashFile(
}
catch (ArgumentException)
{
Logger?.LogWarning("Unable to write firmware with Dfu - is Dfu-util installed? Run `meadow dfu install` to install");
Logger?.LogWarning("Unable to write firmware - is Dfu-util installed? Run `meadow dfu install` to install");
return false;
}
catch (Exception ex)
Expand All @@ -456,35 +507,32 @@ await DfuUtils.FlashFile(
Logger?.LogWarning("This machine requires an older version of LibUsb. The CLI settings have been updated, re-run the 'firmware write' command to update your device.");
return false;
}

var newPort = await WaitForNewSerialPort(initialPorts);

Logger?.LogInformation($"Meadow found at {newPort}");

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

return true;
}

private async Task<string> WaitForNewSerialPort(IList<string>? ignorePorts)
private async Task<IList<string>> WaitForNewSerialPorts(IList<string> ignorePorts)
{
var ports = await MeadowConnectionManager.GetSerialPorts();
var retryCount = 0;

var newPort = ports.Except(ignorePorts).FirstOrDefault();
var retryCount = 0;

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

return newPort;
return ports.Except(ignorePorts).ToList();
}

private async Task<string> WaitForNewSerialPort(IList<string>? ignorePorts)
{
var ports = await WaitForNewSerialPorts(ignorePorts);

return ports.FirstOrDefault();
}
}
5 changes: 5 additions & 0 deletions Source/v2/Meadow.Cli/MeadowConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public MeadowConnectionManager(ISettingsManager settingsManager)
throw new Exception($"No 'route' configuration set.{Environment.NewLine}Use the `meadow config route` command. For example:{Environment.NewLine} > meadow config route COM5");
}

return GetConnectionForRoute(route, forceReconnect);
}

public IMeadowConnection? GetConnectionForRoute(string route, bool forceReconnect = false)
{
// TODO: support connection changing (CLI does this rarely as it creates a new connection with each command)
if (_currentConnection != null && forceReconnect == false)
{
Expand Down
2 changes: 1 addition & 1 deletion Source/v2/Meadow.Cli/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
},
"Firmware Write version": {
"commandName": "Project",
"commandLineArgs": "firmware write -v 1.8.1.16"
"commandLineArgs": "firmware write -v 1.9.0.0"
},
"Firmware Write runtime": {
"commandName": "Project",
Expand Down
10 changes: 8 additions & 2 deletions Source/v2/Meadow.Hcom/Connections/SerialConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,14 @@ public override async Task<bool> IsRuntimeEnabled(CancellationToken? cancellatio
var timeout = CommandTimeoutSeconds * 2;
while (timeout-- > 0)
{
if (cancellationToken?.IsCancellationRequested ?? false) return false;
if (timeout <= 0) throw new TimeoutException();
if (cancellationToken?.IsCancellationRequested ?? false)
{
return false;
}
if (timeout <= 0)
{
throw new TimeoutException();
}

if (InfoMessages.Count > 0)
{
Expand Down

0 comments on commit 15ef96f

Please sign in to comment.