V1, Library and example GUI Application.

This commit is contained in:
Andrea Santaniello 2024-11-04 19:09:54 +01:00
parent 357047bc40
commit 0315d8d7dc
6 changed files with 351 additions and 210 deletions

View File

@ -3,22 +3,36 @@ using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
using NAudio.Wave;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace RadioControllerApp
{
public class FormRadio : Form
{
// Pre-buffering fields
private const int PreBufferSize = 5000; // Adjust as needed
private ConcurrentQueue<byte[]> preBufferQueue = new ConcurrentQueue<byte[]>();
private int preBufferedBytes = 0;
private bool preBufferingComplete = false;
private RadioController radioController;
private WaveInEvent waveIn;
private BufferedWaveProvider receivedAudioBuffer;
private WaveOutEvent waveOut;
private bool isRecording = false;
private bool isTransmitting = false;
// PTT Key Handling
private Keys pttKey = Keys.Space;
private bool waitingForPTTKey = false;
// UI Controls
private TextBox txtPortName;
private Button btnOpenConnection;
private Button btnCloseConnection;
private Button btnInitialize;
private TextBox txtTXFrequency;
private TextBox txtRXFrequency;
@ -31,35 +45,38 @@ namespace RadioControllerApp
private CheckBox chkLowpass;
private Button btnSetFilters;
private Button btnStartRX;
private Button btnStartTX;
private Button btnEndTX;
private Button btnStop;
private Button btnStartRecording;
private Button btnStopRecording;
private Button btnPlayReceivedAudio;
private Button btnSetPTTKey;
private TextBox txtStatus;
private Panel pnlStatusIndicator;
public FormRadio()
{
InitializeComponent();
InitializeRadioController();
LoadConfigurations();
}
private void InitializeComponent()
{
this.AutoScaleMode = AutoScaleMode.Dpi; // Enable DPI scaling
// Form properties
this.Text = "Radio Controller";
this.Size = new System.Drawing.Size(800, 700);
this.MinimumSize = new System.Drawing.Size(600, 600);
this.FormClosing += FormRadio_FormClosing;
// Initialize controls
InitializeControls();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormRadio));
SuspendLayout();
//
// FormRadio
//
AutoScaleDimensions = new SizeF(144F, 144F);
AutoScaleMode = AutoScaleMode.Dpi;
ClientSize = new Size(778, 644);
Icon = (Icon)resources.GetObject("$this.Icon");
KeyPreview = true;
MinimumSize = new Size(600, 600);
Name = "FormRadio";
Text = "Radio Controller";
FormClosing += FormRadio_FormClosing;
KeyDown += FormRadio_KeyDown;
KeyUp += FormRadio_KeyUp;
ResumeLayout(false);
}
private void InitializeControls()
@ -74,33 +91,37 @@ namespace RadioControllerApp
};
this.Controls.Add(mainLayout);
// Adjust row styles
// Insert row styles
mainLayout.RowStyles.Insert(0, new RowStyle(SizeType.Absolute, 20F)); // Status Indicator
mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // Connection Controls
mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // Frequency Controls
mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // Filter Controls
mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // Mode Controls
mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // Audio Controls
mainLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); // Status TextBox
// Status Indicator Panel
pnlStatusIndicator = new Panel
{
Height = 20,
Dock = DockStyle.Fill,
BackColor = System.Drawing.Color.Green // Assume green for RX
};
mainLayout.Controls.Add(pnlStatusIndicator, 0, 0);
// Connection Controls GroupBox
GroupBox grpConnection = CreateConnectionControls();
grpConnection.Dock = DockStyle.Fill;
mainLayout.Controls.Add(grpConnection, 0, 0);
mainLayout.Controls.Add(grpConnection, 0, 1);
// Frequency Controls GroupBox
GroupBox grpFrequency = CreateFrequencyControls();
grpFrequency.Dock = DockStyle.Fill;
mainLayout.Controls.Add(grpFrequency, 0, 1);
mainLayout.Controls.Add(grpFrequency, 0, 2);
// Filter Controls GroupBox
GroupBox grpFilters = CreateFilterControls();
grpFilters.Dock = DockStyle.Fill;
mainLayout.Controls.Add(grpFilters, 0, 2);
// Mode Controls GroupBox
GroupBox grpModes = CreateModeControls();
grpModes.Dock = DockStyle.Fill;
mainLayout.Controls.Add(grpModes, 0, 3);
mainLayout.Controls.Add(grpFilters, 0, 3);
// Audio Controls GroupBox
GroupBox grpAudio = CreateAudioControls();
@ -130,7 +151,7 @@ namespace RadioControllerApp
TableLayoutPanel layout = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 5,
ColumnCount = 4,
AutoSize = true
};
grpConnection.Controls.Add(layout);
@ -139,23 +160,19 @@ namespace RadioControllerApp
txtPortName = new TextBox { Text = "COM3", Anchor = AnchorStyles.Left };
btnOpenConnection = new Button { Text = "Open Connection", AutoSize = true };
btnCloseConnection = new Button { Text = "Close Connection", AutoSize = true };
btnInitialize = new Button { Text = "Initialize", AutoSize = true };
btnOpenConnection.Click += btnOpenConnection_Click;
btnCloseConnection.Click += btnCloseConnection_Click;
btnInitialize.Click += btnInitialize_Click;
layout.Controls.Add(lblPortName, 0, 0);
layout.Controls.Add(txtPortName, 1, 0);
layout.Controls.Add(btnOpenConnection, 2, 0);
layout.Controls.Add(btnCloseConnection, 3, 0);
layout.Controls.Add(btnInitialize, 4, 0);
layout.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); // Label
layout.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); // TextBox
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33F)); // Button
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33F)); // Button
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 34F)); // Button
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); // Button
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); // Button
return grpConnection;
}
@ -243,41 +260,6 @@ namespace RadioControllerApp
return grpFilters;
}
private GroupBox CreateModeControls()
{
GroupBox grpModes = new GroupBox
{
Text = "Mode Controls",
AutoSize = true,
Dock = DockStyle.Fill
};
FlowLayoutPanel layout = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
AutoSize = true,
WrapContents = false,
};
grpModes.Controls.Add(layout);
btnStartRX = new Button { Text = "Start RX Mode", AutoSize = true };
btnStartTX = new Button { Text = "Start TX Mode", AutoSize = true };
btnEndTX = new Button { Text = "End TX Mode", AutoSize = true };
btnStop = new Button { Text = "Stop", AutoSize = true };
btnStartRX.Click += btnStartRX_Click;
btnStartTX.Click += btnStartTX_Click;
btnEndTX.Click += btnEndTX_Click;
btnStop.Click += btnStop_Click;
layout.Controls.Add(btnStartRX);
layout.Controls.Add(btnStartTX);
layout.Controls.Add(btnEndTX);
layout.Controls.Add(btnStop);
return grpModes;
}
private GroupBox CreateAudioControls()
{
GroupBox grpAudio = new GroupBox
@ -295,17 +277,10 @@ namespace RadioControllerApp
};
grpAudio.Controls.Add(layout);
btnStartRecording = new Button { Text = "Start Recording", AutoSize = true };
btnStopRecording = new Button { Text = "Stop Recording", AutoSize = true };
btnPlayReceivedAudio = new Button { Text = "Play Received Audio", AutoSize = true };
btnSetPTTKey = new Button { Text = "Set PTT Key", AutoSize = true };
btnSetPTTKey.Click += btnSetPTTKey_Click;
btnStartRecording.Click += btnStartRecording_Click;
btnStopRecording.Click += btnStopRecording_Click;
btnPlayReceivedAudio.Click += btnPlayReceivedAudio_Click;
layout.Controls.Add(btnStartRecording);
layout.Controls.Add(btnStopRecording);
layout.Controls.Add(btnPlayReceivedAudio);
layout.Controls.Add(btnSetPTTKey);
return grpAudio;
}
@ -315,9 +290,16 @@ namespace RadioControllerApp
// Disable controls that require an open connection
ToggleControls(false);
receivedAudioBuffer = new BufferedWaveProvider(new WaveFormat(44100, 16, 1));
receivedAudioBuffer = new BufferedWaveProvider(new WaveFormat(44100, 8, 1))
{
BufferDuration = TimeSpan.FromSeconds(5),
DiscardOnBufferOverflow = true
};
waveOut = new WaveOutEvent();
waveOut.Init(receivedAudioBuffer);
}
private void btnOpenConnection_Click(object sender, EventArgs e)
{
try
@ -334,7 +316,14 @@ namespace RadioControllerApp
radioController.AudioDataReceived += RadioController_AudioDataReceived;
radioController.OpenConnection();
radioController.Initialize();
btnTune_Click(null, null);
// Start RX mode
isTransmitting = false;
UpdateStatusIndicator(false);
AppendStatus($"Connection opened on {portName}.");
radioController.StartRXMode();
ToggleControls(true);
}
catch (Exception ex)
@ -362,19 +351,6 @@ namespace RadioControllerApp
}
}
private void btnInitialize_Click(object sender, EventArgs e)
{
try
{
radioController.Initialize();
AppendStatus("Radio initialized.");
}
catch (Exception ex)
{
AppendStatus($"Error initializing radio: {ex.Message}");
}
}
private void btnTune_Click(object sender, EventArgs e)
{
try
@ -410,59 +386,44 @@ namespace RadioControllerApp
}
}
private void btnStartRX_Click(object sender, EventArgs e)
private void btnSetPTTKey_Click(object sender, EventArgs e)
{
try
AppendStatus("Press any key to set as PTT.");
waitingForPTTKey = true;
}
private void FormRadio_KeyDown(object sender, KeyEventArgs e)
{
if (waitingForPTTKey)
{
radioController.StartRXMode();
AppendStatus("Started RX mode.");
pttKey = e.KeyCode;
waitingForPTTKey = false;
AppendStatus($"PTT key set to: {pttKey}");
e.Handled = true;
}
catch (Exception ex)
else if (e.KeyCode == pttKey)
{
AppendStatus($"Error starting RX mode: {ex.Message}");
if (!isTransmitting)
{
StartTransmission();
}
e.Handled = true;
}
}
private void btnStartTX_Click(object sender, EventArgs e)
private void FormRadio_KeyUp(object sender, KeyEventArgs e)
{
try
if (!waitingForPTTKey && e.KeyCode == pttKey)
{
radioController.StartTXMode();
AppendStatus("Started TX mode.");
}
catch (Exception ex)
{
AppendStatus($"Error starting TX mode: {ex.Message}");
if (isTransmitting)
{
StopTransmission();
}
e.Handled = true;
}
}
private void btnEndTX_Click(object sender, EventArgs e)
{
try
{
radioController.EndTXMode();
AppendStatus("Ended TX mode.");
}
catch (Exception ex)
{
AppendStatus($"Error ending TX mode: {ex.Message}");
}
}
private void btnStop_Click(object sender, EventArgs e)
{
try
{
radioController.Stop();
AppendStatus("Radio stopped.");
}
catch (Exception ex)
{
AppendStatus($"Error stopping radio: {ex.Message}");
}
}
private void btnStartRecording_Click(object sender, EventArgs e)
private void StartTransmission()
{
try
{
@ -473,39 +434,45 @@ namespace RadioControllerApp
}
radioController.StartTXMode();
isRecording = true;
isTransmitting = true;
waveIn = new WaveInEvent();
waveIn.WaveFormat = new WaveFormat(44100, 16, 1);
waveIn.WaveFormat = new WaveFormat(44100, 8, 1);
waveIn.DataAvailable += WaveIn_DataAvailable;
waveIn.StartRecording();
AppendStatus("Recording started.");
AppendStatus("Transmission started.");
// Update status indicator
UpdateStatusIndicator(true);
}
catch (Exception ex)
{
AppendStatus($"Error starting recording: {ex.Message}");
AppendStatus($"Error starting transmission: {ex.Message}");
}
}
private void btnStopRecording_Click(object sender, EventArgs e)
private void StopTransmission()
{
try
{
if (isRecording && waveIn != null)
if (isTransmitting && waveIn != null)
{
waveIn.StopRecording();
waveIn.Dispose();
waveIn = null;
isRecording = false;
isTransmitting = false;
radioController.EndTXMode();
AppendStatus("Recording stopped.");
AppendStatus("Transmission stopped.");
radioController.StartRXMode();
// Update status indicator
UpdateStatusIndicator(false);
}
}
catch (Exception ex)
{
AppendStatus($"Error stopping recording: {ex.Message}");
AppendStatus($"Error stopping transmission: {ex.Message}");
}
}
@ -513,13 +480,13 @@ namespace RadioControllerApp
{
try
{
if (isRecording && radioController != null)
if (isTransmitting && radioController != null)
{
byte[] buffer = new byte[e.BytesRecorded];
Array.Copy(e.Buffer, buffer, e.BytesRecorded);
// Convert audio data to the required format if necessary
await radioController.SendAudioDataAsync(buffer);
// Send audio data asynchronously
await radioController.SendAudioDataAsync(buffer, 0, buffer.Length);
}
}
catch (Exception ex)
@ -528,25 +495,6 @@ namespace RadioControllerApp
}
}
private void btnPlayReceivedAudio_Click(object sender, EventArgs e)
{
try
{
if (waveOut == null)
{
waveOut = new WaveOutEvent();
waveOut.Init(receivedAudioBuffer);
}
waveOut.Play();
AppendStatus("Playing received audio.");
}
catch (Exception ex)
{
AppendStatus($"Error playing received audio: {ex.Message}");
}
}
private void RadioController_ErrorOccurred(object sender, ErrorEventArgs e)
{
AppendStatus($"Error: {e.GetException().Message}");
@ -554,9 +502,39 @@ namespace RadioControllerApp
private void RadioController_AudioDataReceived(object sender, byte[] data)
{
// Buffer the received audio data
receivedAudioBuffer.AddSamples(data, 0, data.Length);
AppendStatus($"Audio data received. Length: {data.Length} bytes.");
Console.WriteLine($"AudioDataReceived called with {data.Length} bytes");
if (!preBufferingComplete)
{
preBufferQueue.Enqueue(data);
preBufferedBytes += data.Length;
if (preBufferedBytes >= PreBufferSize)
{
// Pre-buffering complete, start playback
preBufferingComplete = true;
// Add all pre-buffered data to the buffer
while (preBufferQueue.TryDequeue(out byte[] preBufferData))
{
receivedAudioBuffer.AddSamples(preBufferData, 0, preBufferData.Length);
}
// Start playback
waveOut.Play();
}
}
else
{
// Add received audio data to the buffer
receivedAudioBuffer.AddSamples(data, 0, data.Length);
// Ensure playback is ongoing
if (waveOut.PlaybackState != PlaybackState.Playing)
{
waveOut.Play();
}
}
}
private void AppendStatus(string message)
@ -571,19 +549,30 @@ namespace RadioControllerApp
}
}
private void UpdateStatusIndicator(bool isTransmitting)
{
if (pnlStatusIndicator.InvokeRequired)
{
pnlStatusIndicator.Invoke(new Action(() => UpdateStatusIndicator(isTransmitting)));
}
else
{
if (isTransmitting)
{
pnlStatusIndicator.BackColor = System.Drawing.Color.Red;
}
else
{
pnlStatusIndicator.BackColor = System.Drawing.Color.Green;
}
}
}
private void ToggleControls(bool isEnabled)
{
btnInitialize.Enabled = isEnabled;
btnTune.Enabled = isEnabled;
btnSetFilters.Enabled = isEnabled;
btnStartRX.Enabled = isEnabled;
btnStartTX.Enabled = isEnabled;
btnEndTX.Enabled = isEnabled;
btnStop.Enabled = isEnabled;
btnStartRecording.Enabled = isEnabled;
btnStopRecording.Enabled = isEnabled;
btnPlayReceivedAudio.Enabled = isEnabled;
btnSetPTTKey.Enabled = isEnabled;
// Disable connection buttons appropriately
btnOpenConnection.Enabled = !isEnabled;
@ -610,6 +599,77 @@ namespace RadioControllerApp
waveOut.Dispose();
waveOut = null;
}
// Save configurations
SaveConfigurations();
}
private void LoadConfigurations()
{
string configFile = "config.ini";
if (File.Exists(configFile))
{
string[] lines = File.ReadAllLines(configFile);
foreach (string line in lines)
{
if (line.StartsWith("PortName="))
{
txtPortName.Text = line.Substring("PortName=".Length);
}
else if (line.StartsWith("PTTKey="))
{
if (Enum.TryParse(line.Substring("PTTKey=".Length), out Keys key))
{
pttKey = key;
}
}
else if (line.StartsWith("TXFrequency="))
{
txtTXFrequency.Text = line.Substring("TXFrequency=".Length);
}
else if (line.StartsWith("RXFrequency="))
{
txtRXFrequency.Text = line.Substring("RXFrequency=".Length);
}
else if (line.StartsWith("Tone="))
{
txtTone.Text = line.Substring("Tone=".Length);
}
else if (line.StartsWith("SquelchLevel="))
{
txtSquelchLevel.Text = line.Substring("SquelchLevel=".Length);
}
else if (line.StartsWith("Emphasis="))
{
chkEmphasis.Checked = line.Substring("Emphasis=".Length) == "True";
}
else if (line.StartsWith("Highpass="))
{
chkHighpass.Checked = line.Substring("Highpass=".Length) == "True";
}
else if (line.StartsWith("Lowpass="))
{
chkLowpass.Checked = line.Substring("Lowpass=".Length) == "True";
}
}
}
}
private void SaveConfigurations()
{
string configFile = "config.ini";
using (StreamWriter writer = new StreamWriter(configFile))
{
writer.WriteLine($"PortName={txtPortName.Text}");
writer.WriteLine($"PTTKey={pttKey}");
writer.WriteLine($"TXFrequency={txtTXFrequency.Text}");
writer.WriteLine($"RXFrequency={txtRXFrequency.Text}");
writer.WriteLine($"Tone={txtTone.Text}");
writer.WriteLine($"SquelchLevel={txtSquelchLevel.Text}");
writer.WriteLine($"Emphasis={chkEmphasis.Checked}");
writer.WriteLine($"Highpass={chkHighpass.Checked}");
writer.WriteLine($"Lowpass={chkLowpass.Checked}");
}
}
}
}

