From 27cf9fccebc10457517bcb4bdcca46d7b5bd144f Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sat, 22 Mar 2025 20:22:25 -0400 Subject: [PATCH 1/4] remove this call drop logic, like every other piece of equipment without crypto keys just play garble, so the user will want to jam a screwdriver into their ear canal; --- dvmconsole/MainWindow.P25.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dvmconsole/MainWindow.P25.cs b/dvmconsole/MainWindow.P25.cs index d30ddd8..4fa3bd2 100644 --- a/dvmconsole/MainWindow.P25.cs +++ b/dvmconsole/MainWindow.P25.cs @@ -534,14 +534,6 @@ namespace dvmconsole return; } - if ((channel.algId != cpgChannel.GetAlgoId() || channel.kId != cpgChannel.GetKeyId()) && channel.algId != P25Defines.P25_ALGO_UNENCRYPT) - { - slot.RxStreamId = e.StreamId; - channel.Background = ChannelBox.RED_GRADIENT; - Log.WriteLine($"({system.Name}) P25D: Traffic *CALL DROPPED * PEER {e.PeerId} SRC_ID {e.SrcId} TGID {e.DstId} [STREAM ID {e.StreamId}]"); - continue; - } - byte[] newMI = new byte[P25Defines.P25_MI_LENGTH]; int count = 0; From 815d2cdc7f608f74522383a2127d1b66126bfd62 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sat, 22 Mar 2025 22:31:55 -0400 Subject: [PATCH 2/4] add command line argument support (specifically for --userprofile= so the directory where UserProfile.yaml can be overridden by the user); expand the Audio device list with the window; --- dvmconsole/App.xaml | 1 + dvmconsole/App.xaml.cs | 60 ++++++++++++++++++++++- dvmconsole/AudioSettingsWindow.xaml | 2 +- dvmconsole/Properties/launchSettings.json | 8 +++ dvmconsole/SettingsManager.cs | 17 +++++-- 5 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 dvmconsole/Properties/launchSettings.json diff --git a/dvmconsole/App.xaml b/dvmconsole/App.xaml index c1064e9..5671c61 100644 --- a/dvmconsole/App.xaml +++ b/dvmconsole/App.xaml @@ -1,6 +1,7 @@  diff --git a/dvmconsole/App.xaml.cs b/dvmconsole/App.xaml.cs index abb4dc9..a108df3 100644 --- a/dvmconsole/App.xaml.cs +++ b/dvmconsole/App.xaml.cs @@ -12,17 +12,22 @@ * */ +using fnecore.Utility; +using NAudio.Wave; using System.IO; using System.Reflection; +using System.Text; using System.Windows; namespace dvmconsole { /// - /// + /// Encapsulates a Windows Presentation Foundation application. /// public partial class App : Application { + public static string USER_PROFILE_PATH_OVERRIDE = string.Empty; + /* ** Methods */ @@ -44,5 +49,58 @@ namespace dvmconsole return; } } + + /// + /// Internal helper to prints the program usage. + /// + private static void Usage(OptionSet p) + { + string messageBoxText = "[-h | --help][--userprofile ]\r\nOptions:\r\n"; + + using (MemoryStream ms = new MemoryStream()) + { + using (TextWriter writer = new StreamWriter(ms)) + p.WriteOptionDescriptions(writer); + + messageBoxText += Encoding.UTF8.GetString(ms.ToArray()); + } + + MessageBox.Show(messageBoxText, "Digital Voice Modem - Desktop Dispatch Console", + MessageBoxButton.OK, MessageBoxImage.Information); + + Application.Current.Shutdown(); + } + + /// + /// + /// + /// + /// + private void Application_Startup(object sender, StartupEventArgs e) + { + bool showHelp = false; + string configFile = string.Empty; + + // command line parameters + OptionSet options = new OptionSet() + { + { "h|help", "show this message and exit", v => showHelp = v != null }, + { "userprofile=", "sets the path to the UserProfile.yaml", v => USER_PROFILE_PATH_OVERRIDE = v }, + }; + + // attempt to parse the commandline + try + { + options.Parse(e.Args); + } + catch (OptionException) + { + /* ignore */ + } + + // show help? + if (showHelp) + Usage(options); + } } // public partial class App : Application } // namespace dvmconsole diff --git a/dvmconsole/AudioSettingsWindow.xaml b/dvmconsole/AudioSettingsWindow.xaml index 90f93be..2aeec3e 100644 --- a/dvmconsole/AudioSettingsWindow.xaml +++ b/dvmconsole/AudioSettingsWindow.xaml @@ -15,7 +15,7 @@ - + diff --git a/dvmconsole/Properties/launchSettings.json b/dvmconsole/Properties/launchSettings.json new file mode 100644 index 0000000..8582f22 --- /dev/null +++ b/dvmconsole/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "dvmconsole": { + "commandName": "Project", + "commandLineArgs": "--userprofile=." + } + } +} \ No newline at end of file diff --git a/dvmconsole/SettingsManager.cs b/dvmconsole/SettingsManager.cs index 9910e4a..6726f13 100644 --- a/dvmconsole/SettingsManager.cs +++ b/dvmconsole/SettingsManager.cs @@ -31,9 +31,9 @@ namespace dvmconsole Environment.SpecialFolder.ApplicationData); public static readonly string RootAppDataPath = "DVMProject" + Path.DirectorySeparatorChar + "dvmconsole"; - public static readonly string UserAppDataPath = UserAppData + Path.DirectorySeparatorChar + RootAppDataPath; + public static string UserAppDataPath = UserAppData + Path.DirectorySeparatorChar + RootAppDataPath; - private static readonly string SettingsFilePath = UserAppDataPath + Path.DirectorySeparatorChar + "UserSettings.json"; + private static string SettingsFilePath = UserAppDataPath + Path.DirectorySeparatorChar + "UserSettings.json"; /* ** Properties @@ -139,8 +139,17 @@ namespace dvmconsole /// public bool LoadSettings() { - if (!Directory.Exists(UserAppDataPath)) - Directory.CreateDirectory(UserAppDataPath); + // was the user profile path being overridden? + if (App.USER_PROFILE_PATH_OVERRIDE != string.Empty) + { + UserAppDataPath = App.USER_PROFILE_PATH_OVERRIDE; + SettingsFilePath = UserAppDataPath + Path.DirectorySeparatorChar + "UserSettings.json"; + } + else + { + if (!Directory.Exists(UserAppDataPath)) + Directory.CreateDirectory(UserAppDataPath); + } if (!File.Exists(SettingsFilePath)) return false; From 4959dce4005ff2882b6625f5eb8df4edd4cbcf35 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sat, 22 Mar 2025 22:32:34 -0400 Subject: [PATCH 3/4] cleanup usings; --- dvmconsole/App.xaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dvmconsole/App.xaml.cs b/dvmconsole/App.xaml.cs index a108df3..ed1db8f 100644 --- a/dvmconsole/App.xaml.cs +++ b/dvmconsole/App.xaml.cs @@ -12,13 +12,13 @@ * */ -using fnecore.Utility; -using NAudio.Wave; using System.IO; using System.Reflection; using System.Text; using System.Windows; +using fnecore.Utility; + namespace dvmconsole { /// From 64682a5f0a0070b19ad7ff3444adf850f2e88c75 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sun, 23 Mar 2025 01:06:51 -0400 Subject: [PATCH 4/4] cause everyone in the universe to rage because we added a NuGet dependency (MaterialDesignThemes 5); refactor all XAML to use MaterialDesignThemes; --- dvmconsole/App.xaml | 85 +--- dvmconsole/AudioSettingsWindow.xaml | 17 +- dvmconsole/CallHistoryWindow.xaml | 3 + dvmconsole/Controls/AlertTone.xaml | 19 +- dvmconsole/Controls/ChannelBox.xaml | 29 +- dvmconsole/Controls/ChannelBox.xaml.cs | 3 + dvmconsole/Controls/SystemStatusBox.xaml | 4 +- dvmconsole/DVMConsole.csproj | 1 + dvmconsole/DigitalPageWindow.xaml | 31 +- dvmconsole/DigitalPageWindow.xaml.cs | 2 +- dvmconsole/KeyStatusWindow.xaml | 12 +- dvmconsole/MainWindow.xaml | 549 +++++------------------ dvmconsole/MainWindow.xaml.cs | 66 ++- dvmconsole/PeerSystem.cs | 2 + dvmconsole/QuickCallPage.xaml | 31 +- 15 files changed, 268 insertions(+), 586 deletions(-) diff --git a/dvmconsole/App.xaml b/dvmconsole/App.xaml index 5671c61..2428937 100644 --- a/dvmconsole/App.xaml +++ b/dvmconsole/App.xaml @@ -1,86 +1,15 @@  - - - + + + + + + diff --git a/dvmconsole/AudioSettingsWindow.xaml b/dvmconsole/AudioSettingsWindow.xaml index 2aeec3e..ea33c21 100644 --- a/dvmconsole/AudioSettingsWindow.xaml +++ b/dvmconsole/AudioSettingsWindow.xaml @@ -1,7 +1,10 @@  @@ -12,16 +15,18 @@ - + - + - - - + diff --git a/dvmconsole/Controls/ChannelBox.xaml b/dvmconsole/Controls/ChannelBox.xaml index 8af51bf..5bed26c 100644 --- a/dvmconsole/Controls/ChannelBox.xaml +++ b/dvmconsole/Controls/ChannelBox.xaml @@ -2,12 +2,13 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:dvmconsole.Controls" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" Width="220" Height="110"> - + @@ -23,7 +24,7 @@ - + @@ -40,14 +41,14 @@ - @@ -101,22 +102,12 @@ - - diff --git a/dvmconsole/Controls/ChannelBox.xaml.cs b/dvmconsole/Controls/ChannelBox.xaml.cs index 00e584a..5022560 100644 --- a/dvmconsole/Controls/ChannelBox.xaml.cs +++ b/dvmconsole/Controls/ChannelBox.xaml.cs @@ -32,7 +32,9 @@ namespace dvmconsole.Controls { public readonly static Border BORDER_DEFAULT; public readonly static Border BORDER_GREEN; + public readonly static LinearGradientBrush GRAY_GRADIENT; + public readonly static LinearGradientBrush DARK_GRAY_GRADIENT; // Delected/Disconnected Color public readonly static LinearGradientBrush BLUE_GRADIENT; // Selected Channel Color public readonly static LinearGradientBrush RED_GRADIENT; // Playback Selected Color @@ -547,6 +549,7 @@ namespace dvmconsole.Controls if (SystemName == MainWindow.PLAYBACKSYS || ChannelName == MainWindow.PLAYBACKCHNAME || DstId == MainWindow.PLAYBACKTG) { ControlBorder.Background = IsSelected ? RED_GRADIENT : DARK_GRAY_GRADIENT; + SetVolumeMeterBg(ControlBorder.Background); return; } diff --git a/dvmconsole/Controls/SystemStatusBox.xaml b/dvmconsole/Controls/SystemStatusBox.xaml index cf5e4ed..b123943 100644 --- a/dvmconsole/Controls/SystemStatusBox.xaml +++ b/dvmconsole/Controls/SystemStatusBox.xaml @@ -7,8 +7,8 @@ - - + + diff --git a/dvmconsole/DVMConsole.csproj b/dvmconsole/DVMConsole.csproj index 1775aa0..16804ae 100644 --- a/dvmconsole/DVMConsole.csproj +++ b/dvmconsole/DVMConsole.csproj @@ -98,6 +98,7 @@ + diff --git a/dvmconsole/DigitalPageWindow.xaml b/dvmconsole/DigitalPageWindow.xaml index 3eba9a8..f57842f 100644 --- a/dvmconsole/DigitalPageWindow.xaml +++ b/dvmconsole/DigitalPageWindow.xaml @@ -4,15 +4,32 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:dvmconsole" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.FontWeight="Regular" TextElement.FontSize="13" + Style="{StaticResource MaterialDesignWindow}" Background="{DynamicResource MaterialDesignPaper}" FontFamily="{DynamicResource MaterialDesignFont}" mc:Ignorable="d" Icon="/dvmconsole;component/Assets/page.png" - Title="Page Subscriber" Height="141" Width="330" WindowStartupLocation="CenterOwner"> + Title="Page Subscriber" Height="181" Width="340" WindowStartupLocation="CenterOwner"> - - - diff --git a/dvmconsole/DigitalPageWindow.xaml.cs b/dvmconsole/DigitalPageWindow.xaml.cs index 527f055..6e0982a 100644 --- a/dvmconsole/DigitalPageWindow.xaml.cs +++ b/dvmconsole/DigitalPageWindow.xaml.cs @@ -52,7 +52,7 @@ namespace dvmconsole /// /// /// - private void SendPageButton_Click(object sender, RoutedEventArgs e) + private void SendButton_Click(object sender, RoutedEventArgs e) { RadioSystem = SystemCombo.SelectedItem as Codeplug.System; DstId = DstIdText.Text; diff --git a/dvmconsole/KeyStatusWindow.xaml b/dvmconsole/KeyStatusWindow.xaml index dad79d6..752ee8c 100644 --- a/dvmconsole/KeyStatusWindow.xaml +++ b/dvmconsole/KeyStatusWindow.xaml @@ -3,16 +3,18 @@ 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" + TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.FontWeight="Regular" TextElement.FontSize="13" + Style="{StaticResource MaterialDesignWindow}" Background="{DynamicResource MaterialDesignPaper}" FontFamily="{DynamicResource MaterialDesignFont}" mc:Ignorable="d" Icon="/dvmconsole;component/Assets/key.png" Title="Key Status Window" Height="450" Width="800" WindowStartupLocation="CenterOwner"> - + - - - - + + + + diff --git a/dvmconsole/MainWindow.xaml b/dvmconsole/MainWindow.xaml index 858d603..22cbaaf 100644 --- a/dvmconsole/MainWindow.xaml +++ b/dvmconsole/MainWindow.xaml @@ -2,35 +2,29 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:dvmconsole.Controls" - Title="Digital Voice Modem - Desktop Dispatch Console" Height="600" Width="875" Background="#FFF2F2F2" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + Title="Digital Voice Modem - Desktop Dispatch Console" Height="600" Width="1024" + TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.FontWeight="Regular" TextElement.FontSize="13" + Style="{StaticResource MaterialDesignWindow}" Background="{DynamicResource MaterialDesignPaper}" FontFamily="{DynamicResource MaterialDesignFont}" Icon="/dvmconsole;component/Assets/AppIcon.ico"> - + - + - - - - - - - - - - - - + + + - + @@ -39,7 +33,7 @@ - + @@ -51,7 +45,7 @@ - + @@ -62,434 +56,117 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + - - + + - - + - - - - + + - - + - - - - - - - - - - + - - + + - - + - - + + + + - - + + + + + + + + diff --git a/dvmconsole/MainWindow.xaml.cs b/dvmconsole/MainWindow.xaml.cs index 15645cb..5f91eea 100644 --- a/dvmconsole/MainWindow.xaml.cs +++ b/dvmconsole/MainWindow.xaml.cs @@ -19,6 +19,7 @@ using System.Timers; using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using System.Windows.Media; using System.Windows.Media.Imaging; using Microsoft.Win32; @@ -26,6 +27,8 @@ using Microsoft.Win32; using NAudio.Wave; using NWaves.Signals; +using MaterialDesignThemes.Wpf; + using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; @@ -101,6 +104,8 @@ namespace dvmconsole private FlashingBackgroundManager flashingManager; private WaveFilePlaybackManager emergencyAlertPlayback; + private Brush btnGlobalPttDefaultBg; + private ChannelBox playbackChannelBox; CallHistoryWindow callHistoryWindow = new CallHistoryWindow(); @@ -856,6 +861,17 @@ namespace dvmconsole /// private void UpdateBackground() { + // set the UI theme + PaletteHelper paletteHelper = new PaletteHelper(); + Theme theme = paletteHelper.GetTheme(); + + if (settingsManager.DarkMode) + theme.SetBaseTheme(BaseTheme.Dark); + else + theme.SetBaseTheme(BaseTheme.Light); + + paletteHelper.SetTheme(theme); + BitmapImage bg = new BitmapImage(); // do we have a user defined background? @@ -1111,6 +1127,8 @@ namespace dvmconsole menuDarkMode.IsChecked = settingsManager.DarkMode; UpdateBackground(); + btnGlobalPttDefaultBg = btnGlobalPtt.Background; + // set window configuration if (settingsManager.Maximized) { @@ -1184,7 +1202,14 @@ namespace dvmconsole if (pageWindow.ShowDialog() == true) { - PeerSystem handler = fneSystemManager.GetFneSystem(pageWindow.RadioSystem.Name); + // throw an error if the user does the dumb... + if (pageWindow.DstId == string.Empty) + { + MessageBox.Show($"Must supply a destination ID.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + PeerSystem fne = fneSystemManager.GetFneSystem(pageWindow.RadioSystem.Name); IOSP_CALL_ALRT callAlert = new IOSP_CALL_ALRT(uint.Parse(pageWindow.DstId), uint.Parse(pageWindow.RadioSystem.Rid)); RemoteCallData callData = new RemoteCallData @@ -1198,7 +1223,7 @@ namespace dvmconsole callAlert.Encode(ref tsbk); - handler.SendP25TSBK(callData, tsbk); + fne.SendP25TSBK(callData, tsbk); } } @@ -1215,7 +1240,14 @@ namespace dvmconsole if (pageWindow.ShowDialog() == true) { - PeerSystem handler = fneSystemManager.GetFneSystem(pageWindow.RadioSystem.Name); + // throw an error if the user does the dumb... + if (pageWindow.DstId == string.Empty) + { + MessageBox.Show($"Must supply a destination ID.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + PeerSystem fne = fneSystemManager.GetFneSystem(pageWindow.RadioSystem.Name); IOSP_EXT_FNCT extFunc = new IOSP_EXT_FNCT((ushort)ExtendedFunction.CHECK, uint.Parse(pageWindow.RadioSystem.Rid), uint.Parse(pageWindow.DstId)); RemoteCallData callData = new RemoteCallData @@ -1229,7 +1261,7 @@ namespace dvmconsole extFunc.Encode(ref tsbk); - handler.SendP25TSBK(callData, tsbk); + fne.SendP25TSBK(callData, tsbk); } } @@ -1246,7 +1278,14 @@ namespace dvmconsole if (pageWindow.ShowDialog() == true) { - PeerSystem handler = fneSystemManager.GetFneSystem(pageWindow.RadioSystem.Name); + // throw an error if the user does the dumb... + if (pageWindow.DstId == string.Empty) + { + MessageBox.Show($"Must supply a destination ID.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + PeerSystem fne = fneSystemManager.GetFneSystem(pageWindow.RadioSystem.Name); IOSP_EXT_FNCT extFunc = new IOSP_EXT_FNCT((ushort)ExtendedFunction.INHIBIT, P25Defines.WUID_FNE, uint.Parse(pageWindow.DstId)); RemoteCallData callData = new RemoteCallData @@ -1260,7 +1299,7 @@ namespace dvmconsole extFunc.Encode(ref tsbk); - handler.SendP25TSBK(callData, tsbk); + fne.SendP25TSBK(callData, tsbk); } } @@ -1277,7 +1316,14 @@ namespace dvmconsole if (pageWindow.ShowDialog() == true) { - PeerSystem handler = fneSystemManager.GetFneSystem(pageWindow.RadioSystem.Name); + // throw an error if the user does the dumb... + if (pageWindow.DstId == string.Empty) + { + MessageBox.Show($"Must supply a destination ID.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + PeerSystem fne = fneSystemManager.GetFneSystem(pageWindow.RadioSystem.Name); IOSP_EXT_FNCT extFunc = new IOSP_EXT_FNCT((ushort)ExtendedFunction.UNINHIBIT, P25Defines.WUID_FNE, uint.Parse(pageWindow.DstId)); RemoteCallData callData = new RemoteCallData @@ -1291,7 +1337,7 @@ namespace dvmconsole extFunc.Encode(ref tsbk); - handler.SendP25TSBK(callData, tsbk); + fne.SendP25TSBK(callData, tsbk); } } @@ -2015,7 +2061,7 @@ namespace dvmconsole if (globalPttState) btnGlobalPtt.Background = ChannelBox.RED_GRADIENT; else - btnGlobalPtt.Background = ChannelBox.GRAY_GRADIENT; + btnGlobalPtt.Background = btnGlobalPttDefaultBg; }); primaryChannel.PttButton_Click(sender, e); @@ -2069,7 +2115,7 @@ namespace dvmconsole { Dispatcher.Invoke(() => { - btnGlobalPtt.Background = ChannelBox.GRAY_GRADIENT; + btnGlobalPtt.Background = btnGlobalPttDefaultBg; channel.PttState = false; }); diff --git a/dvmconsole/PeerSystem.cs b/dvmconsole/PeerSystem.cs index 60df043..2e956c2 100644 --- a/dvmconsole/PeerSystem.cs +++ b/dvmconsole/PeerSystem.cs @@ -74,6 +74,8 @@ namespace dvmconsole string software = $"CONSOLE_R{_SEM_VERSION.Major.ToString("D2")}A{_SEM_VERSION.Minor.ToString("D2")}"; + if (system.Identity == null) + system.Identity = system.PeerId.ToString(); if (system.Identity.Length == 0) system.Identity = system.PeerId.ToString(); diff --git a/dvmconsole/QuickCallPage.xaml b/dvmconsole/QuickCallPage.xaml index 16bdb3d..5e0eb83 100644 --- a/dvmconsole/QuickCallPage.xaml +++ b/dvmconsole/QuickCallPage.xaml @@ -4,16 +4,31 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:dvmconsole" + TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.FontWeight="Regular" TextElement.FontSize="13" + Style="{StaticResource MaterialDesignWindow}" Background="{DynamicResource MaterialDesignPaper}" FontFamily="{DynamicResource MaterialDesignFont}" mc:Ignorable="d" Icon="/dvmconsole;component/Assets/page.png" - Title="QuickCall II Page" Height="146" Width="330" WindowStartupLocation="CenterOwner"> + Title="QuickCall II Page" Height="166" Width="340" WindowStartupLocation="CenterOwner"> - - - -