36 changed files with 45893 additions and 85 deletions
Binary file not shown.
@ -0,0 +1,28 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<PropertyGroup> |
||||
|
<OutputType>WinExe</OutputType> |
||||
|
<TargetFramework>net9.0-windows</TargetFramework> |
||||
|
<UseWPF>true</UseWPF> |
||||
|
<RootNamespace>Housing</RootNamespace> |
||||
|
<Nullable>enable</Nullable> |
||||
|
<ImplicitUsings>enable</ImplicitUsings> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.3" /> |
||||
|
<PackageReference Include="System.IO.Ports" Version="9.0.10" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<None Update="Database.ini"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</None> |
||||
|
<None Update="Hardware.ini"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</None> |
||||
|
<None Update="InspectionSettings.ini"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</None> |
||||
|
<None Update="init.sql"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</None> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 192 B |
|
After Width: | Height: | Size: 9.3 KiB |
@ -0,0 +1,69 @@ |
|||||
|
using System.IO; |
||||
|
|
||||
|
namespace Housing.Services; |
||||
|
|
||||
|
public sealed class BarcodeScannerSettings |
||||
|
{ |
||||
|
public bool Enabled { get; set; } |
||||
|
public string PortName { get; set; } = "Auto"; |
||||
|
public int BaudRate { get; set; } = 9600; |
||||
|
public int ReadTimeout { get; set; } = 500; |
||||
|
public int IdleCommitMilliseconds { get; set; } = 250; |
||||
|
public bool DtrEnable { get; set; } = true; |
||||
|
public bool RtsEnable { get; set; } = true; |
||||
|
|
||||
|
public static BarcodeScannerSettings Load(string filePath) |
||||
|
{ |
||||
|
if (!File.Exists(filePath)) |
||||
|
{ |
||||
|
throw new FileNotFoundException("Hardware.ini file was not found.", filePath); |
||||
|
} |
||||
|
|
||||
|
var values = IniFile.LoadSection(filePath, "BarcodeScanner"); |
||||
|
return new BarcodeScannerSettings |
||||
|
{ |
||||
|
Enabled = GetBool(values, "Enabled", false), |
||||
|
PortName = GetString(values, "PortName", "Auto"), |
||||
|
BaudRate = GetInt(values, "BaudRate", 9600), |
||||
|
ReadTimeout = GetInt(values, "ReadTimeout", 500), |
||||
|
IdleCommitMilliseconds = GetInt(values, "IdleCommitMilliseconds", 250), |
||||
|
DtrEnable = GetBool(values, "DtrEnable", true), |
||||
|
RtsEnable = GetBool(values, "RtsEnable", true) |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public static bool IsAutoPort(string portName) |
||||
|
{ |
||||
|
return string.IsNullOrWhiteSpace(portName) || |
||||
|
string.Equals(portName.Trim(), "Auto", StringComparison.OrdinalIgnoreCase); |
||||
|
} |
||||
|
|
||||
|
private static string GetString(Dictionary<string, string> values, string key, string defaultValue) |
||||
|
{ |
||||
|
return values.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) |
||||
|
? value.Trim() |
||||
|
: defaultValue; |
||||
|
} |
||||
|
|
||||
|
private static int GetInt(Dictionary<string, string> values, string key, int defaultValue) |
||||
|
{ |
||||
|
return values.TryGetValue(key, out var value) && int.TryParse(value, out var result) |
||||
|
? result |
||||
|
: defaultValue; |
||||
|
} |
||||
|
|
||||
|
private static bool GetBool(Dictionary<string, string> values, string key, bool defaultValue) |
||||
|
{ |
||||
|
if (!values.TryGetValue(key, out var value) || string.IsNullOrWhiteSpace(value)) |
||||
|
{ |
||||
|
return defaultValue; |
||||
|
} |
||||
|
|
||||
|
return value.Trim().ToUpperInvariant() switch |
||||
|
{ |
||||
|
"1" or "TRUE" or "YES" or "ON" => true, |
||||
|
"0" or "FALSE" or "NO" or "OFF" => false, |
||||
|
_ => defaultValue |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,426 @@ |
|||||
|
using System.IO.Ports; |
||||
|
using System.Text; |
||||
|
using System.Text.RegularExpressions; |
||||
|
|
||||
|
namespace Housing.Services; |
||||
|
|
||||
|
public sealed class BarcodeScanReceivedEventArgs : EventArgs |
||||
|
{ |
||||
|
public BarcodeScanReceivedEventArgs(string portName, string text, bool isConfirmedPort) |
||||
|
{ |
||||
|
PortName = portName; |
||||
|
Text = text; |
||||
|
IsConfirmedPort = isConfirmedPort; |
||||
|
} |
||||
|
|
||||
|
public string PortName { get; } |
||||
|
public string Text { get; } |
||||
|
public bool IsConfirmedPort { get; } |
||||
|
} |
||||
|
|
||||
|
public sealed class SerialBarcodeScanner : IDisposable |
||||
|
{ |
||||
|
private readonly BarcodeScannerSettings _settings; |
||||
|
private readonly HashSet<string> _excludedPortNames; |
||||
|
private readonly List<PortSession> _sessions = new(); |
||||
|
private readonly object _sync = new(); |
||||
|
private bool _disposed; |
||||
|
private string? _confirmedPortName; |
||||
|
|
||||
|
public SerialBarcodeScanner(BarcodeScannerSettings settings, IEnumerable<string> excludedPortNames) |
||||
|
{ |
||||
|
_settings = settings; |
||||
|
_excludedPortNames = excludedPortNames |
||||
|
.Where(portName => !string.IsNullOrWhiteSpace(portName)) |
||||
|
.Select(NormalizePortName) |
||||
|
.ToHashSet(StringComparer.OrdinalIgnoreCase); |
||||
|
} |
||||
|
|
||||
|
public event EventHandler<BarcodeScanReceivedEventArgs>? ScanReceived; |
||||
|
|
||||
|
public string? ConfirmedPortName |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
lock (_sync) |
||||
|
{ |
||||
|
return _confirmedPortName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void Start() |
||||
|
{ |
||||
|
ThrowIfDisposed(); |
||||
|
|
||||
|
var candidatePortNames = GetCandidatePortNames(); |
||||
|
if (candidatePortNames.Length == 0) |
||||
|
{ |
||||
|
throw new InvalidOperationException("No available COM ports for the barcode scanner."); |
||||
|
} |
||||
|
|
||||
|
var openErrors = new List<string>(); |
||||
|
foreach (var portName in candidatePortNames) |
||||
|
{ |
||||
|
PortSession? session = null; |
||||
|
try |
||||
|
{ |
||||
|
var port = CreateSerialPort(portName); |
||||
|
session = new PortSession(port, CommitBufferedScan); |
||||
|
|
||||
|
port.DataReceived += SerialPort_DataReceived; |
||||
|
lock (_sync) |
||||
|
{ |
||||
|
_sessions.Add(session); |
||||
|
} |
||||
|
|
||||
|
port.Open(); |
||||
|
port.DiscardInBuffer(); |
||||
|
port.DiscardOutBuffer(); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
if (session is not null) |
||||
|
{ |
||||
|
lock (_sync) |
||||
|
{ |
||||
|
_sessions.Remove(session); |
||||
|
} |
||||
|
|
||||
|
CloseSession(session); |
||||
|
} |
||||
|
|
||||
|
openErrors.Add($"{portName}: {ex.Message}"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int sessionCount; |
||||
|
lock (_sync) |
||||
|
{ |
||||
|
sessionCount = _sessions.Count; |
||||
|
} |
||||
|
|
||||
|
if (sessionCount == 0) |
||||
|
{ |
||||
|
var detail = openErrors.Count == 0 ? string.Empty : $" ({string.Join("; ", openErrors)})"; |
||||
|
throw new InvalidOperationException($"Could not open a barcode scanner COM port.{detail}"); |
||||
|
} |
||||
|
|
||||
|
if (!BarcodeScannerSettings.IsAutoPort(_settings.PortName) || sessionCount == 1) |
||||
|
{ |
||||
|
lock (_sync) |
||||
|
{ |
||||
|
_confirmedPortName = _sessions[0].Port.PortName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void ConfirmPort(string portName) |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(portName)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
List<PortSession> sessionsToClose; |
||||
|
lock (_sync) |
||||
|
{ |
||||
|
if (_disposed) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var normalizedPortName = NormalizePortName(portName); |
||||
|
if (!string.IsNullOrWhiteSpace(_confirmedPortName) && |
||||
|
!string.Equals(_confirmedPortName, normalizedPortName, StringComparison.OrdinalIgnoreCase)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var confirmedSession = _sessions.FirstOrDefault(session => |
||||
|
string.Equals(session.Port.PortName, normalizedPortName, StringComparison.OrdinalIgnoreCase)); |
||||
|
if (confirmedSession is null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
_confirmedPortName = confirmedSession.Port.PortName; |
||||
|
sessionsToClose = _sessions |
||||
|
.Where(session => !ReferenceEquals(session, confirmedSession)) |
||||
|
.ToList(); |
||||
|
|
||||
|
_sessions.RemoveAll(session => !ReferenceEquals(session, confirmedSession)); |
||||
|
} |
||||
|
|
||||
|
foreach (var session in sessionsToClose) |
||||
|
{ |
||||
|
CloseSession(session); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private SerialPort CreateSerialPort(string portName) |
||||
|
{ |
||||
|
return new SerialPort(portName, _settings.BaudRate) |
||||
|
{ |
||||
|
Encoding = Encoding.ASCII, |
||||
|
NewLine = "\r\n", |
||||
|
ReadTimeout = _settings.ReadTimeout, |
||||
|
WriteTimeout = _settings.ReadTimeout, |
||||
|
DtrEnable = _settings.DtrEnable, |
||||
|
RtsEnable = _settings.RtsEnable |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private string[] GetCandidatePortNames() |
||||
|
{ |
||||
|
if (!BarcodeScannerSettings.IsAutoPort(_settings.PortName)) |
||||
|
{ |
||||
|
return new[] { NormalizePortName(_settings.PortName) }; |
||||
|
} |
||||
|
|
||||
|
return SerialPort.GetPortNames() |
||||
|
.Select(NormalizePortName) |
||||
|
.Where(portName => !_excludedPortNames.Contains(portName)) |
||||
|
.OrderBy(GetPortNumber) |
||||
|
.ThenBy(portName => portName, StringComparer.OrdinalIgnoreCase) |
||||
|
.ToArray(); |
||||
|
} |
||||
|
|
||||
|
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) |
||||
|
{ |
||||
|
if (sender is not SerialPort port) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
PortSession? session; |
||||
|
lock (_sync) |
||||
|
{ |
||||
|
if (_disposed) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
session = _sessions.FirstOrDefault(item => ReferenceEquals(item.Port, port)); |
||||
|
} |
||||
|
|
||||
|
if (session is null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
string text; |
||||
|
try |
||||
|
{ |
||||
|
text = port.ReadExisting(); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (string.IsNullOrEmpty(text)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var scans = AppendReceivedText(session, text); |
||||
|
foreach (var scan in scans) |
||||
|
{ |
||||
|
PublishScan(session, scan); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private List<string> AppendReceivedText(PortSession session, string text) |
||||
|
{ |
||||
|
lock (session.Sync) |
||||
|
{ |
||||
|
session.Buffer.Append(text); |
||||
|
var scans = DrainCompleteScans(session.Buffer); |
||||
|
|
||||
|
if (session.Buffer.Length > 0) |
||||
|
{ |
||||
|
var delay = Math.Max(50, _settings.IdleCommitMilliseconds); |
||||
|
session.CommitTimer.Change(delay, Timeout.Infinite); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
session.CommitTimer.Change(Timeout.Infinite, Timeout.Infinite); |
||||
|
} |
||||
|
|
||||
|
return scans; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void CommitBufferedScan(PortSession session) |
||||
|
{ |
||||
|
string scan; |
||||
|
lock (session.Sync) |
||||
|
{ |
||||
|
scan = NormalizeScanText(session.Buffer.ToString()); |
||||
|
session.Buffer.Clear(); |
||||
|
session.CommitTimer.Change(Timeout.Infinite, Timeout.Infinite); |
||||
|
} |
||||
|
|
||||
|
PublishScan(session, scan); |
||||
|
} |
||||
|
|
||||
|
private void PublishScan(PortSession session, string scan) |
||||
|
{ |
||||
|
scan = NormalizeScanText(scan); |
||||
|
if (string.IsNullOrWhiteSpace(scan)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
bool isConfirmedPort; |
||||
|
lock (_sync) |
||||
|
{ |
||||
|
if (_disposed || !_sessions.Contains(session)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
isConfirmedPort = string.Equals( |
||||
|
_confirmedPortName, |
||||
|
session.Port.PortName, |
||||
|
StringComparison.OrdinalIgnoreCase); |
||||
|
} |
||||
|
|
||||
|
ScanReceived?.Invoke(this, new BarcodeScanReceivedEventArgs(session.Port.PortName, scan, isConfirmedPort)); |
||||
|
} |
||||
|
|
||||
|
private static List<string> DrainCompleteScans(StringBuilder buffer) |
||||
|
{ |
||||
|
var scans = new List<string>(); |
||||
|
var text = buffer.ToString(); |
||||
|
var start = 0; |
||||
|
|
||||
|
for (var index = 0; index < text.Length; index++) |
||||
|
{ |
||||
|
if (text[index] != '\r' && text[index] != '\n') |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
var line = NormalizeScanText(text[start..index]); |
||||
|
if (line.Length > 0) |
||||
|
{ |
||||
|
scans.Add(line); |
||||
|
} |
||||
|
|
||||
|
if (text[index] == '\r' && index + 1 < text.Length && text[index + 1] == '\n') |
||||
|
{ |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
start = index + 1; |
||||
|
} |
||||
|
|
||||
|
if (start > 0) |
||||
|
{ |
||||
|
buffer.Clear(); |
||||
|
if (start < text.Length) |
||||
|
{ |
||||
|
buffer.Append(text[start..]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return scans; |
||||
|
} |
||||
|
|
||||
|
private static string NormalizeScanText(string text) |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(text)) |
||||
|
{ |
||||
|
return string.Empty; |
||||
|
} |
||||
|
|
||||
|
var builder = new StringBuilder(text.Length); |
||||
|
foreach (var character in text.Trim()) |
||||
|
{ |
||||
|
if (!char.IsControl(character)) |
||||
|
{ |
||||
|
builder.Append(character); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return builder.ToString().Trim(); |
||||
|
} |
||||
|
|
||||
|
private static string NormalizePortName(string portName) |
||||
|
{ |
||||
|
return portName.Trim().ToUpperInvariant(); |
||||
|
} |
||||
|
|
||||
|
private static int GetPortNumber(string portName) |
||||
|
{ |
||||
|
var match = Regex.Match(portName, @"\d+"); |
||||
|
return match.Success && int.TryParse(match.Value, out var number) |
||||
|
? number |
||||
|
: int.MaxValue; |
||||
|
} |
||||
|
|
||||
|
private void ThrowIfDisposed() |
||||
|
{ |
||||
|
ObjectDisposedException.ThrowIf(_disposed, this); |
||||
|
} |
||||
|
|
||||
|
private void CloseSession(PortSession session) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
session.Port.DataReceived -= SerialPort_DataReceived; |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
// Best effort during shutdown.
|
||||
|
} |
||||
|
|
||||
|
session.Dispose(); |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
List<PortSession> sessionsToClose; |
||||
|
lock (_sync) |
||||
|
{ |
||||
|
if (_disposed) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
_disposed = true; |
||||
|
sessionsToClose = _sessions.ToList(); |
||||
|
_sessions.Clear(); |
||||
|
} |
||||
|
|
||||
|
foreach (var session in sessionsToClose) |
||||
|
{ |
||||
|
CloseSession(session); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private sealed class PortSession : IDisposable |
||||
|
{ |
||||
|
private readonly Action<PortSession> _commitBufferedScan; |
||||
|
|
||||
|
public PortSession(SerialPort port, Action<PortSession> commitBufferedScan) |
||||
|
{ |
||||
|
Port = port; |
||||
|
_commitBufferedScan = commitBufferedScan; |
||||
|
CommitTimer = new Timer(_ => _commitBufferedScan(this), null, Timeout.Infinite, Timeout.Infinite); |
||||
|
} |
||||
|
|
||||
|
public SerialPort Port { get; } |
||||
|
public StringBuilder Buffer { get; } = new(); |
||||
|
public object Sync { get; } = new(); |
||||
|
public Timer CommitTimer { get; } |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
CommitTimer.Dispose(); |
||||
|
Port.Dispose(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Binary file not shown.
File diff suppressed because it is too large
@ -0,0 +1,112 @@ |
|||||
|
-- Run this script against the Housing database before running the app. |
||||
|
-- It creates the login table and login procedures. |
||||
|
|
||||
|
IF OBJECT_ID(N'dbo.Operator_Account', N'U') IS NULL |
||||
|
BEGIN |
||||
|
CREATE TABLE dbo.Operator_Account |
||||
|
( |
||||
|
[Operator] NVARCHAR(10) NOT NULL |
||||
|
CONSTRAINT PK_Operator_Account PRIMARY KEY, |
||||
|
[Password] NVARCHAR(50) NOT NULL, |
||||
|
[CreatedAt] DATETIME2(0) NOT NULL |
||||
|
CONSTRAINT DF_Operator_Account_CreatedAt DEFAULT (SYSDATETIME()), |
||||
|
[UpdatedAt] DATETIME2(0) NULL |
||||
|
); |
||||
|
END; |
||||
|
GO |
||||
|
|
||||
|
IF COL_LENGTH(N'dbo.Operator_Account', N'IsActive') IS NOT NULL |
||||
|
BEGIN |
||||
|
DECLARE @DefaultConstraintName SYSNAME; |
||||
|
|
||||
|
SELECT @DefaultConstraintName = dc.name |
||||
|
FROM sys.default_constraints AS dc |
||||
|
INNER JOIN sys.columns AS c |
||||
|
ON c.default_object_id = dc.object_id |
||||
|
WHERE dc.parent_object_id = OBJECT_ID(N'dbo.Operator_Account', N'U') |
||||
|
AND c.name = N'IsActive'; |
||||
|
|
||||
|
IF @DefaultConstraintName IS NOT NULL |
||||
|
BEGIN |
||||
|
EXEC(N'ALTER TABLE dbo.Operator_Account DROP CONSTRAINT [' + @DefaultConstraintName + N']'); |
||||
|
END; |
||||
|
|
||||
|
ALTER TABLE dbo.Operator_Account DROP COLUMN [IsActive]; |
||||
|
END; |
||||
|
GO |
||||
|
|
||||
|
IF EXISTS (SELECT 1 FROM dbo.Operator_Account WHERE [Operator] = N'su') |
||||
|
BEGIN |
||||
|
UPDATE dbo.Operator_Account |
||||
|
SET |
||||
|
[Password] = N'su', |
||||
|
[UpdatedAt] = SYSDATETIME() |
||||
|
WHERE [Operator] = N'su'; |
||||
|
END |
||||
|
ELSE |
||||
|
BEGIN |
||||
|
INSERT INTO dbo.Operator_Account |
||||
|
( |
||||
|
[Operator], |
||||
|
[Password] |
||||
|
) |
||||
|
VALUES |
||||
|
( |
||||
|
N'su', |
||||
|
N'su' |
||||
|
); |
||||
|
END; |
||||
|
GO |
||||
|
|
||||
|
CREATE OR ALTER PROCEDURE dbo.CheckOperator |
||||
|
@Operator NVARCHAR(10), |
||||
|
@Password NVARCHAR(50) |
||||
|
AS |
||||
|
BEGIN |
||||
|
SET NOCOUNT ON; |
||||
|
|
||||
|
SELECT CAST( |
||||
|
CASE |
||||
|
WHEN EXISTS |
||||
|
( |
||||
|
SELECT 1 |
||||
|
FROM dbo.Operator_Account |
||||
|
WHERE [Operator] = @Operator |
||||
|
AND [Password] = @Password |
||||
|
) |
||||
|
THEN 1 |
||||
|
ELSE 0 |
||||
|
END AS BIT) AS IsValid; |
||||
|
END; |
||||
|
GO |
||||
|
|
||||
|
CREATE OR ALTER PROCEDURE dbo.SaveOperator |
||||
|
@Operator NVARCHAR(10), |
||||
|
@Password NVARCHAR(50) |
||||
|
AS |
||||
|
BEGIN |
||||
|
SET NOCOUNT ON; |
||||
|
|
||||
|
IF EXISTS (SELECT 1 FROM dbo.Operator_Account WHERE [Operator] = @Operator) |
||||
|
BEGIN |
||||
|
UPDATE dbo.Operator_Account |
||||
|
SET |
||||
|
[Password] = @Password, |
||||
|
[UpdatedAt] = SYSDATETIME() |
||||
|
WHERE [Operator] = @Operator; |
||||
|
END |
||||
|
ELSE |
||||
|
BEGIN |
||||
|
INSERT INTO dbo.Operator_Account |
||||
|
( |
||||
|
[Operator], |
||||
|
[Password] |
||||
|
) |
||||
|
VALUES |
||||
|
( |
||||
|
@Operator, |
||||
|
@Password |
||||
|
); |
||||
|
END; |
||||
|
END; |
||||
|
GO |
||||
Binary file not shown.
@ -0,0 +1,12 @@ |
|||||
|
[Database] |
||||
|
IP=127.0.0.1 |
||||
|
Database=Housing |
||||
|
DbId=sa |
||||
|
DbPw=your_password |
||||
|
Encrypt=True |
||||
|
TrustServerCertificate=True |
||||
|
Timeout=5 |
||||
|
|
||||
|
[Login] |
||||
|
Procedure=dbo.CheckOperator |
||||
|
OfflinePreview=true |
||||
@ -0,0 +1,78 @@ |
|||||
|
[Board] |
||||
|
PortName=COM5 |
||||
|
BaudRate=115200 |
||||
|
ReadTimeout=5000 |
||||
|
PreConnectCommand=x00o |
||||
|
ConnectCommand=x00c_001101:owt28006727ea97c7801 |
||||
|
ReadIdCommand=x00c_001101:ow2800326003e |
||||
|
PostReadIdCommand=x00o |
||||
|
CalDefaultCommand=x00c_001001:owt28006727ea97c7801 |
||||
|
EndToken=<end> |
||||
|
DtrEnable=false |
||||
|
RtsEnable=false |
||||
|
|
||||
|
[BarcodeScanner] |
||||
|
Enabled=true |
||||
|
PortName=Auto |
||||
|
BaudRate=9600 |
||||
|
ReadTimeout=500 |
||||
|
IdleCommitMilliseconds=250 |
||||
|
DtrEnable=true |
||||
|
RtsEnable=true |
||||
|
|
||||
|
[StartSignal] |
||||
|
; USB-6501 |
||||
|
Enabled=true |
||||
|
Connection=Ni6501 |
||||
|
PhysicalChannel=Dev1/port0/line0 |
||||
|
ActiveState=High |
||||
|
PollIntervalMilliseconds=50 |
||||
|
TimeoutMilliseconds=30000 |
||||
|
PostSignalDelayMilliseconds=2000 |
||||
|
RequireInactiveBeforeStart=true |
||||
|
|
||||
|
[Equipment] |
||||
|
; V 출력: Keysight 34465A DMM 값 |
||||
|
; A 출력: Keysight E36233A Power Supply CH1 Current 값 |
||||
|
; USB 장비는 Keysight Connection Expert 또는 NI MAX에서 보이는 VISA 주소를 Resource |
||||
|
Timeout=5000 |
||||
|
SettleMilliseconds=300 |
||||
|
PreBoardCommand=VOLT 5, (@2);OUTP ON, (@2) |
||||
|
PreBoardDelayMilliseconds=2000 |
||||
|
LogoutCommand=OUTP OFF, (@1);OUTP OFF, (@2) |
||||
|
|
||||
|
; 34465A DMM |
||||
|
VoltageConnection=LAN |
||||
|
VoltageResource= |
||||
|
VoltageIdnMatch=34465A |
||||
|
VoltageHost=192.168.200.3 |
||||
|
VoltagePort=5025 |
||||
|
VoltageSetupCommand= |
||||
|
VoltageReadCommand=MEAS:VOLT:DC? |
||||
|
|
||||
|
; E36233A Power Supply |
||||
|
CurrentConnection=LAN |
||||
|
CurrentResource= |
||||
|
CurrentIdnMatch=E36233A |
||||
|
; Change this to the E36233A LAN IP if the instrument uses a different address. |
||||
|
CurrentHost=192.168.200.111 |
||||
|
CurrentPort=5025 |
||||
|
CurrentPortName= |
||||
|
CurrentBaudRate=9600 |
||||
|
CurrentTerminator=LF |
||||
|
CurrentSetupCommand=OUTP ON, (@1) |
||||
|
CurrentCleanupCommand=OUTP OFF, (@1) |
||||
|
CurrentReadCommand=MEAS:CURR? (@1) |
||||
|
|
||||
|
; COM 포트로 잡히는 장비 예시: |
||||
|
; VoltageConnection=Serial |
||||
|
; VoltagePortName=Auto |
||||
|
; VoltageBaudRate=115200 |
||||
|
|
||||
|
; LAN 장비 예시: |
||||
|
; VoltageConnection=Tcp |
||||
|
; VoltageHost=192.168.0.10 |
||||
|
; VoltagePort=5025 |
||||
|
|
||||
|
; E36233A 파워서플라이에서 CH1 전압까지 읽고 싶을 때 예시: |
||||
|
; VoltageReadCommand=MEAS:VOLT? CH1 |
||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,5 @@ |
|||||
|
[Judgement] |
||||
|
VMin=0.00 |
||||
|
VMax=9.99 |
||||
|
AMin=0.00 |
||||
|
AMax=9.99 |
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,112 @@ |
|||||
|
-- Run this script against the Housing database before running the app. |
||||
|
-- It creates the login table and login procedures. |
||||
|
|
||||
|
IF OBJECT_ID(N'dbo.Operator_Account', N'U') IS NULL |
||||
|
BEGIN |
||||
|
CREATE TABLE dbo.Operator_Account |
||||
|
( |
||||
|
[Operator] NVARCHAR(10) NOT NULL |
||||
|
CONSTRAINT PK_Operator_Account PRIMARY KEY, |
||||
|
[Password] NVARCHAR(50) NOT NULL, |
||||
|
[CreatedAt] DATETIME2(0) NOT NULL |
||||
|
CONSTRAINT DF_Operator_Account_CreatedAt DEFAULT (SYSDATETIME()), |
||||
|
[UpdatedAt] DATETIME2(0) NULL |
||||
|
); |
||||
|
END; |
||||
|
GO |
||||
|
|
||||
|
IF COL_LENGTH(N'dbo.Operator_Account', N'IsActive') IS NOT NULL |
||||
|
BEGIN |
||||
|
DECLARE @DefaultConstraintName SYSNAME; |
||||
|
|
||||
|
SELECT @DefaultConstraintName = dc.name |
||||
|
FROM sys.default_constraints AS dc |
||||
|
INNER JOIN sys.columns AS c |
||||
|
ON c.default_object_id = dc.object_id |
||||
|
WHERE dc.parent_object_id = OBJECT_ID(N'dbo.Operator_Account', N'U') |
||||
|
AND c.name = N'IsActive'; |
||||
|
|
||||
|
IF @DefaultConstraintName IS NOT NULL |
||||
|
BEGIN |
||||
|
EXEC(N'ALTER TABLE dbo.Operator_Account DROP CONSTRAINT [' + @DefaultConstraintName + N']'); |
||||
|
END; |
||||
|
|
||||
|
ALTER TABLE dbo.Operator_Account DROP COLUMN [IsActive]; |
||||
|
END; |
||||
|
GO |
||||
|
|
||||
|
IF EXISTS (SELECT 1 FROM dbo.Operator_Account WHERE [Operator] = N'su') |
||||
|
BEGIN |
||||
|
UPDATE dbo.Operator_Account |
||||
|
SET |
||||
|
[Password] = N'su', |
||||
|
[UpdatedAt] = SYSDATETIME() |
||||
|
WHERE [Operator] = N'su'; |
||||
|
END |
||||
|
ELSE |
||||
|
BEGIN |
||||
|
INSERT INTO dbo.Operator_Account |
||||
|
( |
||||
|
[Operator], |
||||
|
[Password] |
||||
|
) |
||||
|
VALUES |
||||
|
( |
||||
|
N'su', |
||||
|
N'su' |
||||
|
); |
||||
|
END; |
||||
|
GO |
||||
|
|
||||
|
CREATE OR ALTER PROCEDURE dbo.CheckOperator |
||||
|
@Operator NVARCHAR(10), |
||||
|
@Password NVARCHAR(50) |
||||
|
AS |
||||
|
BEGIN |
||||
|
SET NOCOUNT ON; |
||||
|
|
||||
|
SELECT CAST( |
||||
|
CASE |
||||
|
WHEN EXISTS |
||||
|
( |
||||
|
SELECT 1 |
||||
|
FROM dbo.Operator_Account |
||||
|
WHERE [Operator] = @Operator |
||||
|
AND [Password] = @Password |
||||
|
) |
||||
|
THEN 1 |
||||
|
ELSE 0 |
||||
|
END AS BIT) AS IsValid; |
||||
|
END; |
||||
|
GO |
||||
|
|
||||
|
CREATE OR ALTER PROCEDURE dbo.SaveOperator |
||||
|
@Operator NVARCHAR(10), |
||||
|
@Password NVARCHAR(50) |
||||
|
AS |
||||
|
BEGIN |
||||
|
SET NOCOUNT ON; |
||||
|
|
||||
|
IF EXISTS (SELECT 1 FROM dbo.Operator_Account WHERE [Operator] = @Operator) |
||||
|
BEGIN |
||||
|
UPDATE dbo.Operator_Account |
||||
|
SET |
||||
|
[Password] = @Password, |
||||
|
[UpdatedAt] = SYSDATETIME() |
||||
|
WHERE [Operator] = @Operator; |
||||
|
END |
||||
|
ELSE |
||||
|
BEGIN |
||||
|
INSERT INTO dbo.Operator_Account |
||||
|
( |
||||
|
[Operator], |
||||
|
[Password] |
||||
|
) |
||||
|
VALUES |
||||
|
( |
||||
|
@Operator, |
||||
|
@Password |
||||
|
); |
||||
|
END; |
||||
|
END; |
||||
|
GO |
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue