Skip to content

Commit

Permalink
Add minidump generation, more error handling and logging
Browse files Browse the repository at this point in the history
  • Loading branch information
Leapward-Koex committed Feb 13, 2024
1 parent 6f36483 commit 31f9706
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 89 deletions.
37 changes: 35 additions & 2 deletions App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Windows;

namespace WpfMaiTouchEmulator;
Expand All @@ -8,5 +8,38 @@ namespace WpfMaiTouchEmulator;
/// </summary>
public partial class App : Application
{
public App()
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
DispatcherUnhandledException += App_DispatcherUnhandledException;
Logger.CleanupOldLogFiles();
}

private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
CreateDump(e.Exception);
e.Handled = true;
}

private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
CreateDump(e.ExceptionObject as Exception);
}

private void CreateDump(Exception exception)
{
var dumpFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CrashDump.dmp");

using (var fs = new FileStream(dumpFilePath, FileMode.Create))
{
var process = Process.GetCurrentProcess();
DumpCreator.MiniDumpWriteDump(process.Handle, (uint)process.Id, fs.SafeFileHandle, DumpCreator.Typ.MiniDumpNormal, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}

Logger.Fatal("App encountered a fatal exception", exception);
MessageBox.Show($"A uncaught exception was thrown: {exception.Message}. \n\n {exception.StackTrace}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
Current.Shutdown(1);
}

}

20 changes: 20 additions & 0 deletions DumpCreator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;

class DumpCreator
{
[Flags]
public enum Typ : uint
{
// Add the MiniDump flags you need, for example:
MiniDumpNormal = 0x00000000,
MiniDumpWithDataSegs = 0x00000001,
// etc.
}

[DllImport("DbgHelp.dll")]
public static extern bool MiniDumpWriteDump(IntPtr hProcess, uint ProcessId, SafeHandle hFile, Typ DumpType,
IntPtr ExceptionParam, IntPtr UserStreamParam, IntPtr CallbackParam);
}
91 changes: 91 additions & 0 deletions Logger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.IO;
using System.Text;

public static class Logger
{
private static readonly object lockObj = new();
private static string? logFilePath;

private static string GetLogFilePath()
{
if (logFilePath == null)
{
var fileName = $"app_{DateTime.Now:yyyy-MM-dd}.log";
logFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
}
return logFilePath;
}


public static void CleanupOldLogFiles()
{
var directory = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
var oldFiles = directory.GetFiles("app_*.log")
.Where(f => f.CreationTime < DateTime.Now.AddDays(-7))
.ToList();

foreach (var file in oldFiles)
{
try
{
file.Delete();
}
catch (Exception ex)
{
Error("Failed to delete log file", ex);
}
}
}


public static void Info(string message)
{
Log("INFO", message);
}

public static void Warn(string message)
{
Log("WARN", message);
}

public static void Error(string message, Exception? ex = null)
{
var logMessage = new StringBuilder(message);
if (ex != null)
{
logMessage.AppendLine(); // Ensure the exception starts on a new line
logMessage.AppendLine($"Exception: {ex.Message}");
logMessage.AppendLine($"StackTrace: {ex.StackTrace}");
}

Log("ERROR", logMessage.ToString());
}

public static void Fatal(string message, Exception? ex = null)
{
var logMessage = new StringBuilder(message);
if (ex != null)
{
logMessage.AppendLine(); // Ensure the exception starts on a new line
logMessage.AppendLine($"Exception: {ex.Message}");
logMessage.AppendLine($"StackTrace: {ex.StackTrace}");
}
Log("FATAL", logMessage.ToString());
}

private static void Log(string level, string message)
{
try
{
lock (lockObj)
{
using var sw = new StreamWriter(GetLogFilePath(), true, Encoding.UTF8);
sw.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{level}] {message}");
}
}
catch
{
}
}
}
120 changes: 65 additions & 55 deletions MaiTouchComConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,52 @@
using System.Windows;

