Added WiFi battery indicator

Added persistance of last IP used
Added link to the Wiki
Corrected SPI analyzer
Added channel names on analysis settings
This commit is contained in:
Agustín Gimenez 2023-10-25 00:51:32 +02:00
parent accc3214c9
commit 6ab103e120
19 changed files with 403 additions and 99 deletions

View File

@ -2,7 +2,7 @@
"profiles": { "profiles": {
"CLCapture": { "CLCapture": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "capture COM9 1000000 1:SDA,2:SDB,3:SDC_A,4:nana,5,6,7,8 20 20000 TriggerType:Edge,Channel:1,Value:0 test.csv" "commandLineArgs": "capture COM9 1000000 1:SDA,2:SDB,3:SDC_A,4:nana,5,6,7,8 512 1000 5 TriggerType:Edge,Channel:1,Value:1 test.csv"
} }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

View File

@ -0,0 +1,50 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Environment;
namespace LogicAnalyzer.Classes
{
public static class AppSettingsManager
{
static JsonSerializerSettings jSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, Formatting = Formatting.Indented };
public static T? GetSettings<T>(string FileName) where T : class
{
try
{
string path = GetFilePath(FileName);
if(!File.Exists(path))
return null;
string content = File.ReadAllText(path);
var settings = JsonConvert.DeserializeObject<T>(content, jSettings);
return settings;
}
catch { return null; }
}
public static bool PersistSettings(string FileName, object Settings)
{
try
{
string path = GetFilePath(FileName);
var data = JsonConvert.SerializeObject(Settings, jSettings);
File.WriteAllText(path, data);
return true;
}
catch { return false; }
}
private static string GetFilePath(string FileName)
{
string appData = Path.Combine(Environment.GetFolderPath(SpecialFolder.ApplicationData, SpecialFolderOption.DoNotVerify), "LogicAnalyzer");
Directory.CreateDirectory(appData);
return Path.Combine(appData, FileName);
}
}
}

View File

@ -0,0 +1,21 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="450"
MaxWidth="640" MaxHeight="450"
MinWidth="640" MinHeight="450"
Icon="/Assets/Ico40.ico"
x:Class="LogicAnalyzer.Dialogs.AboutDialog"
Title="About LogicAnalyzer" ShowInTaskbar="False" CanResize="False"
WindowStartupLocation="CenterScreen"
Topmost="True">
<Grid ColumnDefinitions="Auto,180">
<Image Source="/Assets/Logo40.png" Margin="20" Height="420" Width="420"></Image>
<StackPanel Spacing="10" Grid.Column="1" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="20">
<TextBlock TextWrapping="Wrap">©2023 Agustín Giménez Bernad</TextBlock>
<TextBlock TextWrapping="Wrap" Name="txtVersion">Version 5.0.0.0</TextBlock>
<Button Name="btnLicense" Margin="10,0,10,0">License</Button>
</StackPanel>
</Grid>
</Window>

View File

@ -0,0 +1,66 @@
using Avalonia.Controls;
using LogicAnalyzer.Extensions;
using Microsoft.Extensions.PlatformAbstractions;
using System.Diagnostics;
using System.IO.Packaging;
using System.Runtime.InteropServices;
namespace LogicAnalyzer.Dialogs
{
public partial class AboutDialog : Window
{
public AboutDialog()
{
InitializeComponent();
txtVersion.Text = $"Version {GetAppVersion()}";
btnLicense.Click += BtnLicense_Click;
}
private async void BtnLicense_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
try
{
OpenUrl("https://github.com/gusmanb/logicanalyzer/blob/master/LICENSE");
}
catch
{
await this.ShowError("Cannot open page.", "Cannot start the default browser. You can access the online documentation in https://github.com/gusmanb/logicanalyzer/blob/master/LICENSE");
}
}
private void OpenUrl(string url)
{
try
{
Process.Start(url);
}
catch
{
// hack because of this: https://github.com/dotnet/corefx/issues/10361
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
url = url.Replace("&", "^&");
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Process.Start("xdg-open", url);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Process.Start("open", url);
}
else
{
throw;
}
}
}
static string GetAppVersion()
{
ApplicationEnvironment app = PlatformServices.Default.Application;
return app.ApplicationVersion;
}
}
}