View File

@ -117,4 +117,66 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
</value>
</data>
</root>

View File

@ -2,13 +2,29 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<Company>Monocul.us</Company>
<Authors>Andrea Santaniello</Authors>
<Description>Radio GUI for KV4P radio</Description>
<PackageIcon>icon-lg-dark.png</PackageIcon>
<ApplicationIcon>icon-lg-dark.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Content Include="icon-lg-dark.ico" />
</ItemGroup>
<ItemGroup>
<None Include="E:\malattie\malattie_json\icon-lg-dark.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="NAudio" Version="2.2.1" />
</ItemGroup>

BIN
RadioGUI/icon-lg-dark.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
@ -73,6 +74,7 @@ public class RadioController : IDisposable
WriteTimeout = writeTimeout
};
serialPort.DataReceived += SerialPort_DataReceived;
}
public void OpenConnection()
@ -181,7 +183,7 @@ public class RadioController : IDisposable
SendCommand(ESP32Command.FILTERS, paramsStr);
}
public async Task SendAudioDataAsync(byte[] audioData, CancellationToken cancellationToken = default)
public async Task SendAudioDataAsync(byte[] audioData, int offset, int count, CancellationToken cancellationToken = default)
{
lock (_syncLock)
{
@ -193,10 +195,10 @@ public class RadioController : IDisposable
int chunkSize = 512;
Stopwatch stopwatch = new Stopwatch();
for (int i = 0; i < audioData.Length; i += chunkSize)
for (int i = offset; i < count; i += chunkSize)
{
cancellationToken.ThrowIfCancellationRequested();
int remaining = audioData.Length - i;
int remaining = count - i;
int size = remaining > chunkSize ? chunkSize : remaining;
byte[] chunk = new byte[size];
Array.Copy(audioData, i, chunk, 0, size);
@ -217,6 +219,7 @@ public class RadioController : IDisposable
}
}
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] receivedData = null;
@ -246,7 +249,7 @@ public class RadioController : IDisposable
{
mode = currentMode;
}
if (mode == RadioMode.RX)
if (mode != RadioMode.TX)
{
// Raise an event with the received audio data
OnAudioDataReceived(data);

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>kv4p_sharp</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>