From 1c02dc4cac223a6287a7cec7f2863eeddf8efba1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 7 Aug 2025 02:57:06 +0000
Subject: [PATCH 1/2] Initial plan
From 99ac9e3b59b6bd696040474cc0f5d55238d89fc0 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 7 Aug 2025 03:06:27 +0000
Subject: [PATCH 2/2] Add SharpCAT.Client library with full API implementation
Co-authored-by: ekinnee <1707617+ekinnee@users.noreply.github.com>
---
Client/Models/ApiModels.cs | 216 ++++++++++++++++++++
Client/README.md | 196 ++++++++++++++++++
Client/SharpCAT.Client.csproj | 17 ++
Client/SharpCATClient.cs | 325 ++++++++++++++++++++++++++++++
Client/SharpCATClientException.cs | 60 ++++++
SharpCAT.sln | 6 +
6 files changed, 820 insertions(+)
create mode 100644 Client/Models/ApiModels.cs
create mode 100644 Client/README.md
create mode 100644 Client/SharpCAT.Client.csproj
create mode 100644 Client/SharpCATClient.cs
create mode 100644 Client/SharpCATClientException.cs
diff --git a/Client/Models/ApiModels.cs b/Client/Models/ApiModels.cs
new file mode 100644
index 0000000..72c1c4f
--- /dev/null
+++ b/Client/Models/ApiModels.cs
@@ -0,0 +1,216 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+
+namespace SharpCAT.Client.Models
+{
+ ///
+ /// Parity settings for serial communication
+ ///
+ public enum Parity
+ {
+ ///
+ /// No parity checking
+ ///
+ None = 0,
+ ///
+ /// Odd parity checking
+ ///
+ Odd = 1,
+ ///
+ /// Even parity checking
+ ///
+ Even = 2,
+ ///
+ /// Mark parity checking
+ ///
+ Mark = 3,
+ ///
+ /// Space parity checking
+ ///
+ Space = 4
+ }
+
+ ///
+ /// Stop bits settings for serial communication
+ ///
+ public enum StopBits
+ {
+ ///
+ /// No stop bits
+ ///
+ None = 0,
+ ///
+ /// One stop bit
+ ///
+ One = 1,
+ ///
+ /// Two stop bits
+ ///
+ Two = 2,
+ ///
+ /// One and a half stop bits
+ ///
+ OnePointFive = 3
+ }
+
+ ///
+ /// Handshake settings for serial communication
+ ///
+ public enum Handshake
+ {
+ ///
+ /// No flow control
+ ///
+ None = 0,
+ ///
+ /// XOn/XOff software flow control
+ ///
+ XOnXOff = 1,
+ ///
+ /// RTS hardware flow control
+ ///
+ RequestToSend = 2,
+ ///
+ /// Both RTS and XOn/XOff flow control
+ ///
+ RequestToSendXOnXOff = 3
+ }
+
+ ///
+ /// Response model for listing available serial ports
+ ///
+ public class PortListResponse
+ {
+ ///
+ /// Array of available serial port names
+ ///
+ public string[] Ports { get; set; } = new string[0];
+
+ ///
+ /// Number of available ports
+ ///
+ public int Count => Ports.Length;
+ }
+
+ ///
+ /// Request model for opening a serial port
+ ///
+ public class OpenPortRequest
+ {
+ ///
+ /// Name of the serial port to open (e.g., "COM1", "/dev/ttyUSB0")
+ ///
+ [Required]
+ public string PortName { get; set; } = string.Empty;
+
+ ///
+ /// Baud rate for communication (default: 9600)
+ ///
+ public int BaudRate { get; set; } = 9600;
+
+ ///
+ /// Parity setting (default: None)
+ ///
+ public Parity Parity { get; set; } = Parity.None;
+
+ ///
+ /// Stop bits setting (default: One)
+ ///
+ public StopBits StopBits { get; set; } = StopBits.One;
+
+ ///
+ /// Handshake setting (default: None)
+ ///
+ public Handshake Handshake { get; set; } = Handshake.None;
+ }
+
+ ///
+ /// Response model for port operations
+ ///
+ public class PortOperationResponse
+ {
+ ///
+ /// Indicates if the operation was successful
+ ///
+ public bool Success { get; set; }
+
+ ///
+ /// Human-readable message about the operation
+ ///
+ public string Message { get; set; } = string.Empty;
+
+ ///
+ /// Name of the port that was operated on
+ ///
+ public string? PortName { get; set; }
+
+ ///
+ /// Current status of the port (open/closed)
+ ///
+ public bool IsOpen { get; set; }
+ }
+
+ ///
+ /// Request model for sending CAT commands
+ ///
+ public class SendCommandRequest
+ {
+ ///
+ /// CAT command string to send to the radio
+ ///
+ [Required]
+ public string Command { get; set; } = string.Empty;
+ }
+
+ ///
+ /// Response model for CAT command operations
+ ///
+ public class CommandResponse
+ {
+ ///
+ /// Indicates if the command was sent successfully
+ ///
+ public bool Success { get; set; }
+
+ ///
+ /// The command that was sent
+ ///
+ public string Command { get; set; } = string.Empty;
+
+ ///
+ /// Response received from the radio (if any)
+ ///
+ public string? Response { get; set; }
+
+ ///
+ /// Human-readable message about the operation
+ ///
+ public string Message { get; set; } = string.Empty;
+
+ ///
+ /// Timestamp when the command was executed
+ ///
+ public DateTime Timestamp { get; set; } = DateTime.UtcNow;
+ }
+
+ ///
+ /// Response model for errors
+ ///
+ public class ErrorResponse
+ {
+ ///
+ /// Error message
+ ///
+ public string Error { get; set; } = string.Empty;
+
+ ///
+ /// Additional details about the error
+ ///
+ public string? Details { get; set; }
+
+ ///
+ /// Timestamp when the error occurred
+ ///
+ public DateTime Timestamp { get; set; } = DateTime.UtcNow;
+ }
+}
\ No newline at end of file
diff --git a/Client/README.md b/Client/README.md
new file mode 100644
index 0000000..4dd3a4e
--- /dev/null
+++ b/Client/README.md
@@ -0,0 +1,196 @@
+# SharpCAT.Client
+
+A .NET Standard 2.0 client library that provides a typed C# API for consuming the SharpCAT Server HTTP API endpoints. This library makes it easy to integrate CAT (Computer Aided Transceiver) control into your .NET applications.
+
+## Features
+
+- **Typed API**: Strongly-typed C# methods for all SharpCAT Server endpoints
+- **Async/Await Support**: Modern async programming with cancellation token support
+- **Error Handling**: Comprehensive error handling with custom exceptions
+- **Cross-Platform**: .NET Standard 2.0 compatible (works with .NET Core, .NET Framework, .NET 5+)
+- **HTTP Client Integration**: Uses System.Net.Http.Json for JSON serialization
+- **Frequency Helpers**: Convenient methods for getting/setting radio frequencies
+- **XML Documentation**: Full IntelliSense support with comprehensive documentation
+
+## Installation
+
+Add the SharpCAT.Client project reference to your application:
+
+```xml
+
+```
+
+## Quick Start
+
+### Basic Usage
+
+```csharp
+using SharpCAT.Client;
+using SharpCAT.Client.Models;
+
+// Create client instance
+using var client = new SharpCATClient("http://localhost:5188");
+
+// Get available serial ports
+var ports = await client.GetPortsAsync();
+Console.WriteLine($"Available ports: {string.Join(", ", ports.Ports)}");
+
+// Open a serial port
+var openRequest = new OpenPortRequest
+{
+ PortName = "COM3",
+ BaudRate = 9600
+};
+var openResult = await client.OpenPortAsync(openRequest);
+Console.WriteLine($"Port opened: {openResult.Success}");
+
+// Send a raw CAT command
+var commandResult = await client.SendCommandAsync("FA;");
+Console.WriteLine($"Command response: {commandResult.Response}");
+
+// Use convenience methods for frequency operations
+var frequency = await client.GetFrequencyAsync();
+Console.WriteLine($"Current frequency: {frequency} Hz");
+
+await client.SetFrequencyAsync(14074000); // Set to 14.074 MHz
+```
+
+### Advanced Usage
+
+```csharp
+// Use with dependency injection and HttpClientFactory
+services.AddHttpClient(client =>
+{
+ client.BaseAddress = new Uri("http://localhost:5188");
+});
+
+// Handle errors
+try
+{
+ var result = await client.SendCommandAsync("invalid_command");
+}
+catch (SharpCATClientException ex)
+{
+ Console.WriteLine($"Error: {ex.Message}");
+ if (ex.Details != null)
+ Console.WriteLine($"Details: {ex.Details}");
+}
+
+// Use cancellation tokens
+using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
+var status = await client.GetStatusAsync(cts.Token);
+```
+
+## API Reference
+
+### Core Methods
+
+#### Port Management
+- `GetPortsAsync()` - Get all available serial ports
+- `OpenPortAsync(request)` - Open and configure a serial port
+- `ClosePortAsync()` - Close the current serial port
+- `GetStatusAsync()` - Get current port connection status
+
+#### CAT Commands
+- `SendCommandAsync(command)` - Send a raw CAT command string
+- `SendCommandAsync(request)` - Send a CAT command with full request object
+
+#### Frequency Operations (Convenience Methods)
+- `GetFrequencyAsync()` - Get current frequency (VFO A)
+- `SetFrequencyAsync(frequencyHz)` - Set frequency (VFO A)
+- `GetFrequencyBAsync()` - Get current frequency (VFO B)
+- `SetFrequencyBAsync(frequencyHz)` - Set frequency (VFO B)
+
+### Configuration Options
+
+When opening a port, you can configure:
+
+```csharp
+var request = new OpenPortRequest
+{
+ PortName = "COM3", // Required
+ BaudRate = 9600, // Default: 9600
+ Parity = Parity.None, // Default: None
+ StopBits = StopBits.One, // Default: One
+ Handshake = Handshake.None // Default: None
+};
+```
+
+### Error Handling
+
+The client throws `SharpCATClientException` for various error conditions:
+
+- HTTP request failures
+- Network timeouts
+- API error responses
+- Deserialization failures
+
+```csharp
+try
+{
+ var result = await client.GetPortsAsync();
+}
+catch (SharpCATClientException ex)
+{
+ // Handle SharpCAT-specific errors
+ Console.WriteLine($"SharpCAT Error: {ex.Message}");
+}
+catch (Exception ex)
+{
+ // Handle other errors
+ Console.WriteLine($"Unexpected error: {ex.Message}");
+}
+```
+
+## Common CAT Commands
+
+Here are some common CAT commands you can send using `SendCommandAsync()`:
+
+| Command | Description | Example Response |
+|---------|-------------|------------------|
+| `FA;` | Get VFO A frequency | `FA00014074000;` |
+| `FB;` | Get VFO B frequency | `FB00007074000;` |
+| `FA14074000;` | Set VFO A frequency | No response or `FA14074000;` |
+| `MD;` | Get operating mode | `MD2;` (USB) |
+| `MD2;` | Set mode to USB | No response |
+| `IF;` | Get radio information | `IF00014074000...;` |
+
+**Note**: The exact commands and responses depend on your radio model. Consult your radio's CAT documentation for complete command reference.
+
+## Thread Safety
+
+The `SharpCATClient` class is thread-safe for concurrent read operations, but write operations (like sending commands) should be serialized to avoid conflicts at the radio level.
+
+## Disposal
+
+The client implements `IDisposable`. When you create a client with a base address string or URI, it owns the internal `HttpClient` and will dispose it. If you pass in your own `HttpClient`, the client will not dispose it.
+
+```csharp
+// Client owns HttpClient - will be disposed
+using var client = new SharpCATClient("http://localhost:5188");
+
+// You own HttpClient - manage disposal yourself
+var httpClient = new HttpClient();
+var client = new SharpCATClient(httpClient);
+// Don't forget to dispose httpClient when done
+```
+
+## Requirements
+
+- .NET Standard 2.0 or later
+- SharpCAT Server running and accessible
+- Network connectivity to the server
+
+## Dependencies
+
+- System.Net.Http.Json (5.0.0)
+- System.Text.Json (5.0.2)
+- System.ComponentModel.Annotations (5.0.0)
+
+## License
+
+This project follows the same license as the parent SharpCAT project.
+
+## Contributing
+
+Contributions are welcome! Please follow the existing code style and add appropriate documentation for new features.
\ No newline at end of file
diff --git a/Client/SharpCAT.Client.csproj b/Client/SharpCAT.Client.csproj
new file mode 100644
index 0000000..6cf16d9
--- /dev/null
+++ b/Client/SharpCAT.Client.csproj
@@ -0,0 +1,17 @@
+
+
+
+ netstandard2.0
+ enable
+ true
+ $(NoWarn);1591
+ 9.0
+
+
+
+
+
+
+
+
+
diff --git a/Client/SharpCATClient.cs b/Client/SharpCATClient.cs
new file mode 100644
index 0000000..07b2670
--- /dev/null
+++ b/Client/SharpCATClient.cs
@@ -0,0 +1,325 @@
+using System;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using SharpCAT.Client.Models;
+
+namespace SharpCAT.Client
+{
+ ///
+ /// Client for accessing SharpCAT Server API endpoints
+ ///
+ public class SharpCATClient : IDisposable
+ {
+ private readonly HttpClient _httpClient;
+ private readonly bool _ownsHttpClient;
+
+ ///
+ /// Gets the base address of the SharpCAT server
+ ///
+ public Uri BaseAddress => _httpClient.BaseAddress ?? throw new InvalidOperationException("Base address not set");
+
+ ///
+ /// Initializes a new instance of the SharpCATClient with the specified base address
+ ///
+ /// Base URL of the SharpCAT server (e.g., "http://localhost:5188")
+ public SharpCATClient(string baseAddress) : this(new Uri(baseAddress))
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the SharpCATClient with the specified base address
+ ///
+ /// Base URI of the SharpCAT server
+ public SharpCATClient(Uri baseAddress)
+ {
+ _httpClient = new HttpClient { BaseAddress = baseAddress };
+ _ownsHttpClient = true;
+ }
+
+ ///
+ /// Initializes a new instance of the SharpCATClient with an existing HttpClient
+ ///
+ /// Configured HttpClient instance
+ public SharpCATClient(HttpClient httpClient)
+ {
+ _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
+ _ownsHttpClient = false;
+ }
+
+ ///
+ /// Gets all available serial ports on the system
+ ///
+ /// Cancellation token
+ /// List of available serial ports
+ /// Thrown when the API call fails
+ public async Task GetPortsAsync(CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ var response = await _httpClient.GetFromJsonAsync("api/cat/ports", cancellationToken);
+ return response ?? throw new SharpCATClientException("Failed to deserialize response");
+ }
+ catch (HttpRequestException ex)
+ {
+ throw new SharpCATClientException("Failed to get ports", ex);
+ }
+ catch (TaskCanceledException ex)
+ {
+ throw new SharpCATClientException("Request timed out", ex);
+ }
+ }
+
+ ///
+ /// Opens and configures a serial port for communication
+ ///
+ /// Port configuration parameters
+ /// Cancellation token
+ /// Result of the port open operation
+ /// Thrown when request is null
+ /// Thrown when the API call fails
+ public async Task OpenPortAsync(OpenPortRequest request, CancellationToken cancellationToken = default)
+ {
+ if (request == null) throw new ArgumentNullException(nameof(request));
+
+ try
+ {
+ var httpResponse = await _httpClient.PostAsJsonAsync("api/cat/open", request, cancellationToken);
+
+ if (httpResponse.IsSuccessStatusCode)
+ {
+ var response = await httpResponse.Content.ReadFromJsonAsync(cancellationToken: cancellationToken);
+ return response ?? throw new SharpCATClientException("Failed to deserialize response");
+ }
+ else
+ {
+ var errorResponse = await httpResponse.Content.ReadFromJsonAsync(cancellationToken: cancellationToken);
+ throw new SharpCATClientException($"API returned error: {errorResponse?.Error ?? "Unknown error"}", errorResponse?.Details);
+ }
+ }
+ catch (HttpRequestException ex)
+ {
+ throw new SharpCATClientException("Failed to open port", ex);
+ }
+ catch (TaskCanceledException ex)
+ {
+ throw new SharpCATClientException("Request timed out", ex);
+ }
+ }
+
+ ///
+ /// Closes the currently opened serial port
+ ///
+ /// Cancellation token
+ /// Result of the port close operation
+ /// Thrown when the API call fails
+ public async Task ClosePortAsync(CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ var httpResponse = await _httpClient.PostAsync("api/cat/close", null, cancellationToken);
+
+ if (httpResponse.IsSuccessStatusCode)
+ {
+ var response = await httpResponse.Content.ReadFromJsonAsync(cancellationToken: cancellationToken);
+ return response ?? throw new SharpCATClientException("Failed to deserialize response");
+ }
+ else
+ {
+ var errorResponse = await httpResponse.Content.ReadFromJsonAsync(cancellationToken: cancellationToken);
+ throw new SharpCATClientException($"API returned error: {errorResponse?.Error ?? "Unknown error"}", errorResponse?.Details);
+ }
+ }
+ catch (HttpRequestException ex)
+ {
+ throw new SharpCATClientException("Failed to close port", ex);
+ }
+ catch (TaskCanceledException ex)
+ {
+ throw new SharpCATClientException("Request timed out", ex);
+ }
+ }
+
+ ///
+ /// Gets the current status of the serial port connection
+ ///
+ /// Cancellation token
+ /// Current port status
+ /// Thrown when the API call fails
+ public async Task GetStatusAsync(CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ var response = await _httpClient.GetFromJsonAsync("api/cat/status", cancellationToken);
+ return response ?? throw new SharpCATClientException("Failed to deserialize response");
+ }
+ catch (HttpRequestException ex)
+ {
+ throw new SharpCATClientException("Failed to get status", ex);
+ }
+ catch (TaskCanceledException ex)
+ {
+ throw new SharpCATClientException("Request timed out", ex);
+ }
+ }
+
+ ///
+ /// Sends a CAT command to the connected radio
+ ///
+ /// CAT command to send
+ /// Cancellation token
+ /// Result of the command operation including any response from the radio
+ /// Thrown when request is null
+ /// Thrown when the API call fails
+ public async Task SendCommandAsync(SendCommandRequest request, CancellationToken cancellationToken = default)
+ {
+ if (request == null) throw new ArgumentNullException(nameof(request));
+
+ try
+ {
+ var httpResponse = await _httpClient.PostAsJsonAsync("api/cat/command", request, cancellationToken);
+
+ if (httpResponse.IsSuccessStatusCode)
+ {
+ var response = await httpResponse.Content.ReadFromJsonAsync(cancellationToken: cancellationToken);
+ return response ?? throw new SharpCATClientException("Failed to deserialize response");
+ }
+ else
+ {
+ var errorResponse = await httpResponse.Content.ReadFromJsonAsync(cancellationToken: cancellationToken);
+ throw new SharpCATClientException($"API returned error: {errorResponse?.Error ?? "Unknown error"}", errorResponse?.Details);
+ }
+ }
+ catch (HttpRequestException ex)
+ {
+ throw new SharpCATClientException("Failed to send command", ex);
+ }
+ catch (TaskCanceledException ex)
+ {
+ throw new SharpCATClientException("Request timed out", ex);
+ }
+ }
+
+ ///
+ /// Sends a CAT command to the connected radio
+ ///
+ /// CAT command string to send
+ /// Cancellation token
+ /// Result of the command operation including any response from the radio
+ /// Thrown when command is null
+ /// Thrown when the API call fails
+ public async Task SendCommandAsync(string command, CancellationToken cancellationToken = default)
+ {
+ if (command == null) throw new ArgumentNullException(nameof(command));
+
+ var request = new SendCommandRequest { Command = command };
+ return await SendCommandAsync(request, cancellationToken);
+ }
+
+ ///
+ /// Gets the current frequency from the radio (VFO A)
+ ///
+ /// Cancellation token
+ /// Current frequency in Hz, or null if the command failed or returned no data
+ /// Thrown when the API call fails
+ public async Task GetFrequencyAsync(CancellationToken cancellationToken = default)
+ {
+ var response = await SendCommandAsync("FA;", cancellationToken);
+
+ if (!response.Success || string.IsNullOrEmpty(response.Response))
+ return null;
+
+ // Parse frequency response: FA00014074000; -> 14074000 Hz
+ var frequencyStr = response.Response;
+ if (!string.IsNullOrEmpty(frequencyStr) && frequencyStr.StartsWith("FA") && frequencyStr.EndsWith(";"))
+ {
+ var freqPart = frequencyStr.Substring(2, frequencyStr.Length - 3);
+ if (long.TryParse(freqPart, out var frequency))
+ {
+ return frequency;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Sets the frequency for the radio (VFO A)
+ ///
+ /// Frequency in Hz
+ /// Cancellation token
+ /// True if the command was sent successfully
+ /// Thrown when frequency is out of valid range
+ /// Thrown when the API call fails
+ public async Task SetFrequencyAsync(long frequencyHz, CancellationToken cancellationToken = default)
+ {
+ if (frequencyHz < 0 || frequencyHz > 999999999999)
+ throw new ArgumentOutOfRangeException(nameof(frequencyHz), "Frequency must be between 0 and 999,999,999,999 Hz");
+
+ // Format frequency as 11-digit string with leading zeros
+ var command = $"FA{frequencyHz:D11};";
+ var response = await SendCommandAsync(command, cancellationToken);
+
+ return response.Success;
+ }
+
+ ///
+ /// Gets the current frequency from the radio (VFO B)
+ ///
+ /// Cancellation token
+ /// Current frequency in Hz, or null if the command failed or returned no data
+ /// Thrown when the API call fails
+ public async Task GetFrequencyBAsync(CancellationToken cancellationToken = default)
+ {
+ var response = await SendCommandAsync("FB;", cancellationToken);
+
+ if (!response.Success || string.IsNullOrEmpty(response.Response))
+ return null;
+
+ // Parse frequency response: FB00014074000; -> 14074000 Hz
+ var frequencyStr = response.Response;
+ if (!string.IsNullOrEmpty(frequencyStr) && frequencyStr.StartsWith("FB") && frequencyStr.EndsWith(";"))
+ {
+ var freqPart = frequencyStr.Substring(2, frequencyStr.Length - 3);
+ if (long.TryParse(freqPart, out var frequency))
+ {
+ return frequency;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Sets the frequency for the radio (VFO B)
+ ///
+ /// Frequency in Hz
+ /// Cancellation token
+ /// True if the command was sent successfully
+ /// Thrown when frequency is out of valid range
+ /// Thrown when the API call fails
+ public async Task SetFrequencyBAsync(long frequencyHz, CancellationToken cancellationToken = default)
+ {
+ if (frequencyHz < 0 || frequencyHz > 999999999999)
+ throw new ArgumentOutOfRangeException(nameof(frequencyHz), "Frequency must be between 0 and 999,999,999,999 Hz");
+
+ // Format frequency as 11-digit string with leading zeros
+ var command = $"FB{frequencyHz:D11};";
+ var response = await SendCommandAsync(command, cancellationToken);
+
+ return response.Success;
+ }
+
+ ///
+ /// Disposes the client and releases resources
+ ///
+ public void Dispose()
+ {
+ if (_ownsHttpClient)
+ {
+ _httpClient?.Dispose();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Client/SharpCATClientException.cs b/Client/SharpCATClientException.cs
new file mode 100644
index 0000000..070d3e6
--- /dev/null
+++ b/Client/SharpCATClientException.cs
@@ -0,0 +1,60 @@
+using System;
+
+namespace SharpCAT.Client
+{
+ ///
+ /// Exception thrown by SharpCAT client operations
+ ///
+ public class SharpCATClientException : Exception
+ {
+ ///
+ /// Additional details about the error
+ ///
+ public string? Details { get; }
+
+ ///
+ /// Initializes a new instance of the SharpCATClientException class
+ ///
+ public SharpCATClientException()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the SharpCATClientException class with a specified error message
+ ///
+ /// The message that describes the error
+ public SharpCATClientException(string message) : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the SharpCATClientException class with a specified error message and details
+ ///
+ /// The message that describes the error
+ /// Additional details about the error
+ public SharpCATClientException(string message, string? details) : base(message)
+ {
+ Details = details;
+ }
+
+ ///
+ /// Initializes a new instance of the SharpCATClientException class with a specified error message and a reference to the inner exception
+ ///
+ /// The message that describes the error
+ /// The exception that is the cause of the current exception
+ public SharpCATClientException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the SharpCATClientException class with a specified error message, details, and a reference to the inner exception
+ ///
+ /// The message that describes the error
+ /// Additional details about the error
+ /// The exception that is the cause of the current exception
+ public SharpCATClientException(string message, string? details, Exception innerException) : base(message, innerException)
+ {
+ Details = details;
+ }
+ }
+}
\ No newline at end of file
diff --git a/SharpCAT.sln b/SharpCAT.sln
index 02ee0d1..5be7bc7 100644
--- a/SharpCAT.sln
+++ b/SharpCAT.sln
@@ -9,6 +9,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{43CFF6
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{22E4F655-252E-42DB-ADD5-494BC825A97C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCAT.Client", "Client\SharpCAT.Client.csproj", "{661C070A-612A-41CD-B9DC-9EF9FA05121A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -26,6 +28,10 @@ Global
{22E4F655-252E-42DB-ADD5-494BC825A97C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{22E4F655-252E-42DB-ADD5-494BC825A97C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{22E4F655-252E-42DB-ADD5-494BC825A97C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {661C070A-612A-41CD-B9DC-9EF9FA05121A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {661C070A-612A-41CD-B9DC-9EF9FA05121A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {661C070A-612A-41CD-B9DC-9EF9FA05121A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {661C070A-612A-41CD-B9DC-9EF9FA05121A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{22E4F655-252E-42DB-ADD5-494BC825A97C} = {43CFF66C-84E6-4EC2-AE4F-005FB80D74D5}