View File

@ -142,58 +142,11 @@ namespace LogicAnalyzer.Dialogs
private void LoadSettings(AnalyzerDriverType DriverType) private void LoadSettings(AnalyzerDriverType DriverType)
{ {
settingsFile = WindowExtensions.GetFilePath($"cpSettings{DriverType}.json"); settingsFile = $"cpSettings{DriverType}.json";
CaptureSettings? settings = AppSettingsManager.GetSettings<CaptureSettings>(settingsFile);
if (File.Exists(settingsFile)) if (settings != null)
{ {
string data = File.ReadAllText(settingsFile);
CaptureSettings? settings = null;
try
{
settings = JsonConvert.DeserializeObject<CaptureSettings>(data);
}
catch { }
if (settings == null)
{
try
{
var oldset = JsonConvert.DeserializeObject<OldCaptureSettings>(data);
if (oldset != null)
{
CaptureChannel[] channels = new CaptureChannel[oldset.CaptureChannels.Length];
for (int buc = 0; buc < channels.Length; buc++)
channels[buc] = new CaptureChannel
{
ChannelName = (oldset.ChannelTexts?.Length ?? 0) > buc ? oldset.ChannelTexts[buc] : "",
ChannelNumber = (int)oldset.CaptureChannels[buc]
};
settings = new CaptureSettings
{
CaptureChannels = channels,
Frequency = oldset.Frequency,
PostTriggerSamples = oldset.PostTriggerSamples,
PreTriggerSamples = oldset.PreTriggerSamples,
LoopCount = 0,
TriggerBitCount = oldset.TriggerBitCount,
TriggerChannel = oldset.TriggerChannel,
TriggerInverted = oldset.TriggerInverted,
TriggerPattern = oldset.TriggerPattern,
TriggerType = oldset.TriggerType
};
}
}
catch { }
if (settings == null)
return;
}
nudFrequency.Value = settings.Frequency; nudFrequency.Value = settings.Frequency;
nudPreSamples.Value = settings.PreTriggerSamples; nudPreSamples.Value = settings.PreTriggerSamples;
nudPostSamples.Value = settings.PostTriggerSamples; nudPostSamples.Value = settings.PostTriggerSamples;
@ -218,7 +171,7 @@ namespace LogicAnalyzer.Dialogs
triggerChannels[settings.TriggerChannel].IsChecked = true; triggerChannels[settings.TriggerChannel].IsChecked = true;
ckNegativeTrigger.IsChecked = settings.TriggerInverted; ckNegativeTrigger.IsChecked = settings.TriggerInverted;
ckBurst.IsChecked = settings.LoopCount > 0; ckBurst.IsChecked = settings.LoopCount > 0;
nudBurstCount.Value = settings.LoopCount > 0 ? settings.LoopCount : 1; nudBurstCount.Value = settings.LoopCount > 0 ? settings.LoopCount + 1 : 2;
rbTriggerTypePattern.IsChecked = false; rbTriggerTypePattern.IsChecked = false;
rbTriggerTypeEdge.IsChecked = true; rbTriggerTypeEdge.IsChecked = true;

View File

@ -1,4 +1,5 @@
using Avalonia.Controls; using Avalonia.Controls;
using LogicAnalyzer.Classes;
using LogicAnalyzer.Extensions; using LogicAnalyzer.Extensions;
using MessageBox.Avalonia; using MessageBox.Avalonia;
using System; using System;
@ -18,6 +19,14 @@ namespace LogicAnalyzer.Dialogs
InitializeComponent(); InitializeComponent();
btnAccept.Click += BtnAccept_Click; btnAccept.Click += BtnAccept_Click;
btnCancel.Click += BtnCancel_Click; btnCancel.Click += BtnCancel_Click;
var settings = AppSettingsManager.GetSettings<NetworkConnectionSettings>("NetConnection.json");
if (settings != null)
{
txtAddress.Text = settings.Address;
nudPort.Value = settings.Port;
}
} }
protected override void OnOpened(EventArgs e) protected override void OnOpened(EventArgs e)
{ {
@ -36,10 +45,24 @@ namespace LogicAnalyzer.Dialogs
await this.ShowError("Invalid address", "The specified address is not in the correct format."); await this.ShowError("Invalid address", "The specified address is not in the correct format.");
return; return;
} }
NetworkConnectionSettings settings = new NetworkConnectionSettings
{
Address = txtAddress.Text,
Port = (ushort)nudPort.Value
};
AppSettingsManager.PersistSettings("NetConnection.json", settings);
this.Address = txtAddress.Text; this.Address = txtAddress.Text;
this.Port = (ushort)nudPort.Value; this.Port = (ushort)nudPort.Value;
this.Close(true); this.Close(true);
} }
} }
public class NetworkConnectionSettings
{
public string? Address { get; set; }
public ushort Port { get; set; }
}
} }

View File

@ -19,8 +19,8 @@ namespace LogicAnalyzer.Dialogs
ProtocolAnalyzerBase analyzer; ProtocolAnalyzerBase analyzer;
public ProtocolAnalyzerBase Analyzer { get { return analyzer; } set { analyzer = value; LoadControls(); } } public ProtocolAnalyzerBase Analyzer { get { return analyzer; } set { analyzer = value; LoadControls(); } }
int[] channels; Channel[] channels;
public int[] Channels { get { return channels; } set { channels = value; LoadControls(); } } public Channel[] Channels { get { return channels; } set { channels = value; LoadControls(); } }
public ProtocolAnalyzerSettingsDialog() public ProtocolAnalyzerSettingsDialog()
@ -54,7 +54,7 @@ namespace LogicAnalyzer.Dialogs
channelsSource.Add("< None >"); channelsSource.Add("< None >");
channelsSource.AddRange(channels.Select(c => $"Channel {c + 1}")); channelsSource.AddRange(channels.Select(c => c.ChannelName));
for (int buc = 0; buc < signals.Length; buc++) for (int buc = 0; buc < signals.Length; buc++)
{ {
@ -219,7 +219,6 @@ namespace LogicAnalyzer.Dialogs
} }
return settingsValues.ToArray(); return settingsValues.ToArray();
} }
ProtocolAnalyzerSelectedChannel[]? ComposeChannels() ProtocolAnalyzerSelectedChannel[]? ComposeChannels()
@ -238,6 +237,9 @@ namespace LogicAnalyzer.Dialogs
if (list == null) if (list == null)
return null; return null;
if (list.SelectedIndex == -1)
continue;
selectedChannels.Add(new ProtocolAnalyzerSelectedChannel selectedChannels.Add(new ProtocolAnalyzerSelectedChannel
{ {
ChannelIndex = list.SelectedIndex - 1, ChannelIndex = list.SelectedIndex - 1,
@ -259,5 +261,11 @@ namespace LogicAnalyzer.Dialogs
SelectedChannels = ComposeChannels(); SelectedChannels = ComposeChannels();
this.Close(true); this.Close(true);
} }
public class Channel
{
public required int ChannelIndex { get; set; }
public required string ChannelName { get; set; }
}
} }
} }

View File

@ -12,34 +12,17 @@ using System.IO;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Text.Json; using System.Text.Json;
using static System.Environment; using static System.Environment;
using LogicAnalyzer.Classes;
namespace LogicAnalyzer.Extensions namespace LogicAnalyzer.Extensions
{ {
public static class WindowExtensions public static class WindowExtensions
{ {
static string BasePath { get { return Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) ?? ""; } }
static JsonSerializerSettings jSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Formatting = Formatting.Indented };
public static string GetFilePath(string FileName)
{
string appData = Path.Combine(Environment.GetFolderPath(SpecialFolder.ApplicationData, SpecialFolderOption.DoNotVerify), "LogicAnalyzer");
Directory.CreateDirectory(appData);
return Path.Combine(appData, FileName);
}
static AppConfig config; static AppConfig config;
static WindowExtensions() static WindowExtensions()
{ {
var cfg = AppSettingsManager.GetSettings<AppConfig>("AppConfig.json");
string path = GetFilePath("AppConfig.json"); config = cfg ?? new AppConfig();
if (File.Exists(path))
config = JsonConvert.DeserializeObject<AppConfig>(File.ReadAllText(path), jSettings);
if(config == null)
config = new AppConfig();
} }
public static void FixStartupPosition(this Window windowToFix) public static void FixStartupPosition(this Window windowToFix)
{ {
@ -122,7 +105,7 @@ namespace LogicAnalyzer.Extensions
config.WindowSettings[Window.GetType().FullName] = settings; config.WindowSettings[Window.GetType().FullName] = settings;
PersistSettings(); AppSettingsManager.PersistSettings("AppConfig.json", config);
} }
public static bool RestoreSettings(this Window Window, IEnumerable<string> Properties) public static bool RestoreSettings(this Window Window, IEnumerable<string> Properties)
{ {
@ -144,12 +127,6 @@ namespace LogicAnalyzer.Extensions
return true; return true;
} }
private static void PersistSettings()
{
string path = GetFilePath("AppConfig.json");
File.WriteAllText(path, JsonConvert.SerializeObject(config, Formatting.Indented, jSettings));
}
private static object GetPropertyValue(object Source, string PropertyName) private static object GetPropertyValue(object Source, string PropertyName)
{ {
object obj = Source; object obj = Source;

View File

@ -31,6 +31,7 @@
<PackageReference Include="AvaloniaColorPicker" Version="1.3.3" /> <PackageReference Include="AvaloniaColorPicker" Version="1.3.3" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="0.10.12.2" /> <PackageReference Include="AvaloniaEdit.TextMate" Version="0.10.12.2" />
<PackageReference Include="MessageBox.Avalonia" Version="2.0.2" /> <PackageReference Include="MessageBox.Avalonia" Version="2.0.2" />
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3-beta1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3-beta1" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" /> <PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
</ItemGroup> </ItemGroup>

View File

@ -1,10 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<_LastSelectedProfileId>C:\Users\geniw\source\repos\LogicAnalyzer\LogicAnalyzer\Properties\PublishProfiles\Linux.pubxml</_LastSelectedProfileId> <_LastSelectedProfileId>C:\Users\geniw\source\repos\LogicAnalyzer\LogicAnalyzer\Properties\PublishProfiles\Windows.pubxml</_LastSelectedProfileId>
<ActiveDebugProfile>LogicAnalyzer</ActiveDebugProfile> <ActiveDebugProfile>LogicAnalyzer</ActiveDebugProfile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor> <DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
</Project> </Project>

View File

@ -24,6 +24,11 @@
<MenuItem Header="Network settings" IsEnabled="False" Name="mnuSettings"> <MenuItem Header="Network settings" IsEnabled="False" Name="mnuSettings">
<MenuItem Header="Update network settings" Name="mnuNetSettings"></MenuItem> <MenuItem Header="Update network settings" Name="mnuNetSettings"></MenuItem>
</MenuItem> </MenuItem>
<MenuItem Header="Help">
<MenuItem Header="Online documentation" Name="mnuDocs" />
<Separator/>
<MenuItem Header="About LogicAnalyzer" Name="mnuAbout" />
</MenuItem>
</Menu> </Menu>
<Grid DockPanel.Dock="Top" Height="48" ColumnDefinitions="*,*" Background="#80303030"> <Grid DockPanel.Dock="Top" Height="48" ColumnDefinitions="*,*" Background="#80303030">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Stretch" Grid.Column="0" Margin="10,0,0,0"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Stretch" Grid.Column="0" Margin="10,0,0,0">
@ -57,7 +62,7 @@
<controls:SampleViewer HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="sampleViewer" Grid.Column="1"></controls:SampleViewer> <controls:SampleViewer HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="sampleViewer" Grid.Column="1"></controls:SampleViewer>
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
<Panel Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="#ff303030"> <Panel Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="#ff202020">
<Grid DockPanel.Dock="Top" RowDefinitions="*,*,2*,*,2*,*" ColumnDefinitions="*,4*,*" HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="5" Background="#80383838"> <Grid DockPanel.Dock="Top" RowDefinitions="*,*,2*,*,2*,*" ColumnDefinitions="*,4*,*" HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="5" Background="#80383838">
<TextBlock Grid.ColumnSpan="2" Margin="10"> <TextBlock Grid.ColumnSpan="2" Margin="10">
Adjustments Adjustments
@ -79,9 +84,7 @@
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
</Grid> </Grid>
<Panel VerticalAlignment="Stretch" Margin="0,180,0,180" Background="Black">
<Image Source="/Assets/Logo40.png" VerticalAlignment="Center"></Image> <Image Source="/Assets/Logo40.png" VerticalAlignment="Center"></Image>
</Panel>
<StackPanel DockPanel.Dock="Bottom" VerticalAlignment="Bottom" Margin="5" Background="#80383838"> <StackPanel DockPanel.Dock="Bottom" VerticalAlignment="Bottom" Margin="5" Background="#80383838">
<TextBlock Margin="5,2,5,2"> <TextBlock Margin="5,2,5,2">
Information Information
@ -128,6 +131,15 @@
</TextBlock> </TextBlock>
<TextBlock Margin="5,2,5,2" HorizontalAlignment="Right" Name="lblValue"></TextBlock> <TextBlock Margin="5,2,5,2" HorizontalAlignment="Right" Name="lblValue"></TextBlock>
</Panel> </Panel>
<Panel Name="pnlPower" IsVisible="False">
<TextBlock Margin="5,2,5,2" HorizontalAlignment="Left">
- Power status:
</TextBlock>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Image Margin="5,2,5,2" Name="imgPowerSource" Width="16" Height="16" HorizontalAlignment="Right" Source="/Assets/plug.png"></Image>
<TextBlock Margin="5,2,5,2" HorizontalAlignment="Right" Name="lblVoltage">3.38v</TextBlock>
</StackPanel>
</Panel>
</StackPanel> </StackPanel>
</Panel> </Panel>
</Grid> </Grid>

View File

@ -1,7 +1,11 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
using Avalonia.Threading; using Avalonia.Threading;
using AvaloniaEdit.Utils; using AvaloniaEdit.Utils;
using LogicAnalyzer.Classes; using LogicAnalyzer.Classes;
@ -16,11 +20,14 @@ using SharedDriver;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.IO; using System.IO;
using System.IO.Ports; using System.IO.Ports;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames; using static System.Net.Mime.MediaTypeNames;
@ -28,7 +35,7 @@ namespace LogicAnalyzer
{ {
public partial class MainWindow : PersistableWindowBase public partial class MainWindow : PersistableWindowBase
{ {
IAnalizerDriver driver; IAnalizerDriver? driver;
CaptureSettings settings; CaptureSettings settings;
ProtocolAnalyzerLoader pLoader; ProtocolAnalyzerLoader pLoader;
@ -41,7 +48,7 @@ namespace LogicAnalyzer
AnalysisSettings? analysisSettings; AnalysisSettings? analysisSettings;
bool preserveSamples = false; bool preserveSamples = false;
Timer tmrPower;
public MainWindow() public MainWindow()
{ {
Instance = this; Instance = this;
@ -73,11 +80,67 @@ namespace LogicAnalyzer
mnuExit.Click += MnuExit_Click; mnuExit.Click += MnuExit_Click;
mnuExport.Click += MnuExport_Click; mnuExport.Click += MnuExport_Click;
mnuNetSettings.Click += MnuNetSettings_Click; mnuNetSettings.Click += MnuNetSettings_Click;
mnuDocs.Click += MnuDocs_Click;
mnuAbout.Click += MnuAbout_Click;
AddHandler(InputElement.KeyDownEvent, MainWindow_KeyDown, handledEventsToo: true); AddHandler(InputElement.KeyDownEvent, MainWindow_KeyDown, handledEventsToo: true);
LoadAnalyzers(); LoadAnalyzers();
RefreshPorts(); RefreshPorts();
tmrPower = new Timer((o) =>
{
Dispatcher.UIThread.InvokeAsync(() =>
{
GetPowerStatus();
});
});
}
private async void MnuAbout_Click(object? sender, RoutedEventArgs e)
{
var aboutDialog = new AboutDialog();
await aboutDialog.ShowDialog(this);
}
private async void MnuDocs_Click(object? sender, RoutedEventArgs e)
{
try
{
OpenUrl("https://github.com/gusmanb/logicanalyzer/wiki");
}
catch
{
await this.ShowError("Cannot open page.", "Cannot start the default browser. You can access the online documentation in https://github.com/gusmanb/logicanalyzer/wiki");
}
}
private void OpenUrl(string url)
{
try
{
Process.Start(url);
}
catch
{
// hack because of this: https://github.com/dotnet/corefx/issues/10361
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
url = url.Replace("&", "^&");
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Process.Start("xdg-open", url);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Process.Start("open", url);
}
else
{
throw;
}
}
} }
private void MainWindow_KeyDown(object? sender, Avalonia.Input.KeyEventArgs e) private void MainWindow_KeyDown(object? sender, Avalonia.Input.KeyEventArgs e)
@ -713,7 +776,7 @@ namespace LogicAnalyzer
mnuExport.IsEnabled = true; mnuExport.IsEnabled = true;
mnuSettings.IsEnabled = driver.DriverType == AnalyzerDriverType.Serial && (driver.DeviceVersion?.Contains("WIFI") ?? false); mnuSettings.IsEnabled = driver.DriverType == AnalyzerDriverType.Serial && (driver.DeviceVersion?.Contains("WIFI") ?? false);
LoadInfo(); LoadInfo();
GetPowerStatus();
}); });
} }
@ -725,7 +788,19 @@ namespace LogicAnalyzer
void LoadAnalyzers() void LoadAnalyzers()
{ {
pLoader = new ProtocolAnalyzerLoader(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "analyzers"));
string path = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "analyzers");
if(!Directory.Exists(path))
path = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "Analyzers");
if (!Directory.Exists(path))
{
mnuProtocols.Items = new MenuItem[] { new MenuItem { Header = "<- None ->" } };
return;
}
pLoader = new ProtocolAnalyzerLoader(path);
var protocols = pLoader.ProtocolNames; var protocols = pLoader.ProtocolNames;
mnuProtocols.Items = null; mnuProtocols.Items = null;
@ -799,7 +874,19 @@ namespace LogicAnalyzer
var dlg = new ProtocolAnalyzerSettingsDialog(); var dlg = new ProtocolAnalyzerSettingsDialog();
{ {
dlg.Analyzer = analyzer; dlg.Analyzer = analyzer;
dlg.Channels = channelViewer.Channels.Select(c => c.ChannelNumber).ToArray(); dlg.Channels = channelViewer.Channels.Select(c =>
{
var ch = new ProtocolAnalyzerSettingsDialog.Channel
{
ChannelIndex = c.ChannelNumber,
ChannelName = string.IsNullOrWhiteSpace(c.ChannelName) ?
$"Channel {c.ChannelNumber + 1}" :
c.ChannelName
};
return ch;
}).ToArray();
if (await dlg.ShowDialog<bool>(this) != true) if (await dlg.ShowDialog<bool>(this) != true)
return; return;
@ -892,6 +979,7 @@ namespace LogicAnalyzer
btnCapture.IsEnabled = true; btnCapture.IsEnabled = true;
btnRepeat.IsEnabled = true; btnRepeat.IsEnabled = true;
mnuSettings.IsEnabled = driver.DriverType == AnalyzerDriverType.Serial && (driver.DeviceVersion?.Contains("WIFI") ?? false); mnuSettings.IsEnabled = driver.DriverType == AnalyzerDriverType.Serial && (driver.DeviceVersion?.Contains("WIFI") ?? false);
tmrPower.Change(30000, Timeout.Infinite);
} }
else else
{ {
@ -905,9 +993,48 @@ namespace LogicAnalyzer
btnCapture.IsEnabled = false; btnCapture.IsEnabled = false;
btnRepeat.IsEnabled = false; btnRepeat.IsEnabled = false;
mnuSettings.IsEnabled = false; mnuSettings.IsEnabled = false;
} tmrPower.Change(Timeout.Infinite, Timeout.Infinite);
} }
GetPowerStatus();
}
void GetPowerStatus()
{
if (driver == null || !driver.IsNetwork)
{
pnlPower.IsVisible = false;
return;
}
if(driver.IsCapturing)
return;
var powerStatus = driver.GetVoltageStatus();
if (string.IsNullOrWhiteSpace(powerStatus) || powerStatus == "UNSUPPORTED")
{
pnlPower.IsVisible = false;
return;
}
string[] parts = powerStatus.Split("_");
if(parts.Length == 2 )
{
lblVoltage.Text = parts[0];
var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
using var str = assets.Open(new Uri(parts[1] == "1" ? "avares://LogicAnalyzer/Assets/plug.png" : "avares://LogicAnalyzer/Assets/battery.png"));
Bitmap bmp = new Bitmap(str);
var oldSrc = imgPowerSource.Source;
imgPowerSource.Source = bmp;
pnlPower.IsVisible = true;
if (oldSrc is IDisposable)
((IDisposable)oldSrc).Dispose();
}
}
private void btnRefresh_Click(object? sender, RoutedEventArgs e) private void btnRefresh_Click(object? sender, RoutedEventArgs e)
{ {
RefreshPorts(); RefreshPorts();
@ -934,14 +1061,27 @@ namespace LogicAnalyzer
{ {
var dialog = new CaptureDialog(); var dialog = new CaptureDialog();
dialog.Initialize(driver); dialog.Initialize(driver);
if (!await dialog.ShowDialog<bool>(this)) if (!await dialog.ShowDialog<bool>(this))
return; return;
settings = dialog.SelectedSettings; settings = dialog.SelectedSettings;
preserveSamples = false; preserveSamples = false;
tmrPower.Change(Timeout.Infinite, Timeout.Infinite);
try
{
BeginCapture(); BeginCapture();
var settingsFile = $"cpSettings{driver.DriverType}.json";
AppSettingsManager.PersistSettings(settingsFile, settings);
}
finally
{
tmrPower.Change(30000, Timeout.Infinite);
}
} }
private void btnAbort_Click(object? sender, RoutedEventArgs e) private void btnAbort_Click(object? sender, RoutedEventArgs e)

View File

@ -326,9 +326,9 @@ namespace SPIProtocolAnalyzer
if (csChannel.Samples[buc] == 0) if (csChannel.Samples[buc] == 0)
{ {
if (underConstruction == null) if (underConstruction == null)
underConstruction = new ActiveRange { FirstSample = buc }; underConstruction = new ActiveRange { FirstSample = buc, LastSample = buc };
else else
continue; underConstruction.LastSample = buc;
} }
else else
{ {
@ -342,6 +342,12 @@ namespace SPIProtocolAnalyzer
} }
if (underConstruction != null)
{
ranges.Add(underConstruction);
underConstruction = null;
}
return ranges; return ranges;
} }

View File

@ -10,6 +10,9 @@ namespace SharedDriver
{ {
int deviceCount; int deviceCount;
public bool IsConnected => false;
public bool IsCapturing => false;
public bool IsNetwork => false;
public EmulatedAnalizerDriver(int DeviceCount) public EmulatedAnalizerDriver(int DeviceCount)
{ {
deviceCount = DeviceCount; deviceCount = DeviceCount;
@ -72,6 +75,11 @@ namespace SharedDriver
throw new NotSupportedException(); throw new NotSupportedException();
} }
public string? GetVoltageStatus()
{
return "UNSUPPORTED";
}
public bool StopCapture() public bool StopCapture()
{ {
return true; return true;

View File

@ -9,6 +9,8 @@ namespace SharedDriver
public interface IAnalizerDriver : IDisposable public interface IAnalizerDriver : IDisposable
{ {
public string? DeviceVersion { get; } public string? DeviceVersion { get; }
public bool IsCapturing { get; }
public bool IsNetwork { get; }
public AnalyzerDriverType DriverType { get; } public AnalyzerDriverType DriverType { get; }
public int Channels { get; } public int Channels { get; }
public event EventHandler<CaptureEventArgs> CaptureCompleted; public event EventHandler<CaptureEventArgs> CaptureCompleted;
@ -17,6 +19,8 @@ namespace SharedDriver
public CaptureError StartPatternCapture(int Frequency, int PreSamples, int PostSamples, int[] Channels, int TriggerChannel, int TriggerBitCount, UInt16 TriggerPattern, bool Fast, Action<CaptureEventArgs>? CaptureCompletedHandler = null); public CaptureError StartPatternCapture(int Frequency, int PreSamples, int PostSamples, int[] Channels, int TriggerChannel, int TriggerBitCount, UInt16 TriggerPattern, bool Fast, Action<CaptureEventArgs>? CaptureCompletedHandler = null);
public bool StopCapture(); public bool StopCapture();
public CaptureLimits GetLimits(int[] Channels); public CaptureLimits GetLimits(int[] Channels);
public string? GetVoltageStatus();
} }
public class CaptureEventArgs : EventArgs public class CaptureEventArgs : EventArgs

View File

@ -1,4 +1,5 @@
using System.IO.Ports; using System.IO.Ports;
using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -20,6 +21,9 @@ namespace SharedDriver
string devAddr; string devAddr;
ushort devPort; ushort devPort;
public bool IsCapturing { get { return capturing; } }
public bool IsNetwork { get { return isNetwork; } }
public object Tag { get; set; } public object Tag { get; set; }
public string? DeviceVersion { get; private set; } public string? DeviceVersion { get; private set; }
public int Channels { get { return 24; } } public int Channels { get { return 24; } }
@ -450,6 +454,24 @@ namespace SharedDriver
return CaptureModes.Modes[mode]; return CaptureModes.Modes[mode];
} }
public string? GetVoltageStatus()
{
if(!isNetwork)
return "UNSUPPORTED";
OutputPacket pack = new OutputPacket();
pack.AddByte(3);
baseStream.Write(pack.Serialize());
baseStream.Flush();
baseStream.ReadTimeout = Timeout.Infinite;
var result = readResponse.ReadLine();
baseStream.ReadTimeout = Timeout.Infinite;
return result;
}
public void Dispose() public void Dispose()
{ {
try try

View File

@ -29,6 +29,10 @@ namespace SharedDriver
private int preSamples; private int preSamples;
private Action<CaptureEventArgs>? currentCaptureHandler; private Action<CaptureEventArgs>? currentCaptureHandler;
public bool IsCapturing { get { return capturing; } }
public bool IsNetwork { get { return false; } }
public string DeviceVersion { get; private set; } public string DeviceVersion { get; private set; }
public AnalyzerDriverType DriverType public AnalyzerDriverType DriverType
{ {
@ -237,6 +241,12 @@ namespace SharedDriver
var mode = GetCaptureMode(Channels); var mode = GetCaptureMode(Channels);
return CaptureModes.Modes[mode]; return CaptureModes.Modes[mode];
} }
public string? GetVoltageStatus()
{
return "UNSUPPORTED";
}
private void Dev_CaptureCompleted(object? sender, CaptureEventArgs e) private void Dev_CaptureCompleted(object? sender, CaptureEventArgs e)
{ {
lock(locker) lock(locker)