Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ riderModule.iml
/_ReSharper.Caches/
/.idea/
*.sln.DotSettings.user
/.vs/
22 changes: 19 additions & 3 deletions PTI.Rs232Validator.Desktop/Views/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
xmlns:util="clr-namespace:PTI.Rs232Validator.Desktop.Utility"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="650"
Width="800"
Width="975"
SnapsToDevicePixels="True"
Icon="../icon.ico"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
Expand All @@ -17,6 +17,7 @@
<ResourceDictionary>
<system:String x:Key="SelectPortText">Select Port</system:String>
<system:String x:Key="StartPollingText">Start Polling</system:String>
<system:String x:Key="ResetText">Reset</system:String>
<system:String x:Key="StopPollingText">Stop Polling</system:String>
<system:String x:Key="PauseText">Pause</system:String>
<system:String x:Key="ResumeText">Resume</system:String>
Expand Down Expand Up @@ -50,9 +51,11 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
Expand Down Expand Up @@ -102,12 +105,25 @@
Content="Barcode Detection"
IsChecked="{Binding IsBarcodeDetectionEnabled, Mode=TwoWay, IsAsync=True}" />
</StatusBarItem>

<StatusBarItem Grid.Column="6">
<CheckBox x:Name="AutoReconnectCheckbox"
Content="Auto-Reconnect"
IsChecked="{Binding Reconnect, Mode=TwoWay, IsAsync=True}" />
</StatusBarItem>

<StatusBarItem Grid.Column="8">
<Button x:Name="Reset"
Width="100" Height="25"
Content="{StaticResource ResetText}"
Click="ResetButton_Click" />
</StatusBarItem>

<StatusBarItem Grid.Column="7">
<StatusBarItem Grid.Column="9">
<TextBlock>State:</TextBlock>
</StatusBarItem>

<StatusBarItem Grid.Column="8">
<StatusBarItem Grid.Column="10">
<TextBlock Text="{Binding State, Mode=OneWay, IsAsync=True}" />
</StatusBarItem>
</StatusBar>
Expand Down
74 changes: 72 additions & 2 deletions PTI.Rs232Validator.Desktop/Views/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System;
using System.ComponentModel;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
Expand All @@ -26,6 +28,8 @@ public partial class MainWindow : INotifyPropertyChanged

private BillValidator? _billValidator;
private bool _isPolling;
private bool _reconnect;
private CancellationTokenSource? _reconnectCts;

public MainWindow()
{
Expand Down Expand Up @@ -80,6 +84,16 @@ public bool IsPolling
}
}

public bool Reconnect
{
get => _reconnect;
set
{
_reconnect = value;
NotifyPropertyChanged(nameof(Reconnect));
}
}

private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Expand Down Expand Up @@ -207,11 +221,67 @@ private void PollButton_Click(object sender, RoutedEventArgs e)
}
}

private void BillValidator_OnConnectionLost(object? sender, EventArgs e)
private async void ResetButton_Click(object sender, RoutedEventArgs e)
{
var billValidator = GetBillValidatorOrShowMessage();
if (billValidator is null)
{
return;
}

billValidator.StopPollingLoop();
await billValidator.ResetDevice();
}

private async void BillValidator_OnConnectionLost(object? sender, EventArgs e)
{
LogInfo("Lost connection to the acceptor.");
_billValidator?.StopPollingLoop();
IsPolling = false;


if (!Reconnect || _billValidator is null)
{
IsPolling = false;
return;
}

_reconnectCts = new CancellationTokenSource();
var token = _reconnectCts.Token;

try
{
await Task.Run(async () =>
{
while (!token.IsCancellationRequested && Reconnect && IsPolling)
{
LogInfo("Attempting to reconnect...");
if (_billValidator.StartPollingLoop())
{
DoOnUiThread(() =>
{
LogInfo("Reconnected successfully.");
});
break;
}

await Task.Delay(2000, token); // Wait 2 seconds before retrying
}

if (!Reconnect || _billValidator is null)
{
IsPolling = false;
}
}, token);
}
catch (TaskCanceledException)
{
LogInfo("Reconnection cancelled.");
}
finally
{
_reconnectCts?.Dispose();
_reconnectCts = null;
}
}

/// <summary>
Expand Down
35 changes: 35 additions & 0 deletions PTI.Rs232Validator.Installer/PTI.Rs232Validator.Installer.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
<NoWarn>NU1701;NU1702;IL3000</NoWarn>
</PropertyGroup>

<!-- <Target Name="PostBuild" AfterTargets="PostBuildEvent">-->
<!-- <Exec Command="cd .\&#xD;&#xA;set ide=true&#xD;&#xA;dotnet &quot;$(TargetPath)&quot;" />-->
<!-- </Target>-->

<ItemGroup>
<PackageReference Include="WixSharp.Core" Version="2.1.3">
<Aliases></Aliases>
</PackageReference>
</ItemGroup>

<ItemGroup>
<None Update="icon.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="app.dialog_banner.bmp">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
90 changes: 90 additions & 0 deletions PTI.Rs232Validator.Installer/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using WixSharp;
using File = WixSharp.File;

