From c8b012f75486af63326a836b73ef879f82f38735 Mon Sep 17 00:00:00 2001 From: Eric McDaniel Date: Sun, 15 Mar 2026 13:57:15 -0500 Subject: [PATCH 1/7] Rename NVS flasher utility --- .gitignore | 9 +- .../.vscode/extensions.json | 0 Firmware/NvsFlasherUtility/.vscode/tasks.json | 95 ++++++++++++++++++ .../LumenLabInstaller.code-workspace | 0 .../build/bootloader.bin | Bin .../build/firmware.bin | Bin .../build/partitions.bin | Bin .../platformio.ini | 4 +- .../src/main.cpp | 0 README.md | 5 +- lumenlab-installer.csproj | 6 +- 11 files changed, 109 insertions(+), 10 deletions(-) rename Firmware/{ConfigurationSetup => NvsFlasherUtility}/.vscode/extensions.json (100%) create mode 100644 Firmware/NvsFlasherUtility/.vscode/tasks.json rename Firmware/{ConfigurationSetup => NvsFlasherUtility}/LumenLabInstaller.code-workspace (100%) rename Firmware/{ConfigurationSetup => NvsFlasherUtility}/build/bootloader.bin (100%) rename Firmware/{ConfigurationSetup => NvsFlasherUtility}/build/firmware.bin (100%) rename Firmware/{ConfigurationSetup => NvsFlasherUtility}/build/partitions.bin (100%) rename Firmware/{ConfigurationSetup => NvsFlasherUtility}/platformio.ini (63%) rename Firmware/{ConfigurationSetup => NvsFlasherUtility}/src/main.cpp (100%) diff --git a/.gitignore b/.gitignore index 81cdbb1..362e6f7 100644 --- a/.gitignore +++ b/.gitignore @@ -362,7 +362,8 @@ MigrationBackup/ # Fody - auto-generated XML schema FodyWeavers.xsd -Firmware/ConfigurationSetup/.gitignore -Firmware/ConfigurationSetup/.pio -Firmware/ConfigurationSetup/.vscode/* -!Firmware/ConfigurationSetup/.vscode/extensions.json +Firmware/NvsFlasherUtility/.gitignore +Firmware/NvsFlasherUtility/.pio +Firmware/NvsFlasherUtility/.vscode/* +!Firmware/NvsFlasherUtility/.vscode/extensions.json +!Firmware/NvsFlasherUtility/.vscode/tasks.json diff --git a/Firmware/ConfigurationSetup/.vscode/extensions.json b/Firmware/NvsFlasherUtility/.vscode/extensions.json similarity index 100% rename from Firmware/ConfigurationSetup/.vscode/extensions.json rename to Firmware/NvsFlasherUtility/.vscode/extensions.json diff --git a/Firmware/NvsFlasherUtility/.vscode/tasks.json b/Firmware/NvsFlasherUtility/.vscode/tasks.json new file mode 100644 index 0000000..ac3c77a --- /dev/null +++ b/Firmware/NvsFlasherUtility/.vscode/tasks.json @@ -0,0 +1,95 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "PlatformIO: Upload", + "type": "shell", + "command": "platformio run --target upload", + "options": { + "statusbar": { + "hide": true + } + }, + "presentation": { + "reveal": "always", + "focus": true, + "panel": "shared" + } + }, + { + "label": "Upload and Start Debug", + "type": "shell", + "command": "platformio", + "args": [ + "run", + "-e", + "debug", + "--target", + "upload", + "&&", + "platformio", + "device", + "monitor" + ], + "problemMatcher": [], + "options": { + "statusbar": { + "hide": true + } + }, + "presentation": { + "panel": "shared", + "clear": true, + "reveal": "always", + "focus": true + } + }, + { + "label": "LumenLab Installer - Upload (release)", + "type": "shell", + "command": "platformio", + "args": [ + "run", + "-e", + "release", + "--target", + "upload", + "&&", + "platformio", + "device", + "monitor" + ], + "problemMatcher": [ + "$platformio" + ], + "options": { + "statusbar": { + "hide": true + } + }, + "presentation": { + "reveal": "always", + "focus": true, + "panel": "shared" + } + }, + { + "label": "LumenLab Installer - Clean", + "type": "shell", + "command": "platformio run --target clean -e debug -e release", + "problemMatcher": [ + "$platformio" + ], + "options": { + "statusbar": { + "hide": true + } + }, + "presentation": { + "reveal": "always", + "focus": true, + "panel": "shared" + } + } + ] +} \ No newline at end of file diff --git a/Firmware/ConfigurationSetup/LumenLabInstaller.code-workspace b/Firmware/NvsFlasherUtility/LumenLabInstaller.code-workspace similarity index 100% rename from Firmware/ConfigurationSetup/LumenLabInstaller.code-workspace rename to Firmware/NvsFlasherUtility/LumenLabInstaller.code-workspace diff --git a/Firmware/ConfigurationSetup/build/bootloader.bin b/Firmware/NvsFlasherUtility/build/bootloader.bin similarity index 100% rename from Firmware/ConfigurationSetup/build/bootloader.bin rename to Firmware/NvsFlasherUtility/build/bootloader.bin diff --git a/Firmware/ConfigurationSetup/build/firmware.bin b/Firmware/NvsFlasherUtility/build/firmware.bin similarity index 100% rename from Firmware/ConfigurationSetup/build/firmware.bin rename to Firmware/NvsFlasherUtility/build/firmware.bin diff --git a/Firmware/ConfigurationSetup/build/partitions.bin b/Firmware/NvsFlasherUtility/build/partitions.bin similarity index 100% rename from Firmware/ConfigurationSetup/build/partitions.bin rename to Firmware/NvsFlasherUtility/build/partitions.bin diff --git a/Firmware/ConfigurationSetup/platformio.ini b/Firmware/NvsFlasherUtility/platformio.ini similarity index 63% rename from Firmware/ConfigurationSetup/platformio.ini rename to Firmware/NvsFlasherUtility/platformio.ini index e8de475..b43a7c3 100644 --- a/Firmware/ConfigurationSetup/platformio.ini +++ b/Firmware/NvsFlasherUtility/platformio.ini @@ -1,6 +1,6 @@ [platformio] -name = LumenLab Installation Tool -description = A Windows-only installation tool helper to easily write NVS memory preferences on demand for global reference and config for the LumenLab. +name = LumenLab NVS Flasher Utility Tool +description = A utility helper tool included within the LumenLab Installation Tool to easily write NVS memory settings for global configuration of the LumenLab. [env] upload_speed = 921600 diff --git a/Firmware/ConfigurationSetup/src/main.cpp b/Firmware/NvsFlasherUtility/src/main.cpp similarity index 100% rename from Firmware/ConfigurationSetup/src/main.cpp rename to Firmware/NvsFlasherUtility/src/main.cpp diff --git a/README.md b/README.md index c055226..876c85f 100644 --- a/README.md +++ b/README.md @@ -7,5 +7,8 @@ A Windows-based installation tool to help keep your LumenLab up-to-date. # How To Use (More detail will be added soon, the priority is to finish the core functionality by allowing users to flash controller configuration, store settings, and re-load them. Full documention will be drafted when that is deployed.) +### Windows Defender (Protection?) -[To be finalized.] \ No newline at end of file +I don't want to pay to have this officially signed. + +For what it's worth, you can see that each executable was created by the release pipeline in this GitHub Action. You can see that it's building this repository. This repository is open source, and you can see that I'm not doing anything nefarious. Trust me bro. \ No newline at end of file diff --git a/lumenlab-installer.csproj b/lumenlab-installer.csproj index 6cdec59..edbe20f 100644 --- a/lumenlab-installer.csproj +++ b/lumenlab-installer.csproj @@ -19,13 +19,13 @@ - + Firmware.firmware.bin - + Firmware.bootloader.bin - + Firmware.partitions.bin From 95ef0898055c03c6a1ea2e81f4b165ae3316d099 Mon Sep 17 00:00:00 2001 From: Eric McDaniel Date: Sun, 15 Mar 2026 15:00:53 -0500 Subject: [PATCH 2/7] Bypass version check if first flash --- ...space => NvsFlasherUtility.code-workspace} | 0 Firmware/NvsFlasherUtility/build/firmware.bin | Bin 282784 -> 282784 bytes Firmware/NvsFlasherUtility/src/main.cpp | 6 +++--- LumenLabInstallerForm.cs | 10 ++++++++++ 4 files changed, 13 insertions(+), 3 deletions(-) rename Firmware/NvsFlasherUtility/{LumenLabInstaller.code-workspace => NvsFlasherUtility.code-workspace} (100%) diff --git a/Firmware/NvsFlasherUtility/LumenLabInstaller.code-workspace b/Firmware/NvsFlasherUtility/NvsFlasherUtility.code-workspace similarity index 100% rename from Firmware/NvsFlasherUtility/LumenLabInstaller.code-workspace rename to Firmware/NvsFlasherUtility/NvsFlasherUtility.code-workspace diff --git a/Firmware/NvsFlasherUtility/build/firmware.bin b/Firmware/NvsFlasherUtility/build/firmware.bin index 0dca9c693e117dac51c7b3bc967fa9a1d9e7a199..dee2f73a200faa947bd38da366a7442125dc8526 100644 GIT binary patch delta 127 zcmZ3mP;kLQ!3i4_%>K>e{}I2N_mIe^H80jjNOEMJwYt@Z zfiYh!BQrfCz9=<0F(-!s%r3}CEKY4+%Gkb?5rmn5n0fnBMwVNCinZN}50fvIF3`^8 c|MBtdzGrhxl0B*567ytkO delta 127 zcmZ3mP;kLQ!3i4_4%n1iB~6Qnd)Be~S^58ru9Wq=N@vV2+`G}lvFfN*qub=f*8!6i z81u!7Qj-&Na&$8?(=!+fG7^hZ!OZ5RjO|MqL6`}MnYS-xWVz+1n8bNAv`4CBb(c%Y c$M5$8*zZS`Ub5e~XX)?0FAYx~Kbi6q09WTbdH?_b diff --git a/Firmware/NvsFlasherUtility/src/main.cpp b/Firmware/NvsFlasherUtility/src/main.cpp index f0e99ac..7a796db 100644 --- a/Firmware/NvsFlasherUtility/src/main.cpp +++ b/Firmware/NvsFlasherUtility/src/main.cpp @@ -178,8 +178,8 @@ void dumpAll() } } const char *knownHighScores[] = { - "recall-high", - "phase-high"}; + "high_recall", + "high_phase"}; for (auto key : knownHighScores) { @@ -190,7 +190,7 @@ void dumpAll() continue; } - auto value = preferences.getUInt(key, 0); + auto value = preferences.getString(key, "0"); Serial.print(key); Serial.print("="); Serial.println(value); diff --git a/LumenLabInstallerForm.cs b/LumenLabInstallerForm.cs index 454539c..44d01b6 100644 --- a/LumenLabInstallerForm.cs +++ b/LumenLabInstallerForm.cs @@ -153,6 +153,16 @@ private async Task ReadConnectedDeviceVersion() WriteToLogs($"LumenLab detected on {port}"); string? version = await DeviceService.ReadFirmwareVersionAsync(port); + + if (version == null) + { + WriteToLogs("Failed to read LumenLab version. Either this is the board's first time flashing the LumenLab, or the LumenLab firmware is corrupted. Please make sure the external power is on and try again before continuing."); + BtnSync.Enabled = true; + BtnFlashFirmware.Enabled = true; + this.UseWaitCursor = false; + return false; + } + _context.FirmwareVersion = new Version(version.Substring(1)); LblInstalledVersion.Text = $"v{_context.FirmwareVersion.ToString()}"; From 9c9f754438e9598bd20709318b1bd93408f27ad4 Mon Sep 17 00:00:00 2001 From: Eric McDaniel Date: Sun, 15 Mar 2026 23:32:20 -0500 Subject: [PATCH 3/7] Establish UserSetting object --- LumenLabInstallerForm.Designer.cs | 32 ++++++++++++++++------------ LumenLabInstallerForm.cs | 35 +++++++++++++++++++++++++++++++ Services/UserSettings.cs | 17 +++++++++++++++ 3 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 Services/UserSettings.cs diff --git a/LumenLabInstallerForm.Designer.cs b/LumenLabInstallerForm.Designer.cs index b03839c..d4c23b8 100644 --- a/LumenLabInstallerForm.Designer.cs +++ b/LumenLabInstallerForm.Designer.cs @@ -257,10 +257,11 @@ private void InitializeComponent() TxtMacAddress.Font = new Font("Consolas", 11.25F, FontStyle.Regular, GraphicsUnit.Point, 0); TxtMacAddress.Location = new Point(201, 97); TxtMacAddress.Name = "TxtMacAddress"; - TxtMacAddress.PlaceholderText = "00:00:00:00:00"; - TxtMacAddress.Size = new Size(130, 25); + TxtMacAddress.PlaceholderText = "00:00:00:00:00:00"; + TxtMacAddress.Size = new Size(147, 25); TxtMacAddress.TabIndex = 13; - TxtMacAddress.Text = "00:00:00:00:00"; + TxtMacAddress.Text = "00:00:00:00:00:00"; + TxtMacAddress.TextChanged += TxtMacAddress_TextChanged; // // LblSerialBaud // @@ -286,34 +287,37 @@ private void InitializeComponent() // TxtBound1.Enabled = false; TxtBound1.Font = new Font("Consolas", 11.25F, FontStyle.Regular, GraphicsUnit.Point, 0); - TxtBound1.Location = new Point(125, 158); + TxtBound1.Location = new Point(174, 158); TxtBound1.Maximum = new decimal(new int[] { 300, 0, 0, 0 }); TxtBound1.Name = "TxtBound1"; - TxtBound1.Size = new Size(65, 25); + TxtBound1.Size = new Size(55, 25); TxtBound1.TabIndex = 17; TxtBound1.Value = new decimal(new int[] { 75, 0, 0, 0 }); + TxtBound1.ValueChanged += TxtBound1_ValueChanged; // // TxtBound2 // TxtBound2.Enabled = false; TxtBound2.Font = new Font("Consolas", 11.25F, FontStyle.Regular, GraphicsUnit.Point, 0); - TxtBound2.Location = new Point(195, 158); + TxtBound2.Location = new Point(234, 158); TxtBound2.Maximum = new decimal(new int[] { 300, 0, 0, 0 }); TxtBound2.Name = "TxtBound2"; - TxtBound2.Size = new Size(65, 25); + TxtBound2.Size = new Size(55, 25); TxtBound2.TabIndex = 18; TxtBound2.Value = new decimal(new int[] { 150, 0, 0, 0 }); + TxtBound2.ValueChanged += TxtBound2_ValueChanged; // // TxtBound3 // TxtBound3.Enabled = false; TxtBound3.Font = new Font("Consolas", 11.25F, FontStyle.Regular, GraphicsUnit.Point, 0); - TxtBound3.Location = new Point(266, 158); + TxtBound3.Location = new Point(293, 158); TxtBound3.Maximum = new decimal(new int[] { 300, 0, 0, 0 }); TxtBound3.Name = "TxtBound3"; - TxtBound3.Size = new Size(65, 25); + TxtBound3.Size = new Size(55, 25); TxtBound3.TabIndex = 19; TxtBound3.Value = new decimal(new int[] { 225, 0, 0, 0 }); + TxtBound3.ValueChanged += TxtBound3_ValueChanged; // // TxtSerialBaud // @@ -323,9 +327,10 @@ private void InitializeComponent() TxtSerialBaud.Location = new Point(201, 127); TxtSerialBaud.Maximum = new decimal(new int[] { 1000000, 0, 0, 0 }); TxtSerialBaud.Name = "TxtSerialBaud"; - TxtSerialBaud.Size = new Size(130, 25); + TxtSerialBaud.Size = new Size(147, 25); TxtSerialBaud.TabIndex = 20; TxtSerialBaud.Value = new decimal(new int[] { 921600, 0, 0, 0 }); + TxtSerialBaud.ValueChanged += TxtSerialBaud_ValueChanged; // // TxtNumLeds // @@ -334,9 +339,10 @@ private void InitializeComponent() TxtNumLeds.Location = new Point(201, 36); TxtNumLeds.Maximum = new decimal(new int[] { 3000, 0, 0, 0 }); TxtNumLeds.Name = "TxtNumLeds"; - TxtNumLeds.Size = new Size(130, 25); + TxtNumLeds.Size = new Size(147, 25); TxtNumLeds.TabIndex = 21; TxtNumLeds.Value = new decimal(new int[] { 300, 0, 0, 0 }); + TxtNumLeds.ValueChanged += TxtNumLeds_ValueChanged; // // contextMenuStrip1 // @@ -379,7 +385,7 @@ private void InitializeComponent() // RadPS4.AutoSize = true; RadPS4.Enabled = false; - RadPS4.Location = new Point(271, 67); + RadPS4.Location = new Point(281, 67); RadPS4.Name = "RadPS4"; RadPS4.Size = new Size(44, 19); RadPS4.TabIndex = 30; @@ -391,7 +397,7 @@ private void InitializeComponent() RadPS3.AutoSize = true; RadPS3.Checked = true; RadPS3.Enabled = false; - RadPS3.Location = new Point(219, 67); + RadPS3.Location = new Point(229, 67); RadPS3.Name = "RadPS3"; RadPS3.Size = new Size(44, 19); RadPS3.TabIndex = 29; diff --git a/LumenLabInstallerForm.cs b/LumenLabInstallerForm.cs index 44d01b6..ca6d5e7 100644 --- a/LumenLabInstallerForm.cs +++ b/LumenLabInstallerForm.cs @@ -19,12 +19,14 @@ public partial class LumenLabInstallerForm : Form private readonly InstallerContext _context; private readonly NetworkService _networkService; private readonly BindingSource _releaseBindingSource = []; + private UserSettings _userSettings; public LumenLabInstallerForm(NetworkService networkService, InstallerContext context) { _networkService = networkService; _context = context; + _userSettings = new UserSettings(); InitializeComponent(); ConfigureReleaseGrid(); } @@ -192,6 +194,7 @@ private void AppendLog(string text) private async void BtnFlashFirmware_Click(object sender, EventArgs e) { WriteToLogs("Starting LumenLab firmware upgrade."); + WriteToLogs($"Is using custom User Settings? {(_userSettings.isActive ? "True" : "False")}"); BtnFlashFirmware.Enabled = false; string? port = await DeviceService.DetectLumenLabPortAsync(); if (port == null) @@ -312,6 +315,8 @@ private void exitToolStripMenuItem_Click(object sender, EventArgs e) private void ChkCustomizeConfiguration_CheckedChanged(object sender, EventArgs e) { + _userSettings.isActive = !_userSettings.isActive; + TxtNumLeds.Enabled = !TxtNumLeds.Enabled; LblTotalLeds.Enabled = !LblTotalLeds.Enabled; @@ -399,4 +404,34 @@ private void LoadControllerSettingsToolStripMenuItem_Click(object sender, EventA MessageBox.Show($"Selected config file:\n{path}"); } } + + private void TxtNumLeds_ValueChanged(object sender, EventArgs e) + { + _userSettings.TotalLeds = (int)TxtNumLeds.Value; + } + + private void TxtMacAddress_TextChanged(object sender, EventArgs e) + { + _userSettings.MacAddress = TxtMacAddress.Text; + } + + private void TxtSerialBaud_ValueChanged(object sender, EventArgs e) + { + _userSettings.SerialBaud = (int)TxtSerialBaud.Value; + } + + private void TxtBound1_ValueChanged(object sender, EventArgs e) + { + _userSettings.Boundaries[0] = (int)TxtBound1.Value; + } + + private void TxtBound2_ValueChanged(object sender, EventArgs e) + { + _userSettings.Boundaries[1] = (int)TxtBound2.Value; + } + + private void TxtBound3_ValueChanged(object sender, EventArgs e) + { + _userSettings.Boundaries[2] = (int)TxtBound3.Value; + } } diff --git a/Services/UserSettings.cs b/Services/UserSettings.cs new file mode 100644 index 0000000..9f4d9c3 --- /dev/null +++ b/Services/UserSettings.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LumenLabInstaller.Services; + +public class UserSettings +{ + public bool isActive = false; + public int TotalLeds { get; set; } = 300; + public string ControllerType { get; set; } = "PS3"; + public string MacAddress { get; set; } = "00:00:00:00:00:00"; + public int SerialBaud { get; set; } = 921600; + public int[] Boundaries { get; set; } = [ 75, 150, 225 ]; +} From df9a58f53101cbe9fd089bc6aa985ff78460f607 Mon Sep 17 00:00:00 2001 From: Eric McDaniel Date: Mon, 16 Mar 2026 21:11:28 -0500 Subject: [PATCH 4/7] Add alert for the user of update available --- LumenLabInstallerForm.Designer.cs | 4 +++- LumenLabInstallerForm.cs | 30 ++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/LumenLabInstallerForm.Designer.cs b/LumenLabInstallerForm.Designer.cs index d4c23b8..9dd38f4 100644 --- a/LumenLabInstallerForm.Designer.cs +++ b/LumenLabInstallerForm.Designer.cs @@ -467,9 +467,11 @@ private void InitializeComponent() LblUpdateAlert.Font = new Font("Segoe UI", 11.25F, FontStyle.Regular, GraphicsUnit.Point, 0); LblUpdateAlert.Location = new Point(466, 88); LblUpdateAlert.Name = "LblUpdateAlert"; + LblUpdateAlert.ReadOnly = true; + LblUpdateAlert.ScrollBars = RichTextBoxScrollBars.None; LblUpdateAlert.Size = new Size(432, 21); LblUpdateAlert.TabIndex = 30; - LblUpdateAlert.Text = "Plug in your LumenLab to continue."; + LblUpdateAlert.Text = ""; // // LumenLabInstallerForm // diff --git a/LumenLabInstallerForm.cs b/LumenLabInstallerForm.cs index ca6d5e7..f2b44b7 100644 --- a/LumenLabInstallerForm.cs +++ b/LumenLabInstallerForm.cs @@ -73,6 +73,7 @@ private async void LumenLabInstallerForm_Shown(object sender, EventArgs e) { this.UseWaitCursor = true; BtnFlashFirmware.Enabled = false; + FormatGuideLabel("Plug in your LumenLab and click Scan Devices"); try { await QueryGitHub(); @@ -170,7 +171,12 @@ private async Task ReadConnectedDeviceVersion() LblInstalledVersion.Text = $"v{_context.FirmwareVersion.ToString()}"; WriteToLogs($"Currently installed version: {version}"); - //if (_context.FirmwareVersion == ) TODO: update the label to inform user if they're out of date or current. + var tag = _context.AvailableReleases?.FirstOrDefault()?.TagName; + var latestVersion = new Version(tag != null ? tag.Substring(1) : "99.99.99"); + if (_context.FirmwareVersion < latestVersion) + { + FormatGuideLabel("New update available!", Color.DarkGreen, FontStyle.Bold, 1); + } BtnFlashFirmware.Enabled = true; WriteToLogs($"Device scan complete. Ready for firmware upgrade."); @@ -191,6 +197,26 @@ private void AppendLog(string text) WriteToLogs(text); } + void FormatGuideLabel(string text, Color? color = null, FontStyle? fontStyle = null, int? sizeDelta = 0) + { + LblUpdateAlert.Clear(); + + LblUpdateAlert.Text = text; + + LblUpdateAlert.SelectionStart = 0; + LblUpdateAlert.SelectionLength = LblUpdateAlert.TextLength; + + LblUpdateAlert.SelectionAlignment = HorizontalAlignment.Center; + LblUpdateAlert.SelectionColor = color ?? Color.Black; + LblUpdateAlert.SelectionFont = new Font( + LblUpdateAlert.Font.FontFamily, + LblUpdateAlert.Font.Size + (sizeDelta ?? 0), + fontStyle ?? FontStyle.Regular + ); + + LblUpdateAlert.SelectionLength = 0; + } + private async void BtnFlashFirmware_Click(object sender, EventArgs e) { WriteToLogs("Starting LumenLab firmware upgrade."); @@ -239,7 +265,7 @@ private async void BtnFlashFirmware_Click(object sender, EventArgs e) try { - var latestRelease = _context.AvailableReleases[0] ?? null; + var latestRelease = _context.AvailableReleases?[0] ?? null; if (latestRelease == null) { // second-pass refactor: more specific error From befb91362eefe0c46be67853dcf5c01444506a1b Mon Sep 17 00:00:00 2001 From: Eric McDaniel Date: Mon, 16 Mar 2026 22:11:37 -0500 Subject: [PATCH 5/7] Add logs and user directions --- LumenLabInstallerForm.cs | 104 ++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 41 deletions(-) diff --git a/LumenLabInstallerForm.cs b/LumenLabInstallerForm.cs index f2b44b7..db092fb 100644 --- a/LumenLabInstallerForm.cs +++ b/LumenLabInstallerForm.cs @@ -73,13 +73,14 @@ private async void LumenLabInstallerForm_Shown(object sender, EventArgs e) { this.UseWaitCursor = true; BtnFlashFirmware.Enabled = false; - FormatGuideLabel("Plug in your LumenLab and click Scan Devices"); + FormatGuideLabel("Scanning device hardware"); try { await QueryGitHub(); } catch (Exception ex) { + FormatGuideLabel("Network error", Color.DarkRed, FontStyle.Bold, 1); MessageBox.Show($"Error connecting to server to download releases.{Environment.NewLine}{ex.Message}", "Network Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } @@ -88,13 +89,12 @@ private async void LumenLabInstallerForm_Shown(object sender, EventArgs e) var successfulRead = await ReadConnectedDeviceVersion(); if (!successfulRead) { - - // TODO: Just update the guide label, don't fire messagebox - //MessageBox.Show("LumenLab was not detected. Please make sure the external power is on and try again.", "LumenLab Not Detected", MessageBoxButtons.RetryCancel, MessageBoxIcon.Stop); + FormatGuideLabel("Plug in your LumenLab and click Scan Devices"); } } catch (Exception ex) { + FormatGuideLabel("Error reading device", Color.DarkRed, FontStyle.Bold, 1); MessageBox.Show($"Error checking version installed on LumenLab.{Environment.NewLine}{ex.Message}", "Device Read Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } @@ -177,6 +177,10 @@ private async Task ReadConnectedDeviceVersion() { FormatGuideLabel("New update available!", Color.DarkGreen, FontStyle.Bold, 1); } + else if (_context.FirmwareVersion == latestVersion) + { + FormatGuideLabel("You are up-to-date."); + } BtnFlashFirmware.Enabled = true; WriteToLogs($"Device scan complete. Ready for firmware upgrade."); @@ -186,38 +190,7 @@ private async Task ReadConnectedDeviceVersion() return true; } - private void AppendLog(string text) - { - if (InvokeRequired) - { - Invoke(new Action(AppendLog), text); - return; - } - - WriteToLogs(text); - } - - void FormatGuideLabel(string text, Color? color = null, FontStyle? fontStyle = null, int? sizeDelta = 0) - { - LblUpdateAlert.Clear(); - - LblUpdateAlert.Text = text; - - LblUpdateAlert.SelectionStart = 0; - LblUpdateAlert.SelectionLength = LblUpdateAlert.TextLength; - - LblUpdateAlert.SelectionAlignment = HorizontalAlignment.Center; - LblUpdateAlert.SelectionColor = color ?? Color.Black; - LblUpdateAlert.SelectionFont = new Font( - LblUpdateAlert.Font.FontFamily, - LblUpdateAlert.Font.Size + (sizeDelta ?? 0), - fontStyle ?? FontStyle.Regular - ); - - LblUpdateAlert.SelectionLength = 0; - } - - private async void BtnFlashFirmware_Click(object sender, EventArgs e) + private async Task FlashFirmware() { WriteToLogs("Starting LumenLab firmware upgrade."); WriteToLogs($"Is using custom User Settings? {(_userSettings.isActive ? "True" : "False")}"); @@ -226,7 +199,9 @@ private async void BtnFlashFirmware_Click(object sender, EventArgs e) if (port == null) { LblInstalledVersion.Text = "N/A"; - MessageBox.Show("LumenLab was disconnected. Please connect the device and run again.", "No LumenLab detected", MessageBoxButtons.RetryCancel, MessageBoxIcon.Stop); + FormatGuideLabel("Please connect the device and run again", Color.DarkRed, FontStyle.Bold); + WriteToLogs("LumenLab was disconnected. Please connect the device and run again."); + MessageBox.Show("LumenLab was disconnected. Please connect the device and run again.", "No LumenLab detected", MessageBoxButtons.OK, MessageBoxIcon.Stop); return; } @@ -234,6 +209,8 @@ private async void BtnFlashFirmware_Click(object sender, EventArgs e) if (selectedRelease == null) { + FormatGuideLabel("Please select a version to install.", Color.DarkRed, FontStyle.Bold); + WriteToLogs("Version to install was not selected."); MessageBox.Show("Please select a version to install.", "Select Version", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } @@ -265,10 +242,9 @@ private async void BtnFlashFirmware_Click(object sender, EventArgs e) try { - var latestRelease = _context.AvailableReleases?[0] ?? null; + var latestRelease = _context.AvailableReleases?[0]; if (latestRelease == null) { - // second-pass refactor: more specific error throw new Exception("Error"); } @@ -300,11 +276,14 @@ private async void BtnFlashFirmware_Click(object sender, EventArgs e) if (exitCode == 0) { + FormatGuideLabel("You are up-to-date."); WriteToLogs($"Successful installation of LumenLab {latestRelease.TagName}."); WriteToLogs("You may safely exit this tool."); + LblInstalledVersion.Text = latestRelease.TagName; } else { + FormatGuideLabel("Plug in your LumenLab and click Scan Devices"); WriteToLogs($"Failed to flash LumenLab {latestRelease.TagName}."); } } @@ -317,14 +296,47 @@ private async void BtnFlashFirmware_Click(object sender, EventArgs e) BtnFlashFirmware.Enabled = true; } } - private async void BtnSync_Click(object sender, EventArgs e) + + private async Task ReadDevice() { var successfulRead = await ReadConnectedDeviceVersion(); if (!successfulRead) { - MessageBox.Show("LumenLab was not detected. Please make sure the external power is on and try again.", "LumenLab Not Detected", MessageBoxButtons.RetryCancel, MessageBoxIcon.Stop); + FormatGuideLabel("Plug in your LumenLab and click Scan Devices"); + MessageBox.Show("LumenLab was not detected. Please make sure the external power is on and try again.", "LumenLab Not Detected", MessageBoxButtons.OK, MessageBoxIcon.Stop); } } + + private void AppendLog(string text) + { + if (InvokeRequired) + { + Invoke(new Action(AppendLog), text); + return; + } + + WriteToLogs(text); + } + + private void FormatGuideLabel(string text, Color? color = null, FontStyle? fontStyle = null, int? sizeDelta = 0) + { + LblUpdateAlert.Clear(); + + LblUpdateAlert.Text = text; + + LblUpdateAlert.SelectionStart = 0; + LblUpdateAlert.SelectionLength = LblUpdateAlert.TextLength; + + LblUpdateAlert.SelectionAlignment = HorizontalAlignment.Center; + LblUpdateAlert.SelectionColor = color ?? Color.Black; + LblUpdateAlert.SelectionFont = new Font( + LblUpdateAlert.Font.FontFamily, + LblUpdateAlert.Font.Size + (sizeDelta ?? 0), + fontStyle ?? FontStyle.Regular + ); + + LblUpdateAlert.SelectionLength = 0; + } private GitHubRelease? GetSelectedRelease() { @@ -389,6 +401,16 @@ private void WriteToLogs(string log) outputBox.AppendText($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}] - {log}{Environment.NewLine}"); } + private async void BtnFlashFirmware_Click(object sender, EventArgs e) + { + await FlashFirmware(); + } + + private async void BtnSync_Click(object sender, EventArgs e) + { + await ReadDevice(); + } + private void SaveControllerSettingsToolStripMenuItem_Click(object sender, EventArgs e) { using var dialog = new SaveFileDialog(); From 679c31f62a0830d552e9a81876fc2ce7f180bc60 Mon Sep 17 00:00:00 2001 From: Eric McDaniel Date: Wed, 18 Mar 2026 19:00:02 -0500 Subject: [PATCH 6/7] Match best practices --- LumenLabInstallerForm.Designer.cs | 4 +- LumenLabInstallerForm.cs | 130 +++++++++++++++--------------- Services/ConfigManager.cs | 4 +- 3 files changed, 68 insertions(+), 70 deletions(-) diff --git a/LumenLabInstallerForm.Designer.cs b/LumenLabInstallerForm.Designer.cs index 9dd38f4..239c6bc 100644 --- a/LumenLabInstallerForm.Designer.cs +++ b/LumenLabInstallerForm.Designer.cs @@ -184,7 +184,7 @@ private void InitializeComponent() exitToolStripMenuItem.Name = "exitToolStripMenuItem"; exitToolStripMenuItem.Size = new Size(201, 22); exitToolStripMenuItem.Text = "Exit"; - exitToolStripMenuItem.Click += exitToolStripMenuItem_Click; + exitToolStripMenuItem.Click += ExitToolStripMenuItem_Click; // // viewToolStripMenuItem // @@ -200,7 +200,7 @@ private void InitializeComponent() toggleDebugWindowToolStripMenuItem.Name = "toggleDebugWindowToolStripMenuItem"; toggleDebugWindowToolStripMenuItem.Size = new Size(143, 22); toggleDebugWindowToolStripMenuItem.Text = "Verbose Logs"; - toggleDebugWindowToolStripMenuItem.Click += toggleDebugWindowToolStripMenuItem_Click; + toggleDebugWindowToolStripMenuItem.Click += ToggleDebugWindowToolStripMenuItem_Click; // // helpToolStripMenuItem // diff --git a/LumenLabInstallerForm.cs b/LumenLabInstallerForm.cs index db092fb..5760185 100644 --- a/LumenLabInstallerForm.cs +++ b/LumenLabInstallerForm.cs @@ -19,7 +19,7 @@ public partial class LumenLabInstallerForm : Form private readonly InstallerContext _context; private readonly NetworkService _networkService; private readonly BindingSource _releaseBindingSource = []; - private UserSettings _userSettings; + private readonly UserSettings _userSettings; public LumenLabInstallerForm(NetworkService networkService, InstallerContext context) @@ -129,8 +129,6 @@ private async Task QueryGitHub() WriteToLogs($" Asset: {asset.Name} -> {asset.BrowserDownloadUrl}"); } } - - // PopulateReleaseTable(releases); } private async Task ReadConnectedDeviceVersion() @@ -145,7 +143,7 @@ private async Task ReadConnectedDeviceVersion() string? port = await DeviceService.DetectLumenLabPortAsync(); _context.PortName = port; - if (port == null) + if (port is null) { WriteToLogs("LumenLab was not detected. Please make sure the external power is on and try again."); BtnSync.Enabled = true; @@ -157,7 +155,7 @@ private async Task ReadConnectedDeviceVersion() string? version = await DeviceService.ReadFirmwareVersionAsync(port); - if (version == null) + if (version is null) { WriteToLogs("Failed to read LumenLab version. Either this is the board's first time flashing the LumenLab, or the LumenLab firmware is corrupted. Please make sure the external power is on and try again before continuing."); BtnSync.Enabled = true; @@ -177,7 +175,7 @@ private async Task ReadConnectedDeviceVersion() { FormatGuideLabel("New update available!", Color.DarkGreen, FontStyle.Bold, 1); } - else if (_context.FirmwareVersion == latestVersion) + else { FormatGuideLabel("You are up-to-date."); } @@ -196,7 +194,7 @@ private async Task FlashFirmware() WriteToLogs($"Is using custom User Settings? {(_userSettings.isActive ? "True" : "False")}"); BtnFlashFirmware.Enabled = false; string? port = await DeviceService.DetectLumenLabPortAsync(); - if (port == null) + if (port is null) { LblInstalledVersion.Text = "N/A"; FormatGuideLabel("Please connect the device and run again", Color.DarkRed, FontStyle.Bold); @@ -207,7 +205,7 @@ private async Task FlashFirmware() var selectedRelease = GetSelectedRelease(); - if (selectedRelease == null) + if (selectedRelease is null) { FormatGuideLabel("Please select a version to install.", Color.DarkRed, FontStyle.Bold); WriteToLogs("Version to install was not selected."); @@ -243,7 +241,7 @@ private async Task FlashFirmware() try { var latestRelease = _context.AvailableReleases?[0]; - if (latestRelease == null) + if (latestRelease is null) { throw new Exception("Error"); } @@ -307,17 +305,6 @@ private async Task ReadDevice() } } - private void AppendLog(string text) - { - if (InvokeRequired) - { - Invoke(new Action(AppendLog), text); - return; - } - - WriteToLogs(text); - } - private void FormatGuideLabel(string text, Color? color = null, FontStyle? fontStyle = null, int? sizeDelta = 0) { LblUpdateAlert.Clear(); @@ -346,59 +333,20 @@ private void FormatGuideLabel(string text, Color? color = null, FontStyle? fontS return null; } - private void exitToolStripMenuItem_Click(object sender, EventArgs e) - { - Application.Exit(); - } - - private void ChkCustomizeConfiguration_CheckedChanged(object sender, EventArgs e) - { - _userSettings.isActive = !_userSettings.isActive; - - TxtNumLeds.Enabled = !TxtNumLeds.Enabled; - LblTotalLeds.Enabled = !LblTotalLeds.Enabled; - - LblControllerType.Enabled = !LblControllerType.Enabled; - RadPS3.Enabled = !RadPS3.Enabled; - - TxtMacAddress.Enabled = !TxtMacAddress.Enabled; - LblMacAddress.Enabled = !LblMacAddress.Enabled; - - TxtSerialBaud.Enabled = !TxtSerialBaud.Enabled; - LblSerialBaud.Enabled = !LblSerialBaud.Enabled; - - TxtBound1.Enabled = !TxtBound1.Enabled; - TxtBound2.Enabled = !TxtBound2.Enabled; - TxtBound3.Enabled = !TxtBound3.Enabled; - LblBoundaries.Enabled = !LblBoundaries.Enabled; - } - - private void toggleDebugWindowToolStripMenuItem_Click(object sender, EventArgs e) + private void WriteToLogs(string log) { - toggleDebugWindowToolStripMenuItem.Checked = !toggleDebugWindowToolStripMenuItem.Checked; - outputBox.Visible = !outputBox.Visible; - if (outputBox.Visible) - { - this.Height += outputBox.Height; - } - else - { - this.Height -= outputBox.Height; - } + outputBox.AppendText($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}] - {log}{Environment.NewLine}"); } - private void ChkClearMemory_CheckedChanged(object sender, EventArgs e) + private void AppendLog(string text) { - if (ChkClearMemory.Checked) + if (InvokeRequired) { - MessageBox.Show("Nice try, cheater.", "Failed to erase high score ", MessageBoxButtons.OK, MessageBoxIcon.Error); - ChkClearMemory.Checked = false; + Invoke(new Action(AppendLog), text); + return; } - } - private void WriteToLogs(string log) - { - outputBox.AppendText($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}] - {log}{Environment.NewLine}"); + WriteToLogs(text); } private async void BtnFlashFirmware_Click(object sender, EventArgs e) @@ -453,6 +401,56 @@ private void LoadControllerSettingsToolStripMenuItem_Click(object sender, EventA } } + private void ExitToolStripMenuItem_Click(object sender, EventArgs e) + { + Application.Exit(); + } + + private void ChkCustomizeConfiguration_CheckedChanged(object sender, EventArgs e) + { + _userSettings.isActive = !_userSettings.isActive; + + TxtNumLeds.Enabled = !TxtNumLeds.Enabled; + LblTotalLeds.Enabled = !LblTotalLeds.Enabled; + + LblControllerType.Enabled = !LblControllerType.Enabled; + RadPS3.Enabled = !RadPS3.Enabled; + + TxtMacAddress.Enabled = !TxtMacAddress.Enabled; + LblMacAddress.Enabled = !LblMacAddress.Enabled; + + TxtSerialBaud.Enabled = !TxtSerialBaud.Enabled; + LblSerialBaud.Enabled = !LblSerialBaud.Enabled; + + TxtBound1.Enabled = !TxtBound1.Enabled; + TxtBound2.Enabled = !TxtBound2.Enabled; + TxtBound3.Enabled = !TxtBound3.Enabled; + LblBoundaries.Enabled = !LblBoundaries.Enabled; + } + + private void ToggleDebugWindowToolStripMenuItem_Click(object sender, EventArgs e) + { + toggleDebugWindowToolStripMenuItem.Checked = !toggleDebugWindowToolStripMenuItem.Checked; + outputBox.Visible = !outputBox.Visible; + if (outputBox.Visible) + { + this.Height += outputBox.Height; + } + else + { + this.Height -= outputBox.Height; + } + } + + private void ChkClearMemory_CheckedChanged(object sender, EventArgs e) + { + if (ChkClearMemory.Checked) + { + MessageBox.Show("Nice try, cheater.", "Failed to erase high score ", MessageBoxButtons.OK, MessageBoxIcon.Error); + ChkClearMemory.Checked = false; + } + } + private void TxtNumLeds_ValueChanged(object sender, EventArgs e) { _userSettings.TotalLeds = (int)TxtNumLeds.Value; diff --git a/Services/ConfigManager.cs b/Services/ConfigManager.cs index 9d31f46..e5d147e 100644 --- a/Services/ConfigManager.cs +++ b/Services/ConfigManager.cs @@ -32,9 +32,9 @@ public static Config LoadConfig() var json = File.ReadAllText(AppPaths.ConfigFilePath); var config = JsonSerializer.Deserialize(json); - if (config == null || string.IsNullOrWhiteSpace(config.Version)) + if (string.IsNullOrWhiteSpace(config?.Version)) { - throw new Exception("Invalid config file content."); + throw new InvalidOperationException("Config version is missing or empty."); } return config; From d1cc930ee4a904c53d89fc123b5125f3db4aa5c4 Mon Sep 17 00:00:00 2001 From: Eric McDaniel Date: Wed, 18 Mar 2026 19:48:25 -0500 Subject: [PATCH 7/7] Refactor flash process --- LumenLabInstallerForm.cs | 216 ++++++++++++++++++++++---------------- Services/DeviceService.cs | 4 +- 2 files changed, 130 insertions(+), 90 deletions(-) diff --git a/LumenLabInstallerForm.cs b/LumenLabInstallerForm.cs index 5760185..2fec077 100644 --- a/LumenLabInstallerForm.cs +++ b/LumenLabInstallerForm.cs @@ -10,6 +10,7 @@ using LumenLabInstaller.Models; using System.Reflection; using System.IO.Compression; +using System.IO; namespace LumenLabInstaller; @@ -99,38 +100,6 @@ private async void LumenLabInstallerForm_Shown(object sender, EventArgs e) } } - private async Task QueryGitHub() - { - WriteToLogs("Querying GitHub to check for updates."); - var releases = await _networkService.GetReleasesAsync(); - - _context.AvailableReleases = releases.OrderByDescending(r => r.PublishedAt).ToList(); - - var gridRows = releases - .OrderByDescending(r => r.PublishedAt) - .Select(r => new ReleaseGridRow - { - TagName = r.TagName ?? string.Empty, - Name = r.Name?.Substring(r.Name.IndexOf("-") + 2) ?? string.Empty, - PublishedAt = r.PublishedAt ?? new DateTime(), - Release = r - }) - .ToList(); - - _releaseBindingSource.DataSource = gridRows; - - LblLatestRelease.Text = releases[0].TagName; - - foreach (var release in releases) - { - WriteToLogs($"{release.TagName} - {release.PublishedAt}"); - foreach (var asset in release.Assets) - { - WriteToLogs($" Asset: {asset.Name} -> {asset.BrowserDownloadUrl}"); - } - } - } - private async Task ReadConnectedDeviceVersion() { BtnSync.Enabled = false; @@ -192,15 +161,51 @@ private async Task FlashFirmware() { WriteToLogs("Starting LumenLab firmware upgrade."); WriteToLogs($"Is using custom User Settings? {(_userSettings.isActive ? "True" : "False")}"); + + try + { + if (!(await ValidateHardware())) return; + if (!(await DownloadResources())) return; + + var exitCode = await FlashWithEspTool(); + var latestTag = _context.AvailableReleases?[0].TagName; + + if (exitCode == 0) + { + FormatGuideLabel("You are up-to-date."); + WriteToLogs($"Successful installation of LumenLab {latestTag}."); + WriteToLogs("You may safely exit this tool."); + MessageBox.Show($"Successful installation of LumenLab {latestTag}.", "Installation Complete", MessageBoxButtons.OK, MessageBoxIcon.Information); + LblInstalledVersion.Text = latestTag; + } + else + { + FormatGuideLabel("Plug in your LumenLab and click Scan Devices"); + WriteToLogs($"Failed to flash LumenLab {latestTag}."); + MessageBox.Show($"Failed to flash LumenLab {latestTag}.", "Installation Failure", MessageBoxButtons.OK, MessageBoxIcon.Stop); + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + finally + { + BtnFlashFirmware.Enabled = true; + } + } + + private async Task ValidateHardware() + { BtnFlashFirmware.Enabled = false; - string? port = await DeviceService.DetectLumenLabPortAsync(); - if (port is null) + _context.PortName = await DeviceService.DetectLumenLabPortAsync(); + if (_context.PortName is null) { LblInstalledVersion.Text = "N/A"; FormatGuideLabel("Please connect the device and run again", Color.DarkRed, FontStyle.Bold); WriteToLogs("LumenLab was disconnected. Please connect the device and run again."); MessageBox.Show("LumenLab was disconnected. Please connect the device and run again.", "No LumenLab detected", MessageBoxButtons.OK, MessageBoxIcon.Stop); - return; + return false; } var selectedRelease = GetSelectedRelease(); @@ -210,7 +215,7 @@ private async Task FlashFirmware() FormatGuideLabel("Please select a version to install.", Color.DarkRed, FontStyle.Bold); WriteToLogs("Version to install was not selected."); MessageBox.Show("Please select a version to install.", "Select Version", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; + return false; } var selectedReleaseVersionId = new Version(selectedRelease?.TagName?.Substring(1) ?? "0.0.0"); @@ -223,7 +228,7 @@ private async Task FlashFirmware() { WriteToLogs("Cancelled LumenLab firmware update."); BtnFlashFirmware.Enabled = true; - return; + return false; } } else if (selectedReleaseVersionId < _context.FirmwareVersion) @@ -233,68 +238,71 @@ private async Task FlashFirmware() { WriteToLogs("Cancelled LumenLab firmware update."); BtnFlashFirmware.Enabled = true; - return; + return false; } } BtnFlashFirmware.Enabled = false; + return true; + } - try + private async Task DownloadResources() + { + var latestRelease = _context.AvailableReleases?[0]; + if (latestRelease is null) { - var latestRelease = _context.AvailableReleases?[0]; - if (latestRelease is null) - { - throw new Exception("Error"); - } + throw new Exception("Error"); + } - string downloadPath = Path.Combine(AppPaths.BinariesPath, latestRelease.TagName ?? "v99.99.99"); - if (!Directory.Exists(downloadPath)) - { - WriteToLogs($"Creating directory {downloadPath}"); - Directory.CreateDirectory(downloadPath); - } + string downloadPath = Path.Combine(AppPaths.BinariesPath, latestRelease.TagName ?? "v99.99.99"); + if (!Directory.Exists(downloadPath)) + { + WriteToLogs($"Creating directory {downloadPath}"); + Directory.CreateDirectory(downloadPath); + } - WriteToLogs($"Downloading LumenLab {latestRelease.TagName}"); - var cts = new CancellationTokenSource(); - var result = await _networkService.DownloadAsync( - new Uri($"https://github.com/ericmcdaniel/lumenlab/releases/download/{latestRelease.TagName}/lumenlab-firmware.zip"), - Path.Combine(downloadPath, "lumenlab-firmware.zip") - ); + WriteToLogs($"Downloading LumenLab {latestRelease.TagName}"); + using var cts = new CancellationTokenSource(); + string zipPath = Path.Combine(downloadPath, "lumenlab-firmware.zip"); - string compressedLumenLabPath = Path.Combine(downloadPath, "lumenlab-firmware.zip"); + try + { + var result = await _networkService.DownloadAsync(new Uri($"https://github.com/ericmcdaniel/lumenlab/releases/download/{latestRelease.TagName}/lumenlab-firmware.zip"), zipPath); + if (!File.Exists(zipPath)) + { + throw new FileNotFoundException("Download failed; firmware zip not found."); + } - ZipFile.ExtractToDirectory(compressedLumenLabPath, downloadPath, true); - File.Delete(compressedLumenLabPath); + ZipFile.ExtractToDirectory(zipPath, downloadPath, true); WriteToLogs("Download complete."); WriteToLogs($"Downloaded {result.BytesWritten.Bytes()}."); - - string esptoolFullCmd = $"--chip esp32 --baud 921600 --port {port} write_flash -z 0x1000 {Path.Combine(downloadPath, "bootloader.bin")} 0x8000 {Path.Combine(downloadPath, "partitions.bin")} 0x10000 {Path.Combine(downloadPath, "firmware.bin")}"; - WriteToLogs($"Running esptool.exe {esptoolFullCmd}"); - var exitCode = await DeviceService.RunEsptoolAsync(esptoolFullCmd, AppendLog, cts.Token); - - if (exitCode == 0) - { - FormatGuideLabel("You are up-to-date."); - WriteToLogs($"Successful installation of LumenLab {latestRelease.TagName}."); - WriteToLogs("You may safely exit this tool."); - LblInstalledVersion.Text = latestRelease.TagName; - } - else - { - FormatGuideLabel("Plug in your LumenLab and click Scan Devices"); - WriteToLogs($"Failed to flash LumenLab {latestRelease.TagName}."); - } + return true; } - catch (Exception ex) + catch (Exception ex) when (ex is HttpRequestException or IOException) { - MessageBox.Show(ex.Message); + WriteToLogs($"Error during firmware update: {ex.Message}"); + return false; } finally { - BtnFlashFirmware.Enabled = true; + if (File.Exists(zipPath)) + { + File.Delete(zipPath); + } } } + private async Task FlashWithEspTool() + { + var latestRelease = _context.AvailableReleases?[0]; + string downloadPath = Path.Combine(AppPaths.BinariesPath, latestRelease.TagName ?? "v99.99.99"); + string esptoolFullCmd = $"--chip esp32 --baud 921600 --port {_context.PortName} write_flash -z 0x1000 {Path.Combine(downloadPath, "bootloader.bin")} 0x8000 {Path.Combine(downloadPath, "partitions.bin")} 0x10000 {Path.Combine(downloadPath, "firmware.bin")}"; + + WriteToLogs($"Running esptool.exe {esptoolFullCmd}"); + var exitCode = await DeviceService.RunEsptoolAsync(esptoolFullCmd, AppendLog); + return exitCode; + } + private async Task ReadDevice() { var successfulRead = await ReadConnectedDeviceVersion(); @@ -304,7 +312,47 @@ private async Task ReadDevice() MessageBox.Show("LumenLab was not detected. Please make sure the external power is on and try again.", "LumenLab Not Detected", MessageBoxButtons.OK, MessageBoxIcon.Stop); } } - + + private async Task QueryGitHub() + { + WriteToLogs("Querying GitHub to check for updates."); + var releases = await _networkService.GetReleasesAsync(); + + _context.AvailableReleases = releases.OrderByDescending(r => r.PublishedAt).ToList(); + + var gridRows = releases + .OrderByDescending(r => r.PublishedAt) + .Select(r => new ReleaseGridRow + { + TagName = r.TagName ?? string.Empty, + Name = r.Name?.Substring(r.Name.IndexOf("-") + 2) ?? string.Empty, + PublishedAt = r.PublishedAt ?? new DateTime(), + Release = r + }) + .ToList(); + + _releaseBindingSource.DataSource = gridRows; + + LblLatestRelease.Text = releases[0].TagName; + + foreach (var release in releases) + { + WriteToLogs($"{release.TagName} - {release.PublishedAt}"); + foreach (var asset in release.Assets) + { + WriteToLogs($" Asset: {asset.Name} -> {asset.BrowserDownloadUrl}"); + } + } + } + + private GitHubRelease? GetSelectedRelease() + { + if (_releaseBindingSource.Current is ReleaseGridRow row) + return row.Release; + + return null; + } + private void FormatGuideLabel(string text, Color? color = null, FontStyle? fontStyle = null, int? sizeDelta = 0) { LblUpdateAlert.Clear(); @@ -325,14 +373,6 @@ private void FormatGuideLabel(string text, Color? color = null, FontStyle? fontS LblUpdateAlert.SelectionLength = 0; } - private GitHubRelease? GetSelectedRelease() - { - if (_releaseBindingSource.Current is ReleaseGridRow row) - return row.Release; - - return null; - } - private void WriteToLogs(string log) { outputBox.AppendText($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}] - {log}{Environment.NewLine}"); diff --git a/Services/DeviceService.cs b/Services/DeviceService.cs index 90ba9cb..1d43a94 100644 --- a/Services/DeviceService.cs +++ b/Services/DeviceService.cs @@ -86,7 +86,7 @@ public static void EnsureEsptoolExists() resourceStream.CopyTo(fileStream); } - public static async Task RunEsptoolAsync(string arguments, Action onOutput, CancellationToken cancellationToken) + public static async Task RunEsptoolAsync(string arguments, Action onOutput) { EnsureEsptoolExists(); var psi = new ProcessStartInfo @@ -118,7 +118,7 @@ public static async Task RunEsptoolAsync(string arguments, Action o process.BeginOutputReadLine(); process.BeginErrorReadLine(); - await process.WaitForExitAsync(cancellationToken); + await process.WaitForExitAsync(); return process.ExitCode; }