diff --git a/botterm/.vs/botterm/v16/.suo b/botterm/.vs/botterm/v16/.suo index 86739f8..09b380d 100644 Binary files a/botterm/.vs/botterm/v16/.suo and b/botterm/.vs/botterm/v16/.suo differ diff --git a/botterm/botterm/CanInterface.cs b/botterm/botterm/CanInterface.cs index c76873d..1637aab 100644 --- a/botterm/botterm/CanInterface.cs +++ b/botterm/botterm/CanInterface.cs @@ -1,6 +1,9 @@ using System; using System.Runtime.InteropServices; using System.Windows.Forms; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Concurrent; namespace BootloaderGUI { @@ -8,7 +11,11 @@ namespace BootloaderGUI { private const string DLL_NAME = "slcan.dll"; public IntPtr hDevice { get; private set; } = IntPtr.Zero; + public event Action ErrorReceived; // событие для ошибок + private CancellationTokenSource rxCts; + private ConcurrentQueue rxQueue = new ConcurrentQueue(); private bool slcanLoaded = false; + private bool waitingForResponse = false; public const ushort SLCAN_BR_CIA_1000K = 0x8000; @@ -313,44 +320,95 @@ namespace BootloaderGUI public bool WaitForResponse(uint timeoutMs, out UInt16 error) { error = 0; + waitingForResponse = true; // включаем режим ожидания - // 1) Очистим RX буфер у устройства - try + DateTime start = DateTime.Now; + while ((DateTime.Now - start).TotalMilliseconds < timeoutMs) { - // SLCAN_PURGE_RX_CLEAR определён в заголовке - SlCan_DevicePurge(hDevice, SLCAN_PURGE_RX_CLEAR); - } - catch - { - // если purge не доступен/ошибка — можно продолжить, но логировать - } - - // 2) Ждём один свежий пакет (блокирующе, с таймаутом) - SLCAN_MESSAGE[] buffer = new SLCAN_MESSAGE[1]; - buffer[0].Data = new byte[8]; - - if (SlCan_DeviceReadMessages(hDevice, timeoutMs, buffer, 1, out uint read)) - { - if (read > 0) + if (rxQueue.TryDequeue(out var msg)) { - byte[] response = buffer[0].Data; + byte[] response = msg.Data; + + waitingForResponse = false; // мы получили ответ — отключаем режим if (response[0] == 0) - { return true; - } else { error = (UInt16)((response[1] << 8) | response[2]); return false; } } + Thread.Sleep(1); } - error = 0xFFFF; // таймаут / ничего не пришло + waitingForResponse = false; // таймаут + error = 0xFFFF; return false; } + + + + + + + /// + /// Запуск фонового приёма сообщений только с ID=123. + /// + public void StartBackgroundReceive() + { + rxCts = new CancellationTokenSource(); + Task.Run(() => + { + SLCAN_MESSAGE[] buffer = new SLCAN_MESSAGE[1]; + buffer[0].Data = new byte[8]; + + while (!rxCts.Token.IsCancellationRequested) + { + if (SlCan_DeviceReadMessages(hDevice, 200, buffer, 1, out uint read) && read > 0) + { + if (buffer[0].ID == 123) + { + if (waitingForResponse) + { + // Кладём пакет в очередь для WaitForResponse + rxQueue.Enqueue(buffer[0]); + } + // Проверяем, ошибка ли это + byte[] resp = buffer[0].Data; + if (resp[0] != 0) // ошибка + { + UInt16 err = (UInt16)((resp[1] << 8) | resp[2]); + ErrorReceived?.Invoke(err); // вызываем событие + } + } + } + else + { + Thread.Sleep(1); + } + } + }, rxCts.Token); + } + + + /// + /// Остановка фонового приёма. + /// + public void StopBackgroundReceive() + { + try + { + rxCts?.Cancel(); + } + catch { } + } + + + + + public void Disconnect() { if (hDevice != IntPtr.Zero) diff --git a/botterm/botterm/Program.cs b/botterm/botterm/Program.cs index 69e265c..82b4f99 100644 --- a/botterm/botterm/Program.cs +++ b/botterm/botterm/Program.cs @@ -112,9 +112,18 @@ namespace BootloaderGUI string status; if (can.ConnectFirstDevice(bitrate.Value, out status)) + { lblStatus.Text = status; + + // запуск фонового приёма + can.ErrorReceived -= Can_ErrorReceived; // безопасно удалить старую подписку + can.ErrorReceived += Can_ErrorReceived; + can.StartBackgroundReceive(); + } else + { lblStatus.Text = "Connect failed"; + } }; @@ -144,11 +153,20 @@ namespace BootloaderGUI } + private void Can_ErrorReceived(UInt16 err) + { + this.BeginInvoke(new Action(() => + { + lblStatus.Text = $"Error received: 0x{err:X4}"; + MessageBox.Show($"Error received from device: 0x{err:X4}", "CAN Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); + })); + } private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { try { + can?.StopBackgroundReceive(); can?.Disconnect(); can?.Free(); } @@ -222,7 +240,7 @@ namespace BootloaderGUI { uint timeout = 1000u; UInt16 error = 0; - + Thread.Sleep(10); try { if (fwData == null) return; @@ -303,6 +321,7 @@ namespace BootloaderGUI { UpdateStatusOnUI("Error during RECEIVE: " + ex.Message); } + } private bool SendCmdSync(byte cmd) @@ -315,12 +334,16 @@ namespace BootloaderGUI if (!can.SendCmd(cmd, out UInt16 error)) { - if (error == 0xFFFF) + if ((error == 0xFFFF) && cmd != (BootloaderCommands.RESET) && (cmd != BootloaderCommands.JUMP)) + { MessageBox.Show($"Command 0x{cmd:X2} timed out", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); - else + return false; + } + else if ((error != 0xFFFF) && (error != 0)) + { MessageBox.Show($"Command 0x{cmd:X2} failed, error code: 0x{error:X4}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); - - return false; + return false; + } } UpdateStatusOnUI($"Command 0x{cmd:X2} sent successfully"); diff --git a/botterm/botterm/UserFriendlyBoot.cs b/botterm/botterm/UserFriendlyBoot.cs index a754e0d..5cf2f74 100644 --- a/botterm/botterm/UserFriendlyBoot.cs +++ b/botterm/botterm/UserFriendlyBoot.cs @@ -58,7 +58,14 @@ namespace BootloaderGUI // Кнопка "Go To Boot" btnGoBoot = new Button() { Top = top, Left = left + wBtn + gap, Width = wBtn, Height = hBtn, Text = "Go To Boot" }; - btnGoBoot.Click += (s, e) => sendCmdSync(BootloaderCommands.GO_TO_BOOT); + btnGoBoot.Click += (s, e) => + { + if(sendCmdSync(BootloaderCommands.GO_TO_BOOT)) + UpdateStatus("You're in Bootloader"); + else + UpdateStatus("Failed: Jump to Bootloader"); + + }; top += hBtn + gap; @@ -66,13 +73,21 @@ namespace BootloaderGUI Button btnGoApp = new Button() { Top = top, Left = left, Width = wBtn, Height = hBtn, Text = "Go To App" }; btnGoApp.Click += (s, e) => { - UpdateStatus("Jumping to app..."); - sendCmdSync(BootloaderCommands.JUMP); + if(sendCmdSync(BootloaderCommands.JUMP)) + UpdateStatus("Jumping to app..."); + else + UpdateStatus("Failed: Jump to App"); }; // Кнопка "Reset" btnReset = new Button() { Top = top, Left = left + wBtn + gap, Width = wBtn, Height = hBtn, Text = "Reset" }; - btnReset.Click += (s, e) => sendCmdSync(BootloaderCommands.RESET); + btnReset.Click += (s, e) => + { + if (sendCmdSync(BootloaderCommands.RESET)) + UpdateStatus("Resetting..."); + else + UpdateStatus("Failed: Reset MCU"); + }; Tab.Controls.AddRange(new Control[] { btnFirmware, btnGoBoot, btnGoApp, btnReset }); } @@ -98,16 +113,17 @@ namespace BootloaderGUI for (int page = 0; page < totalPages; page++) { UpdateStatus($"Sending page {page + 1}/{totalPages}"); + await Task.Delay(5); // небольшая пауза для UI sendPage(page); UpdateStatus($"Writing page {page + 1}/{totalPages}"); + await Task.Delay(5); // небольшая пауза для UI if (!sendCmdSync(BootloaderCommands.WRITE)) { UpdateStatus($"Write failed on page {page}"); return; } - await Task.Delay(5); // небольшая пауза для UI } UpdateStatus("Jumping to app..."); diff --git a/botterm/botterm/bin/Debug/botterm.exe b/botterm/botterm/bin/Debug/botterm.exe index 624d383..0de060a 100644 Binary files a/botterm/botterm/bin/Debug/botterm.exe and b/botterm/botterm/bin/Debug/botterm.exe differ diff --git a/botterm/botterm/bin/Debug/botterm.pdb b/botterm/botterm/bin/Debug/botterm.pdb index 0a493ce..f6f96b7 100644 Binary files a/botterm/botterm/bin/Debug/botterm.pdb and b/botterm/botterm/bin/Debug/botterm.pdb differ diff --git a/botterm/botterm/obj/Debug/botterm.csproj.AssemblyReference.cache b/botterm/botterm/obj/Debug/botterm.csproj.AssemblyReference.cache index f5e894a..1228a24 100644 Binary files a/botterm/botterm/obj/Debug/botterm.csproj.AssemblyReference.cache and b/botterm/botterm/obj/Debug/botterm.csproj.AssemblyReference.cache differ diff --git a/botterm/botterm/obj/Debug/botterm.exe b/botterm/botterm/obj/Debug/botterm.exe index 624d383..0de060a 100644 Binary files a/botterm/botterm/obj/Debug/botterm.exe and b/botterm/botterm/obj/Debug/botterm.exe differ diff --git a/botterm/botterm/obj/Debug/botterm.pdb b/botterm/botterm/obj/Debug/botterm.pdb index 0a493ce..f6f96b7 100644 Binary files a/botterm/botterm/obj/Debug/botterm.pdb and b/botterm/botterm/obj/Debug/botterm.pdb differ