Skip to content
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
33 changes: 33 additions & 0 deletions Companion.Tests/ViewModels/FirmwareTabViewModelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
public void LoadDevices_ValidManufacturer_PopulatesDevices()
{
// Arrange
_viewModel.GetType()

Check warning on line 48 in Companion.Tests/ViewModels/FirmwareTabViewModelTests.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, x64)

Dereference of a possibly null reference.
.GetField("_firmwareData", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.SetValue(_viewModel, new FirmwareData
{
Expand Down Expand Up @@ -143,6 +143,39 @@
Assert.That(canExecute, Is.True);
}

[Test]
public void SelectedFirmwareSource_DefaultsToOpenIpcBuilder()
{
Assert.That(_viewModel.SelectedFirmwareSource, Is.EqualTo("OpenIPC Builder"));
}

[Test]
public void BuildFirmwareDownloadUrl_DefaultSource_UsesOpenIpcReleaseUrl()
{
var url = (string)InvokePrivateMethod(_viewModel, "BuildFirmwareDownloadUrl", "test-fw.tgz");
Assert.That(url, Is.EqualTo("https://github.com/OpenIPC/builder/releases/download/latest/test-fw.tgz"));
}

[Test]
public void BuildFirmwareDownloadUrl_GregSource_UsesRawGithubUrl()
{
_viewModel.SelectedFirmwareSource = "Greg APFPV";

var url = (string)InvokePrivateMethod(_viewModel, "BuildFirmwareDownloadUrl", "test-fw.tgz");

Assert.That(url, Is.EqualTo("https://raw.githubusercontent.com/sickgreg/OpenIPC_sickgregFPV_apfpv/main/test-fw.tgz"));
}

[Test]
public void CanUseDropdowns_GregSource_ReturnsFalse()
{
_viewModel.CanConnect = true;
_viewModel.IsConnected = true;
_viewModel.SelectedFirmwareSource = "Greg APFPV";

Assert.That(_viewModel.CanUseDropdowns, Is.False);
}

[Test]
public void UpdateSysupgradeProgressFromLine_KernelWritingPercent_MapsToRange()
{
Expand Down
4 changes: 4 additions & 0 deletions Companion/Models/OpenIPC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ public enum FileType

public const string OpenIPCBuilderGitHubApiUrl = "https://api.github.com/repos/OpenIPC/builder/releases/latest";
public const string OpenIPCFirmwareGitHubApiUrl = "https://api.github.com/repos/OpenIPC/firmware/releases/latest";
public const string GregApfpvContentsGitHubApiUrl =
"https://api.github.com/repos/sickgreg/OpenIPC_sickgregFPV_apfpv/contents";
public const string GregApfpvRawBaseUrl =
"https://raw.githubusercontent.com/sickgreg/OpenIPC_sickgregFPV_apfpv/main/";
public const string MajesticFileLoc = "/etc/majestic.yaml";
public const string WfbConfFileLoc = "/etc/wfb.conf";
public const string WfbYamlFileLoc = "/etc/wfb.yaml";
Expand Down
95 changes: 86 additions & 9 deletions Companion/ViewModels/FirmwareTabViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ private enum SysupgradePhase
private static readonly Regex MtdLineRegex =
new(@"^(?<dev>mtd\d+):\s+(?<size>[0-9a-fA-F]+)\s+(?<erasesize>[0-9a-fA-F]+)\s+""(?<name>[^""]+)""",
RegexOptions.Compiled);
private const string OpenIpcFirmwareSource = "OpenIPC Builder";
private const string GregApfpvFirmwareSource = "Greg APFPV";
#endregion

#region Observable Properties
Expand Down Expand Up @@ -106,6 +108,7 @@ private enum SysupgradePhase
[ObservableProperty] private bool _firmwareUpgradeInProgress;
[ObservableProperty] private bool _isFirmwareExpanded = true;
[ObservableProperty] private bool _isBootloaderExpanded;
[ObservableProperty] private string _selectedFirmwareSource;

#endregion

Expand All @@ -114,7 +117,7 @@ private enum SysupgradePhase
/// <summary>
/// Gets whether dropdowns should be enabled based on connection and firmware selection state
/// </summary>
public bool CanUseDropdowns => IsConnected;
public bool CanUseDropdowns => IsConnected && !IsGregApfpvSourceSelected();

/// <summary>
/// Gets whether soc dropdowns should be enabled based on connection and firmware selection state
Expand Down Expand Up @@ -147,6 +150,11 @@ private enum SysupgradePhase
/// </summary>
public ObservableCollection<string> FirmwareBySoc { get; set; } = new();
public ObservableCollection<string> Bootloaders { get; set; } = new();
public ObservableCollection<string> FirmwareSources { get; } = new()
{
OpenIpcFirmwareSource,
GregApfpvFirmwareSource
};

#endregion

Expand Down Expand Up @@ -201,6 +209,7 @@ private void InitializeProperties()
FirmwareUpgradeInProgress = false;
IsFirmwareExpanded = true;
IsBootloaderExpanded = false;
SelectedFirmwareSource = OpenIpcFirmwareSource;
}

partial void OnIsFirmwareExpandedChanged(bool value)
Expand Down Expand Up @@ -299,6 +308,15 @@ partial void OnSelectedFirmwareBySocChanged(string value)
_bRecursionSelectGuard = false;
UpdateCanExecuteCommands();
}

partial void OnSelectedFirmwareSourceChanged(string value)
{
if (string.IsNullOrWhiteSpace(value) || _bRecursionSelectGuard)
return;

ClearFirmwareSelectionsAndCollections();
_ = LoadManufacturersAsync();
}

partial void OnSelectedManufacturerChanged(string value)
{
Expand Down Expand Up @@ -593,6 +611,30 @@ private void ClearForm()
UpdateCanExecuteCommands();
}

private void ClearFirmwareSelectionsAndCollections()
{
_bRecursionSelectGuard = true;

SelectedManufacturer = string.Empty;
SelectedDevice = string.Empty;
SelectedFirmware = string.Empty;
SelectedFirmwareBySoc = string.Empty;
ManualLocalFirmwarePackageFile = string.Empty;

IsLocalFirmwarePackageSelected = false;
IsManufacturerDeviceFirmwareComboSelected = false;
IsManualUpdateEnabled = true;
IsFirmwareBySocSelected = false;

Manufacturers.Clear();
Devices.Clear();
Firmwares.Clear();
FirmwareBySoc.Clear();

_bRecursionSelectGuard = false;
UpdateCanExecuteCommands();
}

private bool CanExecuteDownloadFirmware()
{
return CanConnect &&
Expand Down Expand Up @@ -646,7 +688,9 @@ private async Task<FirmwareData> FetchFirmwareListAsync()

Logger.Information($"Fetched {filenames.Count()} firmware files.");

FirmwareData firmwareData = ProcessFilenames(filenames);
FirmwareData firmwareData = IsGregApfpvSourceSelected()
? new FirmwareData { Manufacturers = new ObservableCollection<Manufacturer>() }
: ProcessFilenames(filenames);

// Populate FirmwareBySoc
PopulateFirmwareBySoc(filenames); // Calling populate method here
Expand Down Expand Up @@ -696,11 +740,31 @@ private void PopulateFirmwareBySoc(IEnumerable<string> filenames)

private async Task<IEnumerable<string>> GetFilenamesAsync()
{
var response = await _gitHubService.GetGitHubDataAsync(OpenIPC.OpenIPCBuilderGitHubApiUrl);
var releaseData = JObject.Parse(response.ToString());
var assets = releaseData["assets"];
return assets?.Select(asset => asset["name"]?.ToString()).Where(name => !string.IsNullOrEmpty(name)) ??
Enumerable.Empty<string>();
if (IsGregApfpvSourceSelected())
{
var response = await _gitHubService.GetGitHubDataAsync(OpenIPC.GregApfpvContentsGitHubApiUrl);
if (string.IsNullOrEmpty(response))
return Enumerable.Empty<string>();

var items = JArray.Parse(response);
return items
.Where(item => item["type"]?.ToString() == "file")
.Select(item => item["name"]?.ToString())
.Where(name => !string.IsNullOrEmpty(name))
.Select(name => name!)
.Where(name => name.EndsWith(".tgz", StringComparison.OrdinalIgnoreCase));
}
else
{
var response = await _gitHubService.GetGitHubDataAsync(OpenIPC.OpenIPCBuilderGitHubApiUrl);
if (string.IsNullOrEmpty(response))
return Enumerable.Empty<string>();

var releaseData = JObject.Parse(response);
var assets = releaseData["assets"];
return assets?.Select(asset => asset["name"]?.ToString()).Where(name => !string.IsNullOrEmpty(name)) ??
Enumerable.Empty<string>();
}
}

private async Task<IEnumerable<string>> GetBootloaderFilenamesAsync()
Expand Down Expand Up @@ -1385,7 +1449,7 @@ private async Task PerformFirmwareUpgradeFromSocAsync()
if (!string.IsNullOrEmpty(firmwwareFile))
{
filename = firmwwareFile;
downloadUrl = $"https://github.com/OpenIPC/builder/releases/download/latest/{firmwwareFile}";
downloadUrl = BuildFirmwareDownloadUrl(firmwwareFile);
}

else
Expand Down Expand Up @@ -1441,7 +1505,7 @@ private async Task PerformFirmwareUpgradeFromDropdownAsync()
!string.IsNullOrEmpty(firmware?.Name))
{
filename = firmware.PackageFile;
downloadUrl = $"https://github.com/OpenIPC/builder/releases/download/latest/{filename}";
downloadUrl = BuildFirmwareDownloadUrl(filename);
}

else
Expand Down Expand Up @@ -1727,6 +1791,19 @@ public async Task SelectLocalFirmwarePackage(Window window)
}
}