[assembly: InternalsVisibleTo(assemblyName: "PTI.Rs232Validator.Installer.aot")] // assembly name + '.aot suffix

internal class Program
{
private static void Main(string[] args)
{
const string projectName = "RS232 Validator";
var msiGuid = new Guid("C7154179-9B82-4016-AF33-E480F3E0F276");

if (!TryGetStringArgument(args, "-BuildDir", out var buildDirectoryPath)
|| !TryGetStringArgument(args, "-Binary", out var guiBinaryPath))
{
throw new ArgumentException("Required arguments not provided. Usage: -BuildDir <path> -Binary <path>");
}

var guiPublishDir = Path.GetDirectoryName(guiBinaryPath);
if (guiPublishDir is null)
{
throw new InvalidOperationException("Could not determine GUI publish directory.");
}

var installerDirectoryPath = AppDomain.CurrentDomain.BaseDirectory;
var bannerPath = Path.Combine(installerDirectoryPath, "app.dialog_banner.bmp");
var iconFilePath = Path.Combine(installerDirectoryPath, "icon.ico");

var guiFileVersionInfo = FileVersionInfo.GetVersionInfo(guiBinaryPath);
if (guiFileVersionInfo.FileVersion is null)
{
throw new InvalidOperationException("Could not get file version info for GUI binary.");
}

var guiBinaryName = Path.GetFileName(guiBinaryPath);

var project =
new ManagedProject(projectName,
new Dir($@"%ProgramFiles%\Pyramid Technologies Inc\{projectName}",
new File(guiBinaryPath, new FileShortcut("RS232 Validator", "INSTALLDIR")),
new Files(Path.Combine(guiPublishDir, "*.dll"))),
new Dir("%ProgramMenu%",
new ExeFileShortcut(projectName, $@"[INSTALLDIR]\{guiBinaryName}", "")
{
WorkingDirectory = "[INSTALLDIR]"
}
),
new Dir("%Desktop%",
new ExeFileShortcut(projectName, $@"[INSTALLDIR]\{guiBinaryName}", "")
{
WorkingDirectory = "[INSTALLDIR]"
}
))
{
SourceBaseDir = guiPublishDir,
ControlPanelInfo =
{
Comments = "PTI RS232 Validator Application",
Manufacturer = "Pyramid Technologies Inc",
ProductIcon = iconFilePath,
},
GUID = msiGuid,
Version = new Version(guiFileVersionInfo.FileVersion),
MajorUpgradeStrategy = MajorUpgradeStrategy.Default,
BannerImage = bannerPath
};

project.BuildMsi(Path.Combine(buildDirectoryPath, "PTI.Rs232Validator.Installer.msi"));
}

private static bool TryGetStringArgument(string[] args, string argName, out string argValue)
{
argValue = string.Empty;
var argIndex = Array.IndexOf(args, argName);
if (argIndex == -1)
{
return false;
}

if (argIndex + 1 >= args.Length)
{
return false;
}

argValue = args[argIndex + 1];
return true;
}
}
Binary file not shown.
Binary file added PTI.Rs232Validator.Installer/icon.ico
Binary file not shown.
55 changes: 55 additions & 0 deletions PTI.Rs232Validator/BillValidators/BillValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,61 @@ internal async Task<TResponseMessage> SendNonPollMessageAsync<TResponseMessage>(
});
}

public async Task<bool> ResetDevice()
{
var eventWaitHandle = new ManualResetEvent(false);

var messageCallback = new Func<bool>(() =>
{
var requestMessage = new ResetRequestMessage(!_lastAck);
var requestPayload = requestMessage.Payload.ToArray();

_serialProvider.Write(requestPayload);

_logger.LogTrace("Sent data to acceptor: {0}", requestMessage.Payload.ConvertToHexString(true, false));
_logger.LogInfo("Reset command sent to device.");
return true;
});

bool isPolling;
lock (_mutex)
{
isPolling = _isPolling;
}

if (isPolling)
{
EnqueueMessageCallback(messageCallback);
return await Task.Run(() =>
{
eventWaitHandle.WaitOne();
return true;
});
}

return await Task.Run(() =>
{
if (!TryOpenPort())
{
return true;
}

if (!CheckForDevice())
{
ClosePort();
return true;
}

while (!messageCallback.Invoke())
{
Thread.Sleep(Configuration.PollingPeriod);
}

ClosePort();
return true;
});
}

private void EnqueueMessageCallback(Func<bool> messageCallback)
{
lock (_mutex)
Expand Down
35 changes: 35 additions & 0 deletions PTI.Rs232Validator/Messages/Requests/ResetRequestMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace PTI.Rs232Validator.Messages.Requests;

public class ResetRequestMessage : Rs232RequestMessage
{

public ResetRequestMessage(bool ack) : base(BuildPayload(ack))
{

}

public override string ToString()
{
return base.ToString() + $" | Reset";
}

private static ReadOnlyCollection<byte> BuildPayload(bool ack)
{
var payload = new List<byte>
{
Stx,
0x08,
(byte)(0x60 | (ack ? 0x01 : 0x00)),
0x7F,
0x7F,
0x7F,
Etx,
0
};

return payload.AsReadOnly();
}
}
Loading