namespace WpfMaiTouchEmulator;
internal class MaiTouchComConnector
internal class MaiTouchComConnector(MaiTouchSensorButtonStateManager buttonState)
{
private static SerialPort? serialPort;
private bool isActiveMode;
private bool _connected;
private bool _shouldReconnect = true;
private readonly MaiTouchSensorButtonStateManager _buttonState;
private readonly MaiTouchSensorButtonStateManager _buttonState = buttonState;

public Action<string> OnConnectStatusChange
public Action<string>? OnConnectStatusChange
{
get;
internal set;
}
public Action OnConnectError
public Action? OnConnectError
{
get;
internal set;
}
public Action<string> OnDataSent
public Action<string>? OnDataSent
{
get;
internal set;
}
public Action<string> OnDataRecieved
public Action<string>? OnDataRecieved
{
get;
internal set;
}

public MaiTouchComConnector(MaiTouchSensorButtonStateManager buttonState)
{
_buttonState = buttonState;
}

public async Task StartTouchSensorPolling()
{
if (!_connected && _shouldReconnect)
{
Logger.Info("Trying to connect to COM port...");
var virtualPort = "COM23"; // Adjust as needed
try
{
OnConnectStatusChange("Conecting...");
serialPort = new SerialPort(virtualPort, 9600, Parity.None, 8, StopBits.One);
serialPort.WriteTimeout = 100;
OnConnectStatusChange?.Invoke("Conecting...");
serialPort = new SerialPort(virtualPort, 9600, Parity.None, 8, StopBits.One)
{
WriteTimeout = 100
};
serialPort.DataReceived += SerialPort_DataReceived;
serialPort.Open();
Console.WriteLine("Serial port opened successfully.");
OnConnectStatusChange("Connected to port");
Logger.Info("Serial port opened successfully.");
OnConnectStatusChange?.Invoke("Connected to port");
_connected = true;

while (true)
Expand All @@ -69,7 +67,7 @@ public async Task StartTouchSensorPolling()
catch (TimeoutException) { }
catch (Exception ex)
{
OnConnectError();
OnConnectError?.Invoke();
Application.Current.Dispatcher.Invoke(() =>
{
MessageBox.Show(ex.Message, "Error connecting to COM port", MessageBoxButton.OK, MessageBoxImage.Error);
Expand All @@ -78,10 +76,13 @@ public async Task StartTouchSensorPolling()
}
finally
{
Logger.Info("Disconnecting from COM port");
_connected = false;
OnConnectStatusChange("Not Connected");
OnConnectStatusChange?.Invoke("Not Connected");
if (serialPort?.IsOpen == true)
{
serialPort.DiscardInBuffer();
serialPort.DiscardOutBuffer();
serialPort.Close();
}
}
Expand All @@ -90,62 +91,71 @@ public async Task StartTouchSensorPolling()

public async Task Disconnect()
{
Logger.Info("Disconnecting from COM port");
_shouldReconnect = false;
_connected = false;
try
{
serialPort.DtrEnable = false;
serialPort.RtsEnable = false;
serialPort.DataReceived -= SerialPort_DataReceived;
await Task.Delay(200);
if (serialPort.IsOpen == true)
if (serialPort != null)
{
serialPort.DiscardInBuffer();
serialPort.DiscardOutBuffer();
serialPort.Close();
serialPort.DtrEnable = false;
serialPort.RtsEnable = false;
serialPort.DataReceived -= SerialPort_DataReceived;
await Task.Delay(200);
if (serialPort.IsOpen == true)
{
serialPort.DiscardInBuffer();
serialPort.DiscardOutBuffer();
serialPort.Close();
}
}

}
catch (Exception ex)
{
Logger.Error("Error whilst disconnecting from COM port", ex);
MessageBox.Show(ex.Message);
}
}

void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var recievedData = serialPort.ReadExisting();
var commands = recievedData.Split(new[] { '}' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var command in commands)
var recievedData = serialPort?.ReadExisting();
var commands = recievedData?.Split(new[] { '}' }, StringSplitOptions.RemoveEmptyEntries);
if (commands != null)
{
var cleanedCommand = command.TrimStart('{');
Console.WriteLine($"Received data: {cleanedCommand}");
OnDataRecieved(cleanedCommand);

if (cleanedCommand == "STAT")
{
isActiveMode = true;
}
else if (cleanedCommand == "RSET")
foreach (var command in commands)
{
var cleanedCommand = command.TrimStart('{');
Logger.Info($"Received serial data: {cleanedCommand}");
OnDataRecieved?.Invoke(cleanedCommand);

}
else if (cleanedCommand == "HALT")
{
isActiveMode = false;
}
else if (cleanedCommand[2] == 'r' || cleanedCommand[2] == 'k')
{
var leftOrRight = cleanedCommand[0];
var sensor = cleanedCommand[1];
var ratio = cleanedCommand[3];
if (cleanedCommand == "STAT")
{
isActiveMode = true;
}
else if (cleanedCommand == "RSET")
{

var newString = $"({leftOrRight}{sensor}{cleanedCommand[2]}{ratio})";
serialPort.Write(newString);
OnDataSent(newString);
}
else
{
Console.WriteLine(cleanedCommand);
}
else if (cleanedCommand == "HALT")
{
isActiveMode = false;
}
else if (cleanedCommand[2] == 'r' || cleanedCommand[2] == 'k')
{
var leftOrRight = cleanedCommand[0];
var sensor = cleanedCommand[1];
var ratio = cleanedCommand[3];

var newString = $"({leftOrRight}{sensor}{cleanedCommand[2]}{ratio})";
serialPort?.Write(newString);
OnDataSent?.Invoke(newString);
}
else
{
Logger.Warn($"Unhandled serial data command {cleanedCommand}");
}
}
}
}
Expand Down
Loading

0 comments on commit 31f9706

Please sign in to comment.