private bool IsGregApfpvSourceSelected()
{
return string.Equals(SelectedFirmwareSource, GregApfpvFirmwareSource, StringComparison.OrdinalIgnoreCase);
}

private string BuildFirmwareDownloadUrl(string firmwareFilename)
{
if (IsGregApfpvSourceSelected())
return $"{OpenIPC.GregApfpvRawBaseUrl}{firmwareFilename}";

return $"https://github.com/OpenIPC/builder/releases/download/latest/{firmwareFilename}";
}

#endregion
}

Expand Down
25 changes: 18 additions & 7 deletions Companion/Views/FirmwareTabView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,24 @@
ShowGridLines="False">

<Border Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Background="#E7E7E7" CornerRadius="8" Padding="5">
<Grid RowDefinitions="Auto,Auto,Auto"
<Grid RowDefinitions="Auto,Auto,Auto,Auto"
ColumnDefinitions="Auto,*"
HorizontalAlignment="Stretch"
ShowGridLines="False">
<!-- Manufacturer -->
<TextBlock Text="Manufacturer" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" />
<!-- Firmware Source -->
<TextBlock Text="Firmware Source" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" />
<ComboBox Grid.Row="0" Grid.Column="1"
Classes="firmware-combo"
IsEnabled="{Binding CanUseDropdownsBySoc}"
SelectedItem="{Binding SelectedFirmwareSource, Mode=TwoWay}"
ItemsSource="{Binding FirmwareSources}"
HorizontalAlignment="Left"
Margin="10,0,0,0"
Background="#E7E7E7" />

<!-- Manufacturer -->
<TextBlock Text="Manufacturer" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" />
<ComboBox Grid.Row="1" Grid.Column="1"
Classes="firmware-combo"
IsEnabled="{Binding CanUseDropdowns}"
SelectedItem="{Binding SelectedManufacturer, Mode=TwoWay}"
Expand All @@ -93,8 +104,8 @@
Background="#E7E7E7" />

<!-- Device -->
<TextBlock Text="Device" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" />
<ComboBox Grid.Row="1" Grid.Column="1"
<TextBlock Text="Device" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" />
<ComboBox Grid.Row="2" Grid.Column="1"
Classes="firmware-combo"
IsEnabled="{Binding CanUseDropdowns}"
SelectedItem="{Binding SelectedDevice, Mode=TwoWay}"
Expand All @@ -104,8 +115,8 @@
Background="#E7E7E7" />

<!-- WFB/Ruby -->
<TextBlock Text="WFB/Ruby" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" />
<ComboBox Grid.Row="2" Grid.Column="1"
<TextBlock Text="WFB/Ruby" Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" />
<ComboBox Grid.Row="3" Grid.Column="1"
Classes="firmware-combo"
IsEnabled="{Binding CanUseDropdowns}"
SelectedItem="{Binding SelectedFirmware, Mode=TwoWay}"
Expand Down
Loading