Skip to content

Commit

Permalink
Merge branch 'release/v1.0.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
EvilLord666 committed Mar 4, 2024
2 parents 0d3653c + 05dfeb7 commit 3fa7c91
Show file tree
Hide file tree
Showing 20 changed files with 435 additions and 232 deletions.
1 change: 1 addition & 0 deletions app/Wissance.Zerial/Wissance.Zerial.Common.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using NUnit.Framework;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Wissance.Zerial.Common.Utils;

namespace Wissance.Zerial.Common.Tests.Utils
{
public class TestSerialPortNameHelper
{
[TestCase(true, 4, "COM4", true)]
[TestCase(false, 1, "/dev/tty1", false)]
[TestCase(false, 2, "/dev/ttyUSB2", true)]
public void TestBuildSerialDeviceName(bool isWindows, int portNumber, string expectedDeviceName, bool isUsb)
{
if (OperatingSystem.IsWindows() && isWindows || OperatingSystem.IsLinux() && !isWindows)
Assert.That(SerialDeviceHelper.BuildSerialDeviceName(portNumber, isUsb), Is.EqualTo(expectedDeviceName));
}

[TestCase(true, "COM4",4)]
[TestCase(false, "/dev/tty1",1)]
[TestCase(false, "/dev/ttyUSB2",2)]
public void TestGetSerialDeviceNumber(bool isWindows, string deviceName, int expectedPortNumber)
{
if (OperatingSystem.IsWindows() && isWindows || OperatingSystem.IsLinux() && !isWindows)
Assert.That(SerialDeviceHelper.GetSerialDeviceNumber(deviceName), Is.EqualTo(expectedPortNumber));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0"/>
<PackageReference Include="NUnit" Version="3.13.3"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
<PackageReference Include="NUnit.Analyzers" Version="3.3.0"/>
<PackageReference Include="coverlet.collector" Version="3.1.2"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Wissance.Zerial.Common\Wissance.Zerial.Common.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ namespace Wissance.Zerial.Common.Rs232.Managers
public interface IRs232DeviceManager : IDisposable
{
Task<bool> OpenAsync(Rs232Settings settings);
Task<bool> CloseAsync(int portNumber);
Task<bool> WriteAsync(int portNumber, byte[] data);
Task<byte[]> ReadAsync(int portNumber);
Task<bool> CloseAsync(string deviceName);
Task<bool> WriteAsync(string deviceName, byte[] data);
Task<byte[]> ReadAsync(string deviceName);
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
using System.Collections.Concurrent;
using System.IO.Ports;
using Microsoft.Extensions.Logging;
using Wissance.Zerial.Common.Rs232.Settings;
using Wissance.Zerial.Common.Utils;

namespace Wissance.Zerial.Common.Rs232.Managers
{
public class MultiDeviceRs232Manager : IRs232DeviceManager, IDisposable
public class MultiDeviceRs232Manager : IRs232DeviceManager
{
public MultiDeviceRs232Manager(SerialDataReceivedEventHandler onDataReceivedHandler /*ILoggerFactory loggerFactory*/)

public MultiDeviceRs232Manager(SerialDataReceivedEventHandler onDataReceivedHandler, ILoggerFactory loggerFactory)
{
_onDataReceivedHandler = onDataReceivedHandler;
_logger = loggerFactory.CreateLogger<MultiDeviceRs232Manager>();
}

public void Dispose()
{
_cancellationSource.Cancel();
foreach (KeyValuePair<int,SerialPort> device in _devices)
foreach (KeyValuePair<string,SerialPort> device in _devices)
{
device.Value.Dispose();
}
Expand All @@ -24,16 +28,21 @@ public async Task<bool> OpenAsync(Rs232Settings settings)
{
try
{
// 1. if setting has prepared device name, use it, otherwise we constructing Device name from port number
if (string.IsNullOrEmpty(settings.DeviceName))
return false;
string portName = settings.DeviceName;

SerialPort serialPort = null;
if (_devices.ContainsKey(settings.PortNumber))
serialPort = _devices[settings.PortNumber];
if (_devices.ContainsKey(portName))
serialPort = _devices[portName];

if (serialPort == null)
{
// todo(umv): run timeout parallel to open task
serialPort = new SerialPort()
{
PortName = $"COM{settings.PortNumber}",
PortName = portName,
BaudRate = (int)settings.BaudRate,
StopBits = _stopBitsMapping[settings.StopBits],
DataBits = settings.ByteLength,
Expand All @@ -51,11 +60,11 @@ public async Task<bool> OpenAsync(Rs232Settings settings)
// ?
}

_devices[settings.PortNumber] = serialPort;
_devices[portName] = serialPort;

Task openTask = new Task(async _ =>
{
_devices[settings.PortNumber].Open();
_devices[portName].Open();
},
_cancellationSource.Token);
Task delayTask = Task.Delay(DefaultOperationTimeout); // this task starts automatically
Expand All @@ -81,13 +90,13 @@ public async Task<bool> OpenAsync(Rs232Settings settings)
}
}

public async Task<bool> CloseAsync(int portNumber)
public async Task<bool> CloseAsync(string deviceName)
{
try
{
if (_devices.ContainsKey(portNumber))
if (_devices.ContainsKey(deviceName))
{
_devices[portNumber].Close();
_devices[deviceName].Close();
}
return true;
}
Expand All @@ -98,13 +107,13 @@ public async Task<bool> CloseAsync(int portNumber)
}
}

public async Task<bool> WriteAsync(int portNumber, byte[] data)
public async Task<bool> WriteAsync(string deviceName, byte[] data)
{
try
{
if (_devices.ContainsKey(portNumber))
if (_devices.ContainsKey(deviceName))
{
SerialPort serialDevice = _devices[portNumber];
SerialPort serialDevice = _devices[deviceName];
serialDevice.Write(data, 0, data.Length);
return true;
}
Expand All @@ -118,13 +127,13 @@ public async Task<bool> WriteAsync(int portNumber, byte[] data)
}
}

public async Task<byte[]> ReadAsync(int portNumber)
public async Task<byte[]> ReadAsync(string deviceName)
{
try
{
if (_devices.ContainsKey(portNumber))
if (_devices.ContainsKey(deviceName))
{
SerialPort serialDevice = _devices[portNumber];
SerialPort serialDevice = _devices[deviceName];
byte[] buffer = new byte[4096];
int bytesRead = serialDevice.Read(buffer, 0, buffer.Length);
Array.Resize(ref buffer, bytesRead);
Expand All @@ -142,7 +151,7 @@ public async Task<byte[]> ReadAsync(int portNumber)

private const int DefaultOperationTimeout = 5000;

private readonly IDictionary<int, SerialPort> _devices = new ConcurrentDictionary<int, SerialPort>();
private readonly IDictionary<string, SerialPort> _devices = new ConcurrentDictionary<string, SerialPort>();

private readonly IDictionary<Rs232StopBits, StopBits> _stopBitsMapping = new Dictionary<Rs232StopBits, StopBits>()
{
Expand Down Expand Up @@ -170,5 +179,6 @@ public async Task<byte[]> ReadAsync(int portNumber)

private readonly CancellationTokenSource _cancellationSource = new CancellationTokenSource();
private readonly SerialDataReceivedEventHandler _onDataReceivedHandler;
private ILogger<MultiDeviceRs232Manager> _logger;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public enum Rs232FlowControl

public class Rs232Settings
{
public int PortNumber { get; set; }
public string DeviceName { get; set; }
public Rs232BaudRate BaudRate { get; set; }
public Rs232StopBits StopBits { get; set; }
public Rs232Parity Parity { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
namespace Wissance.Zerial.Common.Utils
{
public static class SerialDeviceHelper
{
/// <summary>
/// Constructs name depends on Operation System.
/// For Windows
/// </summary>
/// <param name="number">
/// In Windows name is COM4, COM5, therefore number is 4, 5
/// In Linux device name is /dev/tty0 for real COM, /dev/ttyUSB0 for USB-COM, therefore number is 0
/// </param>
/// <param name="isUsbDevice">
/// Don't have any sense for Windows, but have for Linux
/// </param>
public static string BuildSerialDeviceName(int number, bool isUsbDevice = true)
{
if (OperatingSystem.IsWindows())
return string.Format(WindowsComPortNamePattern, number);
if (OperatingSystem.IsLinux())
{
string deviceName = string.Format(isUsbDevice ? LinuxUsbDeviceNamePattern : LinuxComDeviceNamePattern, number);
return string.Format(LinuxSerialDeviceNamePattern, deviceName);
}

return null;
}

public static int GetSerialDeviceNumber(string deviceName)
{
try
{
if (OperatingSystem.IsWindows())
{
int portNumber = 0;
bool portParseResult = int.TryParse(deviceName.Substring(WindowsComDeviceNameSign.Length),
out portNumber);
if (portParseResult)
return portNumber;
return -1;
}

if (OperatingSystem.IsLinux())
{
string deviceNumber = "";
// name is /dev/ttyUSB{N}, where N - number
if (deviceName.Contains(LinuxUsbDeviceNameSign))
{
int nameSignStartIndex = deviceName.IndexOf(LinuxUsbDeviceNameSign);
deviceNumber = deviceName.Substring(nameSignStartIndex + LinuxUsbDeviceNameSign.Length);
}
else
{
if (deviceName.Contains(LinuxComDeviceNameSign))
{
int nameSignStartIndex = deviceName.IndexOf(LinuxComDeviceNameSign);
deviceNumber = deviceName.Substring(nameSignStartIndex + LinuxComDeviceNameSign.Length);
}
}

int portNumber = 0;
bool portParseResult = int.TryParse(deviceNumber, out portNumber);
if (portParseResult)
return portNumber;
return -1;

}

return -2;
}
catch (Exception)
{
return -255;
}
}

private const string WindowsComDeviceNameSign = "COM";
private const string LinuxComDeviceNameSign = "tty";
private const string LinuxUsbDeviceNameSign = "ttyUSB";
private const string WindowsComPortNamePattern = $"{WindowsComDeviceNameSign}{{0}}";
private const string LinuxSerialDeviceNamePattern = "/dev/{0}";
private const string LinuxComDeviceNamePattern = $"{LinuxComDeviceNameSign}{{0}}";
private const string LinuxUsbDeviceNamePattern = $"{LinuxUsbDeviceNameSign}{{0}}";
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="System.IO.Ports" Version="7.0.0" />
</ItemGroup>

Expand Down
48 changes: 35 additions & 13 deletions app/Wissance.Zerial/Wissance.Zerial.Desktop/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,48 @@
using System;
using System.IO;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Wissance.Zerial.Desktop.ViewModels;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Wissance.Zerial.Desktop.Views;

namespace Wissance.Zerial.Desktop;

public partial class App : Application
namespace Wissance.Zerial.Desktop
{
public override void Initialize()
public class App : Application
{
AvaloniaXamlLoader.Load(this);
}
static App()
{
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(AppSettingsFile, optional: false, reloadOnChange: true);

public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
Configuration = builder.Build();

ServiceCollection services = new ServiceCollection();
services.AddLogging();

ServiceProvider = services.BuildServiceProvider();
}

public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}

public override void OnFrameworkInitializationCompleted()
{
desktop.MainWindow = new SplashScreenWindow();
//new MainWindow();
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new SplashScreenWindow();
}

base.OnFrameworkInitializationCompleted();
}

public static IServiceProvider ServiceProvider { get; private set; }
public static IConfiguration Configuration { get; private set; }

base.OnFrameworkInitializationCompleted();
private const string AppSettingsFile = "appsettings.json";
}
}
Loading

0 comments on commit 3fa7c91

Please sign in to comment.