diff --git a/.gitignore b/.gitignore
index 3a2238d..8afdcb6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,10 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
+*.rsuser
*.suo
*.user
*.userosscache
@@ -10,48 +13,75 @@
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
+# Mono auto generated files
+mono_crash.*
+
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
-[Xx]64/
-[Xx]86/
-[Bb]uild/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
+[Ll]og/
+[Ll]ogs/
-# Visual Studio 2015 cache/options directory
+# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
-# NUNIT
+# NUnit
*.VisualState.xml
TestResult.xml
+nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
-# DNX
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
project.lock.json
+project.fragment.lock.json
artifacts/
+# Tye
+.tye/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
*_i.c
*_p.c
-*_i.h
+*_h.h
*.ilk
*.meta
*.obj
+*.iobj
*.pch
*.pdb
+*.ipdb
*.pgc
*.pgd
*.rsp
@@ -61,6 +91,7 @@ artifacts/
*.tlh
*.tmp
*.tmp_proj
+*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
@@ -81,6 +112,7 @@ ipch/
*.sdf
*.cachefile
*.VC.db
+*.VC.VC.opendb
# Visual Studio profiler
*.psess
@@ -88,6 +120,9 @@ ipch/
*.vspx
*.sap
+# Visual Studio Trace Files
+*.e2e
+
# TFS 2012 Local Workspace
$tf/
@@ -99,15 +134,25 @@ _ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
-# JustCode is a .NET coding add-in
-.JustCode
-
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
# NCrunch
_NCrunch_*
.*crunch*.local.xml
@@ -139,22 +184,27 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
-
-# TODO: Un-comment the next line if you do not want to checkin
-# your web deploy settings because they may include unencrypted
-# passwords
-#*.pubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
*.publishproj
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
# NuGet Packages
*.nupkg
+# NuGet Symbol Packages
+*.snupkg
# The packages folder can be ignored because of Package Restore
-**/packages/*
+**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
-!**/packages/build/
+!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
@@ -166,31 +216,40 @@ csx/
ecf/
rcf/
-# Microsoft Azure ApplicationInsights config file
-ApplicationInsights.config
-
-# Windows Store app package directory
+# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
-!*.[Cc]ache/
+!?*.[Cc]ache/
# Others
ClientBin/
-[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
+*.jfm
*.pfx
*.publishsettings
-node_modules/
orleans.codegen.cs
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
# RIA/Silverlight projects
Generated_Code/
@@ -201,15 +260,22 @@ _UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
+*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
@@ -219,6 +285,7 @@ FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
+node_modules/
# Visual Studio 6 build log
*.plg
@@ -226,6 +293,9 @@ FakesAssemblies/
# Visual Studio 6 workspace options file
*.opt
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
@@ -234,12 +304,151 @@ FakesAssemblies/
**/*.Server/ModelManifest.xml
_Pvt_Extensions
-# LightSwitch generated files
-GeneratedArtifacts/
-ModelManifest.xml
-
# Paket dependency manager
.paket/paket.exe
+paket-files/
# FAKE - F# Make
-.fake/
\ No newline at end of file
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+##
+## Visual studio for Mac
+##
+
+
+# globs
+Makefile.in
+*.userprefs
+*.usertasks
+config.make
+config.status
+aclocal.m4
+install-sh
+autom4te.cache/
+*.tar.gz
+tarballs/
+test-results/
+
+# Mac bundle stuff
+*.dmg
+*.app
+
+# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
+# Windows thumbnail cache files
+Thumbs.db
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+##
+## Visual Studio Code
+##
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
diff --git a/CSAUSBTool.Base/CSAUSBTool.Base.csproj b/CSAUSBTool.Base/CSAUSBTool.Base.csproj
index 2206107..025dd07 100644
--- a/CSAUSBTool.Base/CSAUSBTool.Base.csproj
+++ b/CSAUSBTool.Base/CSAUSBTool.Base.csproj
@@ -1,17 +1,19 @@
- netstandard2.0
+ netstandard2.1
Library
false
+ latest
+
-
+
all
-
+
\ No newline at end of file
diff --git a/CSAUSBTool.Base/ControlSystemsSoftware.cs b/CSAUSBTool.Base/ControlSystemsSoftware.cs
index 1a7d2c3..9dd06dc 100644
--- a/CSAUSBTool.Base/ControlSystemsSoftware.cs
+++ b/CSAUSBTool.Base/ControlSystemsSoftware.cs
@@ -14,86 +14,86 @@ namespace CSAUSBTool.Base
{
public class ControlSystemsSoftware
{
- public string Name { get; }
- private string Url { get; set; }
- private string Hash { get; }
+ public string Name { get; set; }
+ public string Description { get; set; }
public string FileName { get; set; }
- private bool Unzip { get; }
- private GitHubClient github;
+ public List Tags { get; set; }
+ public string Uri { get; set; }
+ public string? Hash { get; set; }
+ public string Platform { get; set; }
- public ControlSystemsSoftware(string name, string fileName, string url, string hash, bool unzip)
+ private Dictionary DownloadableAssets { get; set; }
+
+ private GitHubClient github = new(new ProductHeaderValue("CSAUSBTool"));
+
+ public ControlSystemsSoftware()
{
- if (url == "")
- return;
- Name = name;
- FileName = fileName;
- Url = url;
- Hash = hash;
- Unzip = unzip;
- github = new GitHubClient(new ProductHeaderValue("CSAUSBTool"));
}
- public async void Download(string path, AsyncCompletedEventHandler progress)
+ private async Task ParseGitHubRelease()
{
- if (FileName == "") return;
- //Org, repo, file Using match index to
- var rx = new Regex(@"({})({})({})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
- var matches = rx.Matches(Url);
- // Use github latest
+ var rx = new Regex(@"github://({})/({})/({})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ var matches = rx.Matches(Uri);
foreach (Match match in matches)
{
+ Release gitHubRelease;
var collection = match.Groups;
var owner = collection["owner"].Value;
var repo = collection["repo"].Value;
- var releaseMatch = collection["release"].Value;
-
- var release = await github.Repository.Release.GetLatest(owner, repo);
- foreach (var asset in release.Assets)
+ var tag = collection["release"].Value;
+ if (tag.Equals("latest"))
{
- if(!asset.Name.Contains(releaseMatch) || matches.Count == 0)
- continue;
-
- FileName = asset.Name;
- Url = asset.BrowserDownloadUrl;
+ gitHubRelease = await github.Repository.Release.GetLatest(owner, repo);
+ }
+ else
+ {
+ gitHubRelease = await github.Repository.Release.Get(owner, repo, tag);
}
+ foreach (var asset in gitHubRelease.Assets)
+ {
+ DownloadableAssets.Add(asset.Name, asset.BrowserDownloadUrl);
+ }
}
-
- if (File.Exists($"{path}\\{FileName}") && IsValid(path))
+ }
+ public async void Download(string path, AsyncCompletedEventHandler progress)
+ {
+ foreach (var (filename, uri) in DownloadableAssets)
{
- progress?.Invoke(null, null);
- return;
- }
+ if (filename.Equals("")) continue;
- if (Url.StartsWith("local:"))
- {
- CopyLocal(Url.ToString().Replace("local:", ""), path);
- progress?.Invoke(null, null);
+ if (!File.Exists($"{path}\\{filename}") || !IsValid(path)) continue;
+
+ if (uri.StartsWith("file://"))
+ {
+ CopyLocal(uri.Replace("file://", ""), path);
+ progress.Invoke(null, null);
+ return;
+ }
+ await DownloadHttp(uri, path, progress);
+ progress.Invoke(null, null);
return;
- }
- await DownloadHttp(path, progress);
+ }
}
- private async Task DownloadHttp(string path, AsyncCompletedEventHandler handler)
+ private async Task DownloadHttp(string sourceUri, string destinationPath, AsyncCompletedEventHandler handler)
{
var noCancel = new CancellationTokenSource();
- using (var client = new HttpClientDownloadWithProgress(Url,
- $"{path}\\{FileName}"))
+ using var client = new HttpClientDownloadWithProgress(sourceUri,
+ $"{destinationPath}\\{FileName}");
+ client.ProgressChanged += (totalFileSize, totalBytesDownloaded, progressPercentage) =>
{
- client.ProgressChanged += (totalFileSize, totalBytesDownloaded, progressPercentage) =>
+ if (progressPercentage == null) return;
+ if ((int) progressPercentage == 100)
{
- if (progressPercentage == null) return;
- if ((int) progressPercentage == 100)
- {
- handler?.Invoke(null, null);
- }
- };
-
- await client.StartDownload(noCancel.Token);
- }
+ handler?.Invoke(null, null);
+ }
+ };
+
+ await client.StartDownload(noCancel.Token);
}
public void CopyLocal(string sourcePath, string destPath)
@@ -108,22 +108,12 @@ public bool IsValid(string path)
return Hash == calc;
}
- public void UnzipFile(string path)
- {
- if (!Unzip) return;
- ZipFile.ExtractToDirectory($"{path}\\{FileName}", FileName);
- }
-
private static string CalculateMd5(string filepath)
{
- using (var md5 = MD5.Create())
- {
- using (var stream = File.OpenRead(filepath))
- {
- var hash = md5.ComputeHash(stream);
- return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
- }
- }
+ using var md5 = MD5.Create();
+ using var stream = File.OpenRead(filepath);
+ var hash = md5.ComputeHash(stream);
+ return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
}
\ No newline at end of file
diff --git a/CSAUSBTool.Base/ExampleYear.json b/CSAUSBTool.Base/ExampleYear.json
new file mode 100644
index 0000000..a95b9dd
--- /dev/null
+++ b/CSAUSBTool.Base/ExampleYear.json
@@ -0,0 +1,34 @@
+{
+ "Year": 2024,
+ "Program": "FRC",
+ "Software": [
+ {
+ "Name": "NI Game Tools",
+ "Description": "Game Tools for FRC - DriverStation",
+ "Tags": [
+ "Team",
+ "Event",
+ "FTA",
+ "CSA"
+ ],
+ "FileName": "",
+ "Uri": "",
+ "Hash": "",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "Example GitHub Release",
+ "Description": "Example Software",
+ "Tags": [
+ "Team",
+ "Event",
+ "FTA",
+ "CSA"
+ ],
+ "FileName": "",
+ "Uri": "github://CrossTheRoadElec/Phoenix-Releases/v24.2.0",
+ "Hash": null,
+ "Platform": "Windows"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/CSAUSBTool.Base/FIRSTSeason.cs b/CSAUSBTool.Base/FIRSTSeason.cs
index 55b782e..7445838 100644
--- a/CSAUSBTool.Base/FIRSTSeason.cs
+++ b/CSAUSBTool.Base/FIRSTSeason.cs
@@ -1,18 +1,19 @@
-using System;
+using RestSharp;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
-using System.Text;
-using System.Threading.Tasks;
+using System.Text.Json;
namespace CSAUSBTool.Base
{
public enum FIRSTProgram
{
FRC,
- FTC
+ FTC
}
+
public class FIRSTSeason
{
public int Year { get; set; }
@@ -21,7 +22,6 @@ public class FIRSTSeason
public FIRSTSeason(int year, FIRSTProgram program, string uri = "")
{
-
Year = year;
Program = program;
if (uri.Equals(""))
@@ -36,6 +36,9 @@ public List GetWebList(string uri)
return GetLocalList(uri.Replace("local:", ""));
}
+ var client = new RestClient(uri);
+ var req = new RestRequest();
+ client.DownloadDataAsync(req);
using (var client = new WebClient())
{
Console.WriteLine($"{Program}{Year}:{uri}");
@@ -45,39 +48,45 @@ public List GetWebList(string uri)
}
}
- public List GetLocalList(string uri)
+ public List FromLocal(string uri)
{
var lines = new List();
using (var file = new StreamReader(uri))
{
string line;
-
+
while ((line = file.ReadLine()) != null)
{
lines.Add(line);
}
}
+
return GetFromCsv(lines);
}
- private static List GetFromCsv(List lines)
+ private static List FromCsv(List lines)
{
var ret = new List();
lines.ForEach(line =>
{
if (line.Equals("") || line.StartsWith("#")) return;
var args = line.Split(',');
- ret.Add(new ControlSystemsSoftware(args[0], args[1], args[2], args[3], bool.Parse(args[4])));
+ ret.Add(new ControlSystemsSoftware() { });
});
return ret;
}
+ private static List FromJson(string json)
+ {
+ }
+
public override string ToString()
{
return $"{Program} - {Year}";
}
}
+
public class FRCSeason : FIRSTSeason
{
public FRCSeason(int year, string uri = "") : base(year, FIRSTProgram.FRC, uri)
@@ -91,4 +100,4 @@ public FTCSeason(int year, string uri = "") : base(year, FIRSTProgram.FTC, uri)
{
}
}
-}
+}
\ No newline at end of file
diff --git a/CSAUSBTool.Base/HttpClientDownload.cs b/CSAUSBTool.Base/HttpClientDownload.cs
index c82ca94..253a39d 100644
--- a/CSAUSBTool.Base/HttpClientDownload.cs
+++ b/CSAUSBTool.Base/HttpClientDownload.cs
@@ -41,8 +41,8 @@ private async Task DownloadFileFromHttpResponseMessage(HttpResponseMessage
var totalBytes = response.Content.Headers.ContentLength;
- using (var contentStream = await response.Content.ReadAsStreamAsync())
- return await ProcessContentStream(totalBytes, contentStream, token);
+ await using var contentStream = await response.Content.ReadAsStreamAsync();
+ return await ProcessContentStream(totalBytes, contentStream, token);
}
private async Task ProcessContentStream(long? totalDownloadSize, Stream contentStream, CancellationToken token)
@@ -52,11 +52,11 @@ private async Task ProcessContentStream(long? totalDownloadSize, Stream co
var buffer = new byte[8192];
var isMoreToRead = true;
- using (var fileStream = new FileStream(_destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
+ await using (var fileStream = new FileStream(_destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
{
do
{
- var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length);
+ var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length, token);
if (bytesRead == 0)
{
isMoreToRead = false;
@@ -64,7 +64,7 @@ private async Task ProcessContentStream(long? totalDownloadSize, Stream co
continue;
}
- await fileStream.WriteAsync(buffer, 0, bytesRead);
+ await fileStream.WriteAsync(buffer, 0, bytesRead, token);
totalBytesRead += bytesRead;
readCount += 1;
@@ -74,26 +74,22 @@ private async Task ProcessContentStream(long? totalDownloadSize, Stream co
}
while (isMoreToRead && !token.IsCancellationRequested);
}
- if (token.IsCancellationRequested)
+
+ if (!token.IsCancellationRequested) return true;
+
+ try
+ {
+ File.Delete(_destinationFilePath);
+ }
+ catch (IOException)
{
- try
- {
- File.Delete(_destinationFilePath);
- }
- catch (IOException)
- {
- }
- return false;
}
- return true;
+ return false;
}
private void TriggerProgressChanged(long? totalDownloadSize, long totalBytesRead)
{
- if (ProgressChanged == null)
- return;
-
double? progressPercentage = null;
if (totalDownloadSize.HasValue)
progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
diff --git a/CSAUSBTool.CrossPlatform.Desktop/CSAUSBTool.CrossPlatform.Desktop.csproj b/CSAUSBTool.CrossPlatform.Desktop/CSAUSBTool.CrossPlatform.Desktop.csproj
new file mode 100644
index 0000000..9905354
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform.Desktop/CSAUSBTool.CrossPlatform.Desktop.csproj
@@ -0,0 +1,20 @@
+
+
+ WinExe
+
+ net7.0
+ enable
+ true
+ app.manifest
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CSAUSBTool.CrossPlatform.Desktop/Program.cs b/CSAUSBTool.CrossPlatform.Desktop/Program.cs
new file mode 100644
index 0000000..2c777bd
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform.Desktop/Program.cs
@@ -0,0 +1,24 @@
+using System;
+
+using Avalonia;
+using Avalonia.ReactiveUI;
+
+namespace CSAUSBTool.CrossPlatform.Desktop;
+
+class Program
+{
+ // Initialization code. Don't use any Avalonia, third-party APIs or any
+ // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
+ // yet and stuff might break.
+ [STAThread]
+ public static void Main(string[] args) => BuildAvaloniaApp()
+ .StartWithClassicDesktopLifetime(args);
+
+ // Avalonia configuration, don't remove; also used by visual designer.
+ public static AppBuilder BuildAvaloniaApp()
+ => AppBuilder.Configure()
+ .UsePlatformDetect()
+ .WithInterFont()
+ .LogToTrace()
+ .UseReactiveUI();
+}
diff --git a/CSAUSBTool.CrossPlatform.Desktop/app.manifest b/CSAUSBTool.CrossPlatform.Desktop/app.manifest
new file mode 100644
index 0000000..e0ce8d0
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform.Desktop/app.manifest
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CSAUSBTool.CrossPlatform/App.axaml b/CSAUSBTool.CrossPlatform/App.axaml
new file mode 100644
index 0000000..f473fcb
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/App.axaml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/CSAUSBTool.CrossPlatform/App.axaml.cs b/CSAUSBTool.CrossPlatform/App.axaml.cs
new file mode 100644
index 0000000..dca9ac4
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/App.axaml.cs
@@ -0,0 +1,37 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+
+using CSAUSBTool.CrossPlatform.ViewModels;
+using CSAUSBTool.CrossPlatform.Views;
+
+namespace CSAUSBTool.CrossPlatform;
+
+public partial class App : Application
+{
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ switch (ApplicationLifetime)
+ {
+ case IClassicDesktopStyleApplicationLifetime desktop:
+ desktop.MainWindow = new MainWindow
+ {
+ DataContext = new MainViewModel()
+ };
+ break;
+ case ISingleViewApplicationLifetime singleViewPlatform:
+ singleViewPlatform.MainView = new MainView
+ {
+ DataContext = new MainViewModel()
+ };
+ break;
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+}
diff --git a/CSAUSBTool.CrossPlatform/Assets/avalonia-logo.ico b/CSAUSBTool.CrossPlatform/Assets/avalonia-logo.ico
new file mode 100644
index 0000000..da8d49f
Binary files /dev/null and b/CSAUSBTool.CrossPlatform/Assets/avalonia-logo.ico differ
diff --git a/CSAUSBTool.CrossPlatform/CSAUSBTool.CrossPlatform.csproj b/CSAUSBTool.CrossPlatform/CSAUSBTool.CrossPlatform.csproj
new file mode 100644
index 0000000..355507c
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/CSAUSBTool.CrossPlatform.csproj
@@ -0,0 +1,28 @@
+
+
+ net7.0
+ enable
+ latest
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ProgramYearView.axaml
+
+
+
diff --git a/CSAUSBTool.CrossPlatform/Models/ControlSystemSoftware.cs b/CSAUSBTool.CrossPlatform/Models/ControlSystemSoftware.cs
new file mode 100644
index 0000000..9a4537a
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Models/ControlSystemSoftware.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CSAUSBTool.CrossPlatform.Models
+{
+ public class ControlSystemSoftware
+ {
+ public string Name { get; set; }
+ public string Description { get; set; }
+ public List Tags { get; set; }
+ public string Uri { get; set; }
+ public string? Hash { get; set; }
+ public string Platform { get; set; }
+
+ public ControlSystemSoftware()
+ {
+
+ }
+ }
+}
diff --git a/CSAUSBTool.CrossPlatform/Models/ControlSystemSoftwareGroup.cs b/CSAUSBTool.CrossPlatform/Models/ControlSystemSoftwareGroup.cs
new file mode 100644
index 0000000..00376d1
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Models/ControlSystemSoftwareGroup.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+using ReactiveUI;
+
+namespace CSAUSBTool.CrossPlatform.Models;
+
+public class ControlSystemSoftwareGroup : ReactiveObject
+{
+ public string Tag { get; set; }
+ public string DisplayName { get; set; }
+ public List Software { get; set; } = new();
+
+ public ControlSystemSoftwareGroup()
+
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/CSAUSBTool.CrossPlatform/Models/SeasonSoftwareList.cs b/CSAUSBTool.CrossPlatform/Models/SeasonSoftwareList.cs
new file mode 100644
index 0000000..1d40beb
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Models/SeasonSoftwareList.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CSAUSBTool.CrossPlatform.Models
+{
+ public class SeasonSoftwareList
+ {
+ public int Year { get; set; }
+ public string Program { get; set; }
+ public List Software { get; set; } = new();
+
+
+ public List GetGroups()
+ {
+ var groups = new Dictionary();
+ Software.ForEach(s =>
+ {
+ // Yes, I know this is inefficient.
+ s.Tags.ForEach(tag =>
+ {
+ if (!groups.ContainsKey(tag))
+ {
+ groups.Add(tag, new ControlSystemSoftwareGroup(){DisplayName =tag, Tag=tag});
+ }
+
+ groups[tag].Software.Add(s);
+ });
+ });
+ return new List(groups.Values);
+ }
+ }
+}
diff --git a/CSAUSBTool.CrossPlatform/ViewModels/MainViewModel.cs b/CSAUSBTool.CrossPlatform/ViewModels/MainViewModel.cs
new file mode 100644
index 0000000..6f7c3f2
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/ViewModels/MainViewModel.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+
+namespace CSAUSBTool.CrossPlatform.ViewModels;
+
+public class MainViewModel : ViewModelBase
+{
+ // Add our SimpleViewModel.
+ // Note: We need at least a get-accessor for our Properties.
+ public ProgramYear ProgramYear { get; } = new ProgramYear(null, null);
+}
diff --git a/CSAUSBTool.CrossPlatform/ViewModels/ProgramYear.cs b/CSAUSBTool.CrossPlatform/ViewModels/ProgramYear.cs
new file mode 100644
index 0000000..a7f8379
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/ViewModels/ProgramYear.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Text.Json;
+using System.Threading.Tasks;
+using CSAUSBTool.CrossPlatform.Models;
+
+
+namespace CSAUSBTool.CrossPlatform.ViewModels
+{
+ public class ProgramYear
+ {
+ public int Year { get; set; }
+ public string Program { get; set; }
+
+ public List SoftwareGroups { get; set; } = new();
+ public ProgramYear(int? year, string? program)
+ {
+ year ??= DateTime.Now.Year;
+ program ??= "FRC";
+ Year = (int) year;
+ Program = program;
+
+ DownloadSoftwareLists();
+ }
+ public ProgramYear()
+ {
+ Year = DateTime.Now.Year;
+ Program = "FRC";
+ }
+
+ private void DownloadSoftwareLists()
+ {
+ var downloadUrl =
+ $"https://raw.githubusercontent.com/JamieSinn/CSA-USB-Tool/avalonia/Lists/{Program}{Year}.json";
+
+ using var client = new HttpClient();
+ var software= client.GetFromJsonAsync(downloadUrl).Result;
+
+ //await client.GetStreamAsync(downloadUrl));
+ SoftwareGroups = software.GetGroups();
+ }
+ }
+}
diff --git a/CSAUSBTool.CrossPlatform/ViewModels/ReactiveViewModel.cs b/CSAUSBTool.CrossPlatform/ViewModels/ReactiveViewModel.cs
new file mode 100644
index 0000000..9738632
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/ViewModels/ReactiveViewModel.cs
@@ -0,0 +1,40 @@
+using ReactiveUI;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CSAUSBTool.CrossPlatform.ViewModels
+{
+ // Instead of implementing "INotifyPropertyChanged" on our own we use "ReactiveObject" as
+ // our base class. Read more about it here: https://www.reactiveui.net
+ public class ReactiveViewModel : ReactiveObject
+ {
+ public ReactiveViewModel()
+ {
+ // We can listen to any property changes with "WhenAnyValue" and do whatever we want in "Subscribe".
+ this.WhenAnyValue(o => o.Name)
+ .Subscribe(o => this.RaisePropertyChanged(nameof(Greeting)));
+ }
+
+ private string? _name; // This is our backing field for Name
+
+ public string? Name
+ {
+ get => _name;
+ set =>
+ // We can use "RaiseAndSetIfChanged" to check if the value changed and automatically notify the UI
+ this.RaiseAndSetIfChanged(ref _name, value);
+ }
+
+ // Greeting will change based on a Name.
+ public string Greeting =>
+ string.IsNullOrEmpty(Name) ?
+ // If no Name is provided, use a default Greeting
+ "Hello World from Avalonia.Samples" :
+ // else Greet the User.
+ $"Hello {Name}";
+
+ }
+}
diff --git a/CSAUSBTool.CrossPlatform/ViewModels/SimpleViewModel.cs b/CSAUSBTool.CrossPlatform/ViewModels/SimpleViewModel.cs
new file mode 100644
index 0000000..b749df5
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/ViewModels/SimpleViewModel.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CSAUSBTool.CrossPlatform.ViewModels
+{
+ // This is our simple ViewModel. We need to implement the interface "INotifyPropertyChanged"
+ // in order to notify the View if any of our properties changed.
+ public class SimpleViewModel : INotifyPropertyChanged
+ {
+ // This event is implemented by "INotifyPropertyChanged" and is all we need to inform
+ // our View about changes.
+ public event PropertyChangedEventHandler? PropertyChanged;
+
+ // For convenience we add a method which will raise the above event.
+ private void RaisePropertyChanged([CallerMemberName] string? propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+ // ---- Add some Properties ----
+
+ private string? _Name; // This is our backing field for Name
+
+ public string? Name
+ {
+ get
+ {
+ return _Name;
+ }
+ set
+ {
+ // We only want to update the UI if the Name actually changed, so we check if the value is actually new
+ if (_Name != value)
+ {
+ // 1. update our backing field
+ _Name = value;
+
+ // 2. We call RaisePropertyChanged() to notify the UI about changes.
+ // We can omit the property name here because [CallerMemberName] will provide it for us.
+ RaisePropertyChanged();
+
+ // 3. Greeting also changed. So let's notify the UI about it.
+ RaisePropertyChanged(nameof(Greeting));
+ }
+ }
+ }
+
+
+ // Greeting will change based on a Name.
+ public string Greeting
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(Name))
+ {
+ // If no Name is provided, use a default Greeting
+ return "Hello World from Avalonia.Samples";
+ }
+ else
+ {
+ // else Greet the User.
+ return $"Hello {Name}";
+ }
+ }
+ }
+ }
+}
diff --git a/CSAUSBTool.CrossPlatform/ViewModels/ViewModelBase.cs b/CSAUSBTool.CrossPlatform/ViewModels/ViewModelBase.cs
new file mode 100644
index 0000000..406332a
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/ViewModels/ViewModelBase.cs
@@ -0,0 +1,7 @@
+using ReactiveUI;
+
+namespace CSAUSBTool.CrossPlatform.ViewModels;
+
+public class ViewModelBase : ReactiveObject
+{
+}
diff --git a/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareGroupView.axaml b/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareGroupView.axaml
new file mode 100644
index 0000000..ed7f986
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareGroupView.axaml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareGroupView.axaml.cs b/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareGroupView.axaml.cs
new file mode 100644
index 0000000..ccec24e
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareGroupView.axaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Controls;
+using CSAUSBTool.CrossPlatform.Models;
+
+namespace CSAUSBTool.CrossPlatform.Views
+{
+ public partial class ControlSystemSoftwareGroupView : UserControl
+ {
+ public ControlSystemSoftwareGroupView()
+ {
+ InitializeComponent();
+ SoftwareSelectionList.SelectionChanged += ListSelectionChanged;
+ }
+
+ public void ListSelectionChanged(object? sender, SelectionChangedEventArgs e)
+ {
+ Details.Text = "";
+ if (SoftwareSelectionList.SelectedItems == null) return;
+ foreach (var selectedItem in SoftwareSelectionList.SelectedItems)
+ {
+ var s = selectedItem as ControlSystemSoftware;
+ Details.Text += $"{s.Name}\n{s.Description}\n{s.Platform}\n\n";
+ }
+ }
+ }
+}
diff --git a/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareView.axaml b/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareView.axaml
new file mode 100644
index 0000000..fc20d8c
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareView.axaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareView.axaml.cs b/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareView.axaml.cs
new file mode 100644
index 0000000..7c8ca71
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Views/ControlSystemSoftwareView.axaml.cs
@@ -0,0 +1,12 @@
+using Avalonia.Controls;
+
+namespace CSAUSBTool.CrossPlatform.Views
+{
+ public partial class ControlSystemSoftwareView : UserControl
+ {
+ public ControlSystemSoftwareView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/CSAUSBTool.CrossPlatform/Views/MainView.axaml b/CSAUSBTool.CrossPlatform/Views/MainView.axaml
new file mode 100644
index 0000000..4f903ff
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Views/MainView.axaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
diff --git a/CSAUSBTool.CrossPlatform/Views/MainView.axaml.cs b/CSAUSBTool.CrossPlatform/Views/MainView.axaml.cs
new file mode 100644
index 0000000..3834ab4
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Views/MainView.axaml.cs
@@ -0,0 +1,17 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
+using ReactiveUI;
+using System;
+
+namespace CSAUSBTool.CrossPlatform.Views;
+
+public partial class MainView : UserControl
+{
+ public MainView()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/CSAUSBTool.CrossPlatform/Views/MainWindow.axaml b/CSAUSBTool.CrossPlatform/Views/MainWindow.axaml
new file mode 100644
index 0000000..caba0b5
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Views/MainWindow.axaml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSAUSBTool.CrossPlatform/Views/MainWindow.axaml.cs b/CSAUSBTool.CrossPlatform/Views/MainWindow.axaml.cs
new file mode 100644
index 0000000..a5e1ead
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Views/MainWindow.axaml.cs
@@ -0,0 +1,11 @@
+using Avalonia.Controls;
+
+namespace CSAUSBTool.CrossPlatform.Views;
+
+public partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/CSAUSBTool.CrossPlatform/Views/ProgramYearView.axaml b/CSAUSBTool.CrossPlatform/Views/ProgramYearView.axaml
new file mode 100644
index 0000000..631ff14
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Views/ProgramYearView.axaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSAUSBTool.CrossPlatform/Views/ProgramYearView.axaml.cs b/CSAUSBTool.CrossPlatform/Views/ProgramYearView.axaml.cs
new file mode 100644
index 0000000..2de0a13
--- /dev/null
+++ b/CSAUSBTool.CrossPlatform/Views/ProgramYearView.axaml.cs
@@ -0,0 +1,25 @@
+using System;
+using Avalonia.Controls;
+using CSAUSBTool.CrossPlatform.Models;
+using CSAUSBTool.CrossPlatform.ViewModels;
+using System.Collections.Generic;
+
+namespace CSAUSBTool.CrossPlatform.Views
+{
+ public partial class ProgramYearView : UserControl
+ {
+ public ProgramYearView()
+ {
+ InitializeComponent();
+
+ DataContext = new ProgramYear(null, null);
+ Tabs.SelectionChanged += new EventHandler(TabChanged);
+ }
+
+ private void TabChanged(object sender, SelectionChangedEventArgs e)
+ {
+ var selectedTab = Tabs.SelectedItem as ControlSystemSoftwareGroup;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/CSAUSBTool.Installer/CSAUSBTool.Installer.wapproj b/CSAUSBTool.Installer/CSAUSBTool.Installer.wapproj
index d5e5a78..9a56854 100644
--- a/CSAUSBTool.Installer/CSAUSBTool.Installer.wapproj
+++ b/CSAUSBTool.Installer/CSAUSBTool.Installer.wapproj
@@ -108,11 +108,10 @@
-
-
+
diff --git a/CSAUSBTool.Tests/CSAUSBTool.Tests.csproj b/CSAUSBTool.Tests/CSAUSBTool.Tests.csproj
new file mode 100644
index 0000000..0b93b8e
--- /dev/null
+++ b/CSAUSBTool.Tests/CSAUSBTool.Tests.csproj
@@ -0,0 +1,29 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
diff --git a/CSAUSBTool.Tests/UnitTest1.cs b/CSAUSBTool.Tests/UnitTest1.cs
new file mode 100644
index 0000000..d671806
--- /dev/null
+++ b/CSAUSBTool.Tests/UnitTest1.cs
@@ -0,0 +1,16 @@
+namespace CSAUSBTool.Tests
+{
+ public class Tests
+ {
+ [SetUp]
+ public void Setup()
+ {
+ }
+
+ [Test]
+ public void Test1()
+ {
+ Assert.Pass();
+ }
+ }
+}
\ No newline at end of file
diff --git a/CSAUSBTool.Tests/Usings.cs b/CSAUSBTool.Tests/Usings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/CSAUSBTool.Tests/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file
diff --git a/CSAUSBTool.sln b/CSAUSBTool.sln
index 97acf65..9575a86 100644
--- a/CSAUSBTool.sln
+++ b/CSAUSBTool.sln
@@ -5,25 +5,35 @@ VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSAUSBTool", "CSAUSBTool\CSAUSBTool.csproj", "{51473C6A-94E1-4908-9F77-15A15EC118F6}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSAUSBTool.Base", "CSAUSBTool.Base\CSAUSBTool.Base.csproj", "{5832E6E7-9A7C-49E1-945F-B37D3563EDC3}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CEE83079-35D3-480F-99E1-AC6BC51486AF}"
ProjectSection(SolutionItems) = preProject
2018Password.txt = 2018Password.txt
2019Password.txt = 2019Password.txt
2020Password.txt = 2020Password.txt
2022Password.txt = 2022Password.txt
+ Lists\FRC2024.json = Lists\FRC2024.json
FRCSoftware2017.csv = FRCSoftware2017.csv
FRCSoftware2018.csv = FRCSoftware2018.csv
FRCSoftware2019.csv = FRCSoftware2019.csv
FRCSoftware2020.csv = FRCSoftware2020.csv
FRCSoftware2022.csv = FRCSoftware2022.csv
+ FRCSoftware2023.csv = FRCSoftware2023.csv
FTCSoftware2020.csv = FTCSoftware2020.csv
+ FTCSoftware2023.csv = FTCSoftware2023.csv
+ README.md = README.md
Years.txt = Years.txt
EndProjectSection
EndProject
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "CSAUSBTool.Installer", "CSAUSBTool.Installer\CSAUSBTool.Installer.wapproj", "{55F8AF2B-E5E9-4B6F-87AE-22E12B3F5323}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSAUSBTool.CrossPlatform", "CSAUSBTool.CrossPlatform\CSAUSBTool.CrossPlatform.csproj", "{711B36C7-0C0E-46F8-8C71-15F55AA10AE8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSAUSBTool.CrossPlatform.Desktop", "CSAUSBTool.CrossPlatform.Desktop\CSAUSBTool.CrossPlatform.Desktop.csproj", "{FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSAUSBTool.Tests", "CSAUSBTool.Tests\CSAUSBTool.Tests.csproj", "{FC547A88-1927-481E-96A4-81CDFC604DC1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSAUSBTool.Base", "CSAUSBTool.Base\CSAUSBTool.Base.csproj", "{6E04964A-281A-4A0B-B068-2C98D0C24AD4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -58,26 +68,6 @@ Global
{51473C6A-94E1-4908-9F77-15A15EC118F6}.Release|x64.Build.0 = Release|Any CPU
{51473C6A-94E1-4908-9F77-15A15EC118F6}.Release|x86.ActiveCfg = Release|Any CPU
{51473C6A-94E1-4908-9F77-15A15EC118F6}.Release|x86.Build.0 = Release|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Debug|ARM.Build.0 = Debug|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Debug|ARM64.ActiveCfg = Debug|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Debug|ARM64.Build.0 = Debug|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Debug|x64.ActiveCfg = Debug|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Debug|x64.Build.0 = Debug|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Debug|x86.ActiveCfg = Debug|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Debug|x86.Build.0 = Debug|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Release|Any CPU.Build.0 = Release|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Release|ARM.ActiveCfg = Release|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Release|ARM.Build.0 = Release|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Release|ARM64.ActiveCfg = Release|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Release|ARM64.Build.0 = Release|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Release|x64.ActiveCfg = Release|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Release|x64.Build.0 = Release|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Release|x86.ActiveCfg = Release|Any CPU
- {5832E6E7-9A7C-49E1-945F-B37D3563EDC3}.Release|x86.Build.0 = Release|Any CPU
{55F8AF2B-E5E9-4B6F-87AE-22E12B3F5323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55F8AF2B-E5E9-4B6F-87AE-22E12B3F5323}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55F8AF2B-E5E9-4B6F-87AE-22E12B3F5323}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
@@ -108,6 +98,86 @@ Global
{55F8AF2B-E5E9-4B6F-87AE-22E12B3F5323}.Release|x86.ActiveCfg = Release|x86
{55F8AF2B-E5E9-4B6F-87AE-22E12B3F5323}.Release|x86.Build.0 = Release|x86
{55F8AF2B-E5E9-4B6F-87AE-22E12B3F5323}.Release|x86.Deploy.0 = Release|x86
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Debug|ARM.Build.0 = Debug|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Debug|x64.Build.0 = Debug|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Debug|x86.Build.0 = Debug|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Release|ARM.ActiveCfg = Release|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Release|ARM.Build.0 = Release|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Release|ARM64.Build.0 = Release|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Release|x64.ActiveCfg = Release|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Release|x64.Build.0 = Release|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Release|x86.ActiveCfg = Release|Any CPU
+ {711B36C7-0C0E-46F8-8C71-15F55AA10AE8}.Release|x86.Build.0 = Release|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Debug|ARM.Build.0 = Debug|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Debug|x64.Build.0 = Debug|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Debug|x86.Build.0 = Debug|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Release|ARM.ActiveCfg = Release|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Release|ARM.Build.0 = Release|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Release|ARM64.Build.0 = Release|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Release|x64.ActiveCfg = Release|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Release|x64.Build.0 = Release|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Release|x86.ActiveCfg = Release|Any CPU
+ {FA689B4D-CB1F-4BFA-83EA-4B5D7012B1EF}.Release|x86.Build.0 = Release|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Debug|ARM.Build.0 = Debug|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Debug|x64.Build.0 = Debug|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Debug|x86.Build.0 = Debug|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Release|ARM.ActiveCfg = Release|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Release|ARM.Build.0 = Release|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Release|ARM64.Build.0 = Release|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Release|x64.ActiveCfg = Release|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Release|x64.Build.0 = Release|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Release|x86.ActiveCfg = Release|Any CPU
+ {FC547A88-1927-481E-96A4-81CDFC604DC1}.Release|x86.Build.0 = Release|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Debug|ARM.Build.0 = Debug|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Debug|x64.Build.0 = Debug|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Debug|x86.Build.0 = Debug|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Release|ARM.ActiveCfg = Release|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Release|ARM.Build.0 = Release|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Release|ARM64.Build.0 = Release|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Release|x64.ActiveCfg = Release|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Release|x64.Build.0 = Release|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Release|x86.ActiveCfg = Release|Any CPU
+ {6E04964A-281A-4A0B-B068-2C98D0C24AD4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/CSAUSBTool/CSAUSBTool.csproj b/CSAUSBTool/CSAUSBTool.csproj
index e519435..919e97d 100644
--- a/CSAUSBTool/CSAUSBTool.csproj
+++ b/CSAUSBTool/CSAUSBTool.csproj
@@ -76,14 +76,14 @@
-
+
-
+
-
+
@@ -97,9 +97,9 @@
-
+
all
-
+
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..5d8722e
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,6 @@
+
+
+ enable
+ 11.0.2
+
+
diff --git a/Lists/FRC2024.json b/Lists/FRC2024.json
new file mode 100644
index 0000000..cb7dffb
--- /dev/null
+++ b/Lists/FRC2024.json
@@ -0,0 +1,181 @@
+{
+ "Year": 2024,
+ "Program": "FRC",
+ "Software": [
+ {
+ "Name": "NI Game Tools",
+ "Description": "Game Tools for FRC - DriverStation",
+ "Tags": [
+ "Team",
+ "Event",
+ "FTA",
+ "CSA"
+ ],
+ "FileName": "ni-frc-2024-game-tools_24.0.1_offline.iso",
+ "Uri": "https://download.ni.com/support/nipkg/products/ni-f/ni-frc-2024-game-tools/24.0/offline/ni-frc-2024-game-tools_24.0.1_offline.iso",
+ "Hash": "68ece2bce407356c4395c77b52e4cd3c",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "NI LabVIEW",
+ "Description": "NI LabVIEW Base",
+ "Tags": [
+ "Team",
+ "Event",
+ "FTA",
+ "CSA"
+ ],
+ "FileName": "ni-frc-2024-base-suite_24.0.0.49158-0+f6_offline.iso",
+ "Uri": "https://download.ni.com/support/nipkg/products/ni-f/ni-frc-2024-base-suite/24.0/offline/ni-frc-2024-base-suite_24.0.0.49158-0+f6_offline.iso",
+ "Hash": "147c547e41a7b57ca76a8c98d042fdf9",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "NI CompactRIO Driver",
+ "Description": "cRIO Driver - Rarely used, but can be helpful for recovering roboRIOs",
+ "Tags": [
+ "FTA",
+ "CSA"
+ ],
+ "FileName": "ni-compactrio-device-drivers_24.0.0.49260-0+f108_offline.iso",
+ "Uri": "https://download.ni.com/support/nipkg/products/ni-c/ni-compactrio-device-drivers/24.0/offline/ni-compactrio-device-drivers_24.0.0.49260-0+f108_offline.iso",
+ "Hash": "a76eef4d5d81d9f01a1c2ea860ba170a",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "WPILibInstaller Windows64",
+ "Description": "WPILib Installer",
+ "Tags": [
+ "Event",
+ "Team",
+ "CSA"
+ ],
+ "FileName": "WPILib_Windows-2024.3.1.iso",
+ "Uri": "https://packages.wpilib.workers.dev/installer/v2024.3.1/Win64/WPILib_Windows-2024.3.1.iso",
+ "Hash": "781408b02146fde5a8275f31bd55a23c",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "WPILib VS Code",
+ "Description": "WPILib Installer can source a specific VSCode version if needed.",
+ "Tags": [
+ "Event",
+ "Team",
+ "CSA"
+ ],
+ "FileName": "VSCode-1.85.1-Windows.zip",
+ "Uri": "https://update.code.visualstudio.com/1.85.1/win32-x64-archive/stable",
+ "Hash": "5621fc9203a0468f9270e2151ac2cdea",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "Season Password",
+ "Description": "WPILib Installer",
+ "Tags": [
+ "Event",
+ "Team",
+ "FTA",
+ "CSA"
+ ],
+ "FileName": "2024Password.txt",
+ "Uri": "https://raw.githubusercontent.com/JamieSinn/CSA-USB-Tool/master/2024Password.txt",
+ "Hash": "f7226fa16bbca941473c41beacf2dba4",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "CTRE Phoenix",
+ "Description": "Phoenix Offline Installer - Contains all data/supporting tools.",
+ "Tags": [
+ "Event",
+ "Team",
+ "FTA",
+ "CSA"
+ ],
+ "FileName": "Phoenix-Offline_v24.2.0.exe",
+ "Uri": "https://github.com/CrossTheRoadElec/Phoenix-Releases/releases/download/v24.2.0/Phoenix-Offline_v24.2.0.exe",
+ "Hash": "f7226fa16bbca941473c41beacf2dba4",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "RadioConfigTool",
+ "Description": "Radio Configuration Tool",
+ "Tags": [
+ "Event",
+ "Team",
+ "FTA",
+ "CSA"
+ ],
+ "FileName": "FRC_Radio_Configuration_24_0_1.zip",
+ "Uri": "https://firstfrc.blob.core.windows.net/frc2024/Radio/FRC_Radio_Configuration_24_0_1.zip",
+ "Hash": "b5b755f4947e79e43bc93dae281ba3e2",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "RadioConfigTool Israel",
+ "Description": "Radio Configuration Tool - Israel Firmware/Variant",
+ "Tags": [
+ "Event",
+ "Team",
+ "FTA",
+ "CSA"
+ ],
+ "FileName": "FRC_Radio_Configuration_24_0_1_IL.zip",
+ "Uri": "https://firstfrc.blob.core.windows.net/frc2024/Radio/FRC_Radio_Configuration_24_0_1_IL.zip",
+ "Hash": "4309bff08b61bc6bfb36e946ed1cf6d7",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "2024 Game Manual",
+ "Description": "Season ",
+ "Tags": [
+ "Event",
+ "Team",
+ "FTA",
+ "CSA"
+ ],
+ "FileName": "2024GameManual.pdf",
+ "Uri": "https://firstfrc.blob.core.windows.net/frc2024/Manual/2024GameManual.pdf",
+ "Hash": null,
+ "Platform": null
+ },
+ {
+ "Name": "NavX Libraries",
+ "Description": "NavX Libraries for the MXP version.",
+ "Tags": [
+ "Event",
+ "Team",
+ "CSA"
+ ],
+ "FileName": "navx-mxp.zip",
+ "Uri": "https://www.kauailabs.com/public_files/navx-mxp/navx-mxp.zip",
+ "Hash": null,
+ "Platform": null
+ },
+ {
+ "Name": "REV Hardware Client",
+ "Description": "REV Hardware Client w/ FRC firmware.",
+ "Tags": [
+ "Event",
+ "Team",
+ "CSA"
+ ],
+ "FileName": "REV-Hardware-Client-Setup-1.6.4-offline-FRC-2024-02-17.exe",
+ "Uri": "https://github.com/REVrobotics/REV-Software-Binaries/releases/download/rhc-1.6.4/REV-Hardware-Client-Setup-1.6.4-offline-FRC-2024-02-17.exe",
+ "Hash": "c03a4fcf1baafef68bf40db626125aee",
+ "Platform": "Windows"
+ },
+ {
+ "Name": "REV Hardware Client",
+ "Description": "REV Hardware Client w/ FRC firmware.",
+ "Tags": [
+ "Event",
+ "Team",
+ "CSA"
+ ],
+ "FileName": "REV-Hardware-Client-Setup-1.6.4-offline-FRC-2024-02-17.exe",
+ "Uri": "https://github.com/REVrobotics/REV-Software-Binaries/releases/download/rhc-1.6.4/REV-Hardware-Client-Setup-1.6.4-offline-FRC-2024-02-17.exe",
+ "Hash": "c03a4fcf1baafef68bf40db626125aee",
+ "Platform": "Windows"
+ }
+ ]
+}