EonaCat.HID/Analyzer/MainForm.cs

454 lines
14 KiB
C#

using EonaCat.HID.EventArguments;
using EonaCat.HID.Helpers;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace EonaCat.HID.Analyzer
{
public partial class MainForm : Form
{
IHidManager _deviceManager;
private IHid _device;
private IEnumerable<IHid> _deviceList;
public MainForm()
{
InitializeComponent();
CreateDeviceManager();
}
private void CreateDeviceManager()
{
_deviceManager = HidFactory.CreateDeviceManager();
if (_deviceManager == null)
{
throw new Exception("Failed to create HID manager.");
}
_deviceManager.OnDeviceInserted += Hid_Inserted;
_deviceManager.OnDeviceRemoved += Hid_Removed;
}
public void RefreshDevices(ushort? vendorId = null, ushort? productId = null)
{
_deviceList = _deviceManager.Enumerate(vendorId, productId);
}
private void MainForm_Load(object sender, System.EventArgs e)
{
try
{
rtbEventLog.Font = new Font("Consolas", 9);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void MainForm_Shown(object sender, System.EventArgs e)
{
try
{
RefreshDevices();
UpdateDeviceList();
toolStripStatusLabel1.Text = "Please select device and click open to start.";
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void AppendEventLog(string result, Color? color = null, bool appendNewLine = true)
{
var currentColor = color ?? Color.Black;
if (appendNewLine)
{
result += Environment.NewLine;
}
// update from UI thread
Invoke(new MethodInvoker(() =>
{
rtbEventLog.SelectionStart = rtbEventLog.TextLength;
rtbEventLog.SelectionLength = 0;
rtbEventLog.SelectionColor = currentColor;
rtbEventLog.AppendText(result);
if (!rtbEventLog.Focused)
{
rtbEventLog.ScrollToCaret();
}
}));
}
private void UpdateDeviceList()
{
dataGridView1.SelectionChanged -= DataGridView1_SelectionChanged;
dataGridView1.Rows.Clear();
for (int i = 0; i < _deviceList.Count(); i++)
{
IHid device = _deviceList.ElementAt(i);
var deviceName = "";
var deviceManufacturer = "";
var deviceSerialNumber = "";
deviceName = device.ProductName;
deviceManufacturer = device.Manufacturer;
deviceSerialNumber = device.SerialNumber;
var row = new string[]
{
(i + 1).ToString(),
deviceName,
deviceManufacturer,
deviceSerialNumber,
device.InputReportByteLength.ToString(),
device.OutputReportByteLength.ToString(),
device.FeatureReportByteLength.ToString(),
$"Vendor:{device.VendorId:X4} Product:{device.ProductId:X4} Revision:{device.VendorId:X4}",
device.DevicePath
};
dataGridView1.Rows.Add(row);
}
dataGridView1.SelectionChanged += DataGridView1_SelectionChanged;
DataGridView1_SelectionChanged(this, null);
}
private void PopupException(string message, string caption = "Exception")
{
Invoke(new Action(() =>
{
MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
}));
}
private void NewToolStripMenuItem_Click(object sender, System.EventArgs e)
{
try
{
Process.Start(Assembly.GetExecutingAssembly().Location);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void ExitToolStripMenuItem_Click(object sender, System.EventArgs e)
{
try
{
this.Close();
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
HelpToolStripButton_Click(sender, e);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void ToolStripButtonReload_Click(object sender, EventArgs e)
{
try
{
RefreshDevices();
UpdateDeviceList();
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void ToolStripButtonFilter_Click(object sender, EventArgs e)
{
try
{
ushort? vid = null;
ushort? pid = null;
var str = toolStripTextBoxVidPid.Text.Split(':');
if (!string.IsNullOrEmpty(toolStripTextBoxVidPid.Text))
{
vid = ushort.Parse(str[0], NumberStyles.AllowHexSpecifier);
pid = ushort.Parse(str[1], NumberStyles.AllowHexSpecifier);
}
RefreshDevices(vid, pid);
UpdateDeviceList();
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void ToolStripButtonConnect_Click(object sender, EventArgs e)
{
ConnectToSelectedDeviceAsync().ConfigureAwait(false);
}
private async Task ConnectToSelectedDeviceAsync()
{
await Task.Run(async () =>
{
try
{
_device = _deviceList.ElementAt(dataGridView1.SelectedRows[0].Index);
if (_device == null)
{
throw new Exception("Could not find Hid USB Device with specified VID PID");
}
var device = _device;
device.OnDataReceived -= OnDataReceived;
device.OnDataReceived += OnDataReceived;
device.OnError -= OnError;
device.OnError += OnError;
device.Open();
AppendEventLog($"Connected to device {_device.ProductName}", Color.Green);
AppendEventLog($"Started listening to device {_device.ProductName}", Color.Green);
await device.StartListeningAsync(default).ConfigureAwait(false);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
});
}
private void OnError(object sender, HidErrorEventArgs e)
{
try
{
var str = $"Device error for {e.Device.ProductName} => {e.Exception.Message}";
AppendEventLog(str, Color.Red);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void OnDataReceived(object sender, HidDataReceivedEventArgs e)
{
try
{
var str = $"Rx Input Report from device {e.Device.ProductName} => {BitConverter.ToString(e.Data)}";
AppendEventLog(str, Color.Blue);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void Hid_Removed(object sender, HidEventArgs e)
{
try
{
var str = string.Format("Removed Device --> VID {0:X4}, PID {0:X4}", e.Device.VendorId, e.Device.ProductId);
AppendEventLog(str);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void Hid_Inserted(object sender, HidEventArgs e)
{
try
{
var str = string.Format("Inserted Device --> VID {0:X4}, PID {0:X4}", e.Device.VendorId, e.Device.ProductId);
AppendEventLog(str, Color.Orange);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void ToolStripButtonClear_Click(object sender, EventArgs e)
{
try
{
rtbEventLog.Clear();
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void HelpToolStripButton_Click(object sender, EventArgs e)
{
try
{
var aboutbox = new AboutBox();
aboutbox.ShowDialog();
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private async void ButtonReadInput_Click(object sender, EventArgs e)
{
try
{
if (_device == null)
{
AppendEventLog("No device connected. Please select a device and click 'Connect'.", Color.Red);
return;
}
var len = (int)_device.InputReportByteLength;
if (len <= 0)
{
throw new Exception("This device has no Input Report support!");
}
var buffer = await _device.ReadInputReportAsync();
if (buffer.Length < 2)
{
AppendEventLog("Received report is too short to contain a valid Report ID.", Color.Red);
return;
}
var str = string.Format("Rx Input Report [{0}] <-- {1}", buffer.Length, BitConverter.ToString(buffer));
AppendEventLog(str, Color.Blue);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private async void ButtonWriteOutput_Click(object sender, EventArgs e)
{
try
{
byte hidReportId = byte.Parse(comboBoxReportId.Text.Trim());
byte[] buf = ByteHelper.HexStringToByteArray(textBoxWriteData.Text.Trim());
// Combine report ID and buffer
byte[] outputReport = new byte[buf.Length + 1];
outputReport[0] = hidReportId;
Array.Copy(buf, 0, outputReport, 1, buf.Length);
try
{
await _device.WriteOutputReportAsync(outputReport);
AppendEventLog($"Output report sent: {BitConverter.ToString(outputReport)}", Color.DarkGreen);
}
catch (Exception ex)
{
AppendEventLog("Write failed: " + ex.Message, Color.DarkRed);
}
}
catch (Exception ex)
{
PopupException("Error preparing output report: " + ex.Message);
}
}
private async void ButtonReadFeature_Click(object sender, EventArgs e)
{
try
{
var hidReportId = byte.Parse(comboBoxReportId.Text);
var len = _device.FeatureReportByteLength;
if (len <= 0)
{
throw new Exception("This device has no Feature Report support!");
}
var buffer = await _device.GetFeatureReportAsync(hidReportId);
var str = string.Format("Rx Feature Report [{0}] <-- {1}", buffer.Length, ByteHelper.ByteArrayToHexString(buffer));
AppendEventLog(str, Color.Blue);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private async void ButtonWriteFeature_Click(object sender, EventArgs e)
{
try
{
var hidReportId = byte.Parse(comboBoxReportId.Text);
var buf = ByteHelper.HexStringToByteArray(textBoxWriteData.Text);
var len = _device.FeatureReportByteLength;
if (buf.Length > len)
{
throw new Exception("Write Feature Report Length Exceed");
}
Array.Resize(ref buf, len);
await _device.SendFeatureReportAsync(buf);
var str = string.Format("Tx Feature Report [{0}] --> {1}", buf.Length, ByteHelper.ByteArrayToHexString(buf));
AppendEventLog(str, Color.DarkGreen);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void DataGridView1_SelectionChanged(object sender, EventArgs e)
{
try
{
if (dataGridView1.SelectedRows.Count <= 0)
{
return;
}
var index = dataGridView1.SelectedRows[0].Index;
var info = _deviceList.ElementAt(index);
toolStripTextBoxVidPid.Text = string.Format("{0:X4}:{1:X4}", info.VendorId, info.ProductId);
}
catch (Exception ex)
{
PopupException(ex.Message);
}
}
private void dataGridView1_DoubleClick(object sender, EventArgs e)
{
ConnectToSelectedDeviceAsync().ConfigureAwait(false);
}
private void toolStripTextBoxVidPid_Enter(object sender, EventArgs e)
{
ToolStripButtonFilter_Click(sender, e);
}
}
}