7 Commits

53 changed files with 2959 additions and 66 deletions

View File

@ -118,7 +118,7 @@ dotnet_diagnostic.CA2254.severity = none # CA2254: The logging message template
dotnet_diagnostic.IDE0001.severity = warning # IDE0001: Simplify name
dotnet_diagnostic.IDE0002.severity = warning # Simplify (member access) - System.Version.Equals("1", "2"); Version.Equals("1", "2");
dotnet_diagnostic.IDE0004.severity = warning # IDE0004: Cast is redundant.
dotnet_diagnostic.IDE0005.severity = warning # Using directive is unnecessary
dotnet_diagnostic.IDE0005.severity = none # Using directive is unnecessary
dotnet_diagnostic.IDE0010.severity = none # Add missing cases to switch statement (IDE0010)
dotnet_diagnostic.IDE0028.severity = error # IDE0028: Collection initialization can be simplified
dotnet_diagnostic.IDE0031.severity = warning # Use null propagation (IDE0031)

23
.vscode/.http vendored Normal file
View File

@ -0,0 +1,23 @@
###
GET https://eaf-dev.mes.infineon.com/bob/v1/sync/
###
POST https://eaf-dev.mes.infineon.com/bob/v1/sync/
Accept: application/json
{
"id": "110738",
"machineId": "30ef1b54e075c5370ce74eea2042cb750be659696b170f8758d219a8f9a88e10",
"page": "time",
"site": "MES",
"time": "1744339499677",
"username": "phares",
"value": "3"
}
###
https://eaf-dev.mes.infineon.com/api/v1/ado/

2
.vscode/launch.json vendored
View File

@ -8,7 +8,7 @@
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"preLaunchTask": "Build",
"program": "${workspaceFolder}/bin/Debug/net8.0/win-x64/File-Watcher.dll",
"args": [
"s"

View File

@ -33,6 +33,7 @@
"Kofax",
"linc",
"Linc",
"Modbus",
"NOPAUSE",
"NSFX",
"OBJE",
@ -42,6 +43,7 @@
"PDSF",
"pged",
"Phares",
"Pinnable",
"Rijndael",
"Serilog",
"SUBM",

18
.vscode/tasks.json vendored
View File

@ -7,8 +7,6 @@
"type": "process",
"args": [
"user-secrets",
"-p",
"${workspaceFolder}/File-Watcher.csproj",
"init"
],
"problemMatcher": "$msCompile"
@ -19,8 +17,6 @@
"type": "process",
"args": [
"user-secrets",
"-p",
"${workspaceFolder}/File-Watcher.csproj",
"set",
"_UserSecretsId",
"6516d19d6569"
@ -43,19 +39,16 @@
"problemMatcher": "$msCompile"
},
{
"label": "build",
"label": "Build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/File-Watcher.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
"build"
],
"problemMatcher": "$msCompile"
},
{
"label": "Format-Whitespaces",
"label": "Format Whitespaces",
"command": "dotnet",
"type": "process",
"args": [
@ -74,10 +67,7 @@
"win-x64",
"-c",
"Release",
"-p:PublishAot=true",
"${workspaceFolder}/File-Watcher.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
"-p:PublishAot=true"
],
"problemMatcher": "$msCompile"
},

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Worker">
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="CliWrap" Version="3.8.2" />
<PackageReference Include="DiscUtils.Iso9660" Version="0.16.13" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.14" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.16" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.1" />
@ -20,13 +20,20 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="8.0.1" />
<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.7.0" />
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.14" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.20" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
<PackageReference Include="System.Drawing.Common" Version="8.0.14" />
<PackageReference Include="System.Drawing.Common" Version="8.0.16" />
<PackageReference Include="System.IO.Ports" Version="8.0.0" />
<PackageReference Include="System.Text.Json" Version="9.0.3" />
<PackageReference Include="Phares.AA.Shared" Version="8.0.114.12235" />
<PackageReference Include="Phares.AA.Metadata" Version="8.0.114.12235" />
<PackageReference Include="System.Text.Json" Version="9.0.5" />
<PackageReference Include="Phares.Shared" Version="8.0.118.14751" />
<PackageReference Include="Phares.Metadata" Version="8.0.118.14751" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Nancy.Owin" Version="2.0.0" />
<PackageReference Include="Microsoft.Owin" Version="4.2.2" />
<PackageReference Include="Microsoft.Owin.Cors" Version="4.2.2" />
<PackageReference Include="Microsoft.Owin.Hosting" Version="4.2.2" />
<PackageReference Include="Microsoft.Owin.Host.HttpListener" Version="4.2.2" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
</ItemGroup>
</Project>

12
Helpers/DAQmx/CSVTime.cs Normal file
View File

@ -0,0 +1,12 @@
namespace Helpers.DAQmx;
#pragma warning disable IDE1006 // Naming Styles
#pragma warning disable IDE0044 // Add readonly modifier
#pragma warning disable IDE0051 // Remove unused private members
#pragma warning disable CS0169 // Field is never assigned to, and will always have its default value
public struct CSVTime
{
private ulong lsb;
private long msb;
}

View File

@ -0,0 +1,17 @@
using System.Runtime.InteropServices;
namespace Helpers.DAQmx;
#pragma warning disable IDE0044 // Add readonly modifier
#pragma warning disable IDE0051 // Remove unused private members
#pragma warning disable IDE1006 // Naming Styles
#pragma warning disable CS0169 // Field is never assigned to, and will always have its default value
[StructLayout(LayoutKind.Explicit)]
public struct CVIAbsoluteTime
{
[FieldOffset(0)]
private CSVTime cviTime;
[FieldOffset(0)]
private uint[] u32Data;
}

13
Helpers/DAQmx/DAQmx.cs Normal file
View File

@ -0,0 +1,13 @@
using System.Text;
namespace Helpers.DAQmx;
public static class DAQmx
{
public static string GetErrorString(int errorCode)
{
StringBuilder errorString = new(256);
_ = Interop.DAQmxGetErrorString(errorCode, errorString, (uint)(errorString.Capacity + 1));
return errorString.ToString();
}
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxActiveEdge
{
Falling = 10171, // 0x000027BB
Rising = 10280, // 0x00002828
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxDataLayout
{
GroupByChannel,
GroupByScanNumber,
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxDigitalPatternTriggerWhen
{
PatternDoesNotMatch = 10253, // 0x0000280D
PatternMatches = 10254, // 0x0000280E
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxEdge
{
Falling = 10171, // 0x000027BB
Rising = 10280, // 0x00002828
}

View File

@ -0,0 +1,14 @@
namespace Helpers.DAQmx;
public class DAQmxException : Exception
{
public DAQmxException(string message)
: base(message)
{
}
public DAQmxException(int errorCode, string message)
: base(errorCode.ToString() + " - " + message + " (" + DAQmx.GetErrorString(errorCode) + ")")
{
}
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxFillMode
{
GroupByChannel,
GroupByScanNumber,
}

View File

@ -0,0 +1,10 @@
namespace Helpers.DAQmx;
public enum DAQmxInputTerminalConfiguration
{
Default = -1, // 0xFFFFFFFF
NonReferencedSingleEnded = 10078, // 0x0000275E
ReferencedSingleEnded = 10083, // 0x00002763
Differential = 10106, // 0x0000277A
Pseudodifferential = 12529, // 0x000030F1
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxLevel
{
High = 10192, // 0x000027D0
Low = 10214, // 0x000027E6
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxLineGrouping
{
OneChannelForEachLine,
OneChannelForAllLines,
}

View File

@ -0,0 +1,8 @@
namespace Helpers.DAQmx;
public enum DAQmxLoggingMode
{
Off = 10231, // 0x000027F7
LogAndRead = 15842, // 0x00003DE2
Log = 15844, // 0x00003DE4
}

View File

@ -0,0 +1,9 @@
namespace Helpers.DAQmx;
public enum DAQmxLoggingTDMSOperation
{
Open = 10437, // 0x000028C5
OpenOrCreate = 15846, // 0x00003DE6
CreateOrReplace = 15847, // 0x00003DE7
Create = 15848, // 0x00003DE8
}

View File

@ -0,0 +1,5 @@
namespace Helpers.DAQmx;
public class DAQmxMemoryException(string message) : Exception(message)
{
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxPolarity
{
ActiveHigh = 10095, // 0x0000276F
ActiveLow = 10096, // 0x00002770
}

View File

@ -0,0 +1,8 @@
namespace Helpers.DAQmx;
public enum DAQmxSampleMode
{
ContinuousSamples = 10123, // 0x0000278B
FiniteSamples = 10178, // 0x000027C2
HardwareTimedSinglePoint = 12522, // 0x000030EA
}

348
Helpers/DAQmx/DAQmxTask.cs Normal file
View File

@ -0,0 +1,348 @@
namespace Helpers.DAQmx;
#pragma warning disable IDE1006 // Naming Styles
#pragma warning disable IDE0044 // Add readonly modifier
#pragma warning disable IDE0051 // Remove unused private members
#pragma warning disable CS0169 // Field is never assigned to, and will always have its default value
public class DAQmxTask
{
private IntPtr taskHandle;
private DAQmxTask()
{
}
public double DT { get; private set; }
public int Channels { get; private set; }
public ulong TotalSamplesRead { get; private set; }
public DateTime TaskStartedUtc { get; private set; }
public ulong TotalSamplesWrite { get; private set; }
public ulong TotalSamplesPerChanRead { get; private set; }
public ulong TotalSamplesPerChanWrite { get; private set; }
public static DAQmxTask Create(string taskName)
{
DAQmxTask result;
IntPtr taskHandle;
int task = Interop.DAQmxCreateTask(taskName, out taskHandle);
if (task < 0)
throw new DAQmxException(task, "Could not create Task");
result = new() { taskHandle = taskHandle, Channels = 0 };
return result;
}
public void ConfigureLoggingTechnicalDataManagementStreaming(string filePath, DAQmxLoggingMode loggingMode, string groupName, DAQmxLoggingTDMSOperation operation)
{
int errorCode = Interop.DAQmxConfigureLogging(taskHandle, filePath, (int)loggingMode, groupName, (int)operation);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not configure technical data management streaming logging");
}
public void CreateAnalogInputVoltageChannel(string physicalChannel, string nameToAssignToChannel, DAQmxInputTerminalConfiguration terminalConfig, double minVal, double maxVal, DAQmxUnits units, string customScaleName)
{
int analogInputVoltageChan = Interop.DAQmxCreateAIVoltageChan(taskHandle, physicalChannel, nameToAssignToChannel, (int)terminalConfig, minVal, maxVal, (int)units, customScaleName);
if (analogInputVoltageChan < 0)
throw new DAQmxException(analogInputVoltageChan, "Could not create analog input voltage channel");
++Channels;
}
public void CreateAnalogOutputVoltageChan(string physicalChannel, string nameToAssignToChannel, double minVal, double maxVal, DAQmxUnits units, string customScaleName)
{
int analogOutputVoltageChan = Interop.DAQmxCreateAOVoltageChan(taskHandle, physicalChannel, nameToAssignToChannel, minVal, maxVal, (int)units, customScaleName);
if (analogOutputVoltageChan < 0)
throw new DAQmxException(analogOutputVoltageChan, "Could not create analog output voltage channel");
++Channels;
}
public void CreateDigitalOutputChanel(string lines, string nameToAssignToLines, DAQmxLineGrouping lineGrouping)
{
int doChan = Interop.DAQmxCreateDOChan(taskHandle, lines, nameToAssignToLines, (int)lineGrouping);
if (doChan < 0)
throw new DAQmxException(doChan, "Could not create digital output channel");
++Channels;
}
#if unsafe
public unsafe void ReadAnalogF64(int numSamplesPerChan, double timeout, DAQmxFillMode fillMode, Span<double> data)
{
int arraySizeInSamples = numSamplesPerChan * Channels;
if (data.Length < arraySizeInSamples)
throw new DAQmxMemoryException("Span length too short. (Span length: " + data.Length.ToString() + ", required length: " + arraySizeInSamples.ToString() + ")");
fixed (double* readArray = &data.GetPinnableReference())
{
IntPtr samplesPerChanRead;
int errorCode = Interop.DAQmxReadAnalogF64(taskHandle, numSamplesPerChan, timeout, (int)fillMode, readArray, (uint)arraySizeInSamples, out samplesPerChanRead, IntPtr.Zero);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not read samples");
int int32 = samplesPerChanRead.ToInt32();
if (int32 != numSamplesPerChan)
throw new DAQmxException("Could not read requested number of samples");
TotalSamplesPerChanRead += (ulong)int32;
TotalSamplesRead += (ulong)arraySizeInSamples;
}
}
#endif
public double ReadAnalogScalarF64(double timeout)
{
double result;
int errorCode = Interop.DAQmxReadAnalogScalarF64(taskHandle, timeout, out result, IntPtr.Zero);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not read samples");
++TotalSamplesRead;
return result;
}
#if unsafe
public double ReadAnalogF64(double timeout)
{
double result = DAQmxReadAnalogF64(timeout);
++TotalSamplesRead;
return result;
}
#endif
#if unsafe
private unsafe double DAQmxReadAnalogF64(double timeout)
{
double results;
int numSamplesPerChan = 1;
uint arraySizeInSamples = 1;
IntPtr samplesPerChanRead = IntPtr.Zero;
double* readArray = stackalloc double[1];
int fillMode = (int)DAQmxFillMode.GroupByChannel;
int errorCode = Interop.DAQmxReadAnalogF64(taskHandle,
numSamplesPerChan,
timeout,
fillMode,
readArray,
arraySizeInSamples,
out samplesPerChanRead,
IntPtr.Zero);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not read samples");
results = *readArray;
return results;
}
#endif
public void Start()
{
int errorCode = Interop.DAQmxStartTask(taskHandle);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not start Task");
TaskStartedUtc = DateTime.UtcNow;
}
public void Stop()
{
int errorCode = Interop.DAQmxStopTask(taskHandle);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not stop Task");
}
public void Clear()
{
int errorCode = Interop.DAQmxClearTask(taskHandle);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not clear Task");
}
public void CfgSampleClkTiming(string source, double rate, DAQmxActiveEdge activeEdge, DAQmxSampleMode sampleMode, ulong samplesPerChan)
{
int errorCode = Interop.DAQmxCfgSampClkTiming(taskHandle, source, rate, (int)activeEdge, (int)sampleMode, samplesPerChan);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgSampleClkTiming failed.");
DT = 1.0 / SampleClockRate;
}
public void DAQmxCfgHandshakingTiming(DAQmxSampleMode sampleMode, ulong samplesPerChan)
{
int errorCode = Interop.DAQmxCfgHandshakingTiming(taskHandle, (int)sampleMode, samplesPerChan);
if (errorCode < 0)
throw new DAQmxException(errorCode, "DAQmxCfgHandshakingTiming failed.");
}
public void DAQmxCfgBurstHandshakingTimingImportClock(DAQmxSampleMode sampleMode, ulong samplesPerChan, double sampleClkRate, string sampleClkSrc, DAQmxPolarity sampleClkActiveEdge, DAQmxLevel pauseWhen, DAQmxPolarity readyEventActiveLevel)
{
int errorCode = Interop.DAQmxCfgBurstHandshakingTimingImportClock(taskHandle, (int)sampleMode, samplesPerChan, sampleClkRate, sampleClkSrc, (int)sampleClkActiveEdge, (int)pauseWhen, (int)readyEventActiveLevel);
if (errorCode < 0)
throw new DAQmxException(errorCode, "DAQmxCfgBurstHandshakingTimingImportClock failed.");
}
public void DAQmxCfgBurstHandshakingTimingExportClock(DAQmxSampleMode sampleMode, ulong samplesPerChan, double sampleClkRate, string sampleClkOutputTerm, DAQmxPolarity sampleClkPulsePolarity, DAQmxLevel pauseWhen, DAQmxPolarity readyEventActiveLevel)
{
int errorCode = Interop.DAQmxCfgBurstHandshakingTimingExportClock(taskHandle, (int)sampleMode, samplesPerChan, sampleClkRate, sampleClkOutputTerm, (int)sampleClkPulsePolarity, (int)pauseWhen, (int)readyEventActiveLevel);
if (errorCode < 0)
throw new DAQmxException(errorCode, "DAQmxCfgBurstHandshakingTimingExportClock failed.");
}
public void DAQmxCfgChangeDetectionTiming(string risingEdgeChan, string fallingEdgeChan, DAQmxSampleMode sampleMode, ulong samplesPerChan)
{
int errorCode = Interop.DAQmxCfgChangeDetectionTiming(taskHandle, risingEdgeChan, fallingEdgeChan, (int)sampleMode, samplesPerChan);
if (errorCode < 0)
throw new DAQmxException(errorCode, "DAQmxCfgChangeDetectionTiming failed.");
}
public void DAQmxCfgImplicitTiming(DAQmxSampleMode sampleMode, ulong samplesPerChan)
{
int errorCode = Interop.DAQmxCfgImplicitTiming(taskHandle, (int)sampleMode, samplesPerChan);
if (errorCode < 0)
throw new DAQmxException(errorCode, "DAQmxCfgImplicitTiming failed.");
}
public void DAQmxCfgPipelinedSampleClkTiming(string source, double rate, DAQmxActiveEdge activeEdge, DAQmxSampleMode sampleMode, ulong samplesPerChan)
{
int errorCode = Interop.DAQmxCfgPipelinedSampClkTiming(taskHandle, source, rate, (int)activeEdge, (int)sampleMode, samplesPerChan);
if (errorCode < 0)
throw new DAQmxException(errorCode, "DAQmxCfgPipelinedSampleClkTiming failed.");
}
public double SampleClockRate
{
get
{
double result = 0.0;
int sampleClkRate = Interop.DAQmxGetSampClkRate(taskHandle, ref result);
if (sampleClkRate < 0)
throw new DAQmxException(sampleClkRate, "Could not get SampleClockRate");
return result;
}
set
{
int errorCode = Interop.DAQmxSetSampClkRate(taskHandle, value);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not set SampleClockRate");
}
}
public double SampleClockMaxRate
{
get
{
double result = 0.0;
int sampleClkMaxRate = Interop.DAQmxGetSampClkMaxRate(taskHandle, ref result);
if (sampleClkMaxRate < 0)
throw new DAQmxException(sampleClkMaxRate, "Could not get SampleClockMaxRate");
return result;
}
}
public void DisableStartTrig()
{
int errorCode = Interop.DAQmxDisableStartTrig(taskHandle);
if (errorCode < 0)
throw new DAQmxException(errorCode, "DisableStartTrig failed.");
}
public void CfgDigEdgeStartTrig(string triggerSource, DAQmxEdge triggerEdge)
{
int errorCode = Interop.DAQmxCfgDigEdgeStartTrig(taskHandle, triggerSource, (int)triggerEdge);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgDigEdgeStartTrig failed.");
}
public void CfgAnalogEdgeStartTrig(string triggerSource, DAQmxEdge triggerSlope, double triggerLevel)
{
int errorCode = Interop.DAQmxCfgAnlgEdgeStartTrig(taskHandle, triggerSource, (int)triggerSlope, triggerLevel);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgAnalogEdgeStartTrig failed.");
}
public void CfgAnalogMultiEdgeStartTrig(string triggerSources, DAQmxEdge[] triggerSlopes, double[] triggerLevels) =>
throw new NotImplementedException("CfgAnalogMultiEdgeStartTrig is not implemented in this version.");
public void CfgAnalogWindowStartTrig(string triggerSource, DAQmxWindowTriggerWhen triggerWhen, double windowTop, double windowBottom)
{
int errorCode = Interop.DAQmxCfgAnlgWindowStartTrig(taskHandle, triggerSource, (int)triggerWhen, windowTop, windowBottom);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgAnalogWindowStartTrig failed.");
}
public void CfgTimeStartTrig(CVIAbsoluteTime when, DAQmxTimescale timescale)
{
int errorCode = Interop.DAQmxCfgTimeStartTrig(taskHandle, when, (int)timescale);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgTimeStartTrig failed.");
}
public void CfgDigPatternStartTrig(string triggerSource, string triggerPattern, DAQmxDigitalPatternTriggerWhen triggerWhen)
{
int errorCode = Interop.DAQmxCfgDigPatternStartTrig(taskHandle, triggerSource, triggerPattern, (int)triggerWhen);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgDigPatternStartTrig failed.");
}
public void DisableRefTrig()
{
int errorCode = Interop.DAQmxDisableRefTrig(taskHandle);
if (errorCode < 0)
throw new DAQmxException(errorCode, "DisableRefTrig failed.");
}
public void CfgDigEdgeRefTrig(string triggerSource, DAQmxEdge triggerEdge, uint pretriggerSamples)
{
int errorCode = Interop.DAQmxCfgDigEdgeRefTrig(taskHandle, triggerSource, (int)triggerEdge, pretriggerSamples);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgDigEdgeRefTrig failed.");
}
public void CfgAnalogEdgeRefTrig(string triggerSource, DAQmxEdge triggerSlope, double triggerLevel, uint pretriggerSamples)
{
int errorCode = Interop.DAQmxCfgAnlgEdgeRefTrig(taskHandle, triggerSource, (int)triggerSlope, triggerLevel, pretriggerSamples);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgAnalogEdgeRefTrig failed.");
}
public void CfgAnalogMultiEdgeRefTrig(string triggerSources, DAQmxEdge[] triggerSlopes, double[] triggerLevels, uint pretriggerSamples) =>
throw new NotImplementedException("CfgAnalogMultiEdgeRefTrig is not implemented in this version.");
public void CfgAnalogWindowRefTrig(string triggerSource, DAQmxWindowTriggerWhen triggerWhen, double windowTop, double windowBottom, uint pretriggerSamples)
{
int errorCode = Interop.DAQmxCfgAnlgWindowRefTrig(taskHandle, triggerSource, (int)triggerWhen, windowTop, windowBottom, pretriggerSamples);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgAnalogWindowRefTrig failed.");
}
public void CfgDigPatternRefTrig(string triggerSource, string triggerPattern, DAQmxDigitalPatternTriggerWhen triggerWhen, uint pretriggerSamples)
{
int errorCode = Interop.DAQmxCfgDigPatternRefTrig(taskHandle, triggerSource, triggerPattern, (int)triggerWhen, pretriggerSamples);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgDigPatternRefTrig failed.");
}
public void WriteAnalogF64(int numSamplesPerChan, bool autoStart, double timeout, DAQmxDataLayout dataLayout, Span<double> data)
{
int num = numSamplesPerChan * Channels;
if (data.Length < num)
throw new DAQmxMemoryException("Span length too short. (Span length: " + data.Length.ToString() + ", required length: " + num.ToString() + ")");
IntPtr samplesPerChanWritten;
int errorCode = Interop.DAQmxWriteAnalogF64(taskHandle, numSamplesPerChan, autoStart, timeout, dataLayout > DAQmxDataLayout.GroupByChannel, data.ToArray(), out samplesPerChanWritten, IntPtr.Zero);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not write samples");
int int32 = samplesPerChanWritten.ToInt32();
if (int32 != numSamplesPerChan)
throw new DAQmxException("Could not write requested number of samples");
TotalSamplesPerChanWrite += (ulong)int32;
TotalSamplesWrite += (ulong)num;
}
public void WriteDigitalLines(int numSamplesPerChan, bool autoStart, double timeout, DAQmxDataLayout dataLayout, Span<byte> data)
{
int num = numSamplesPerChan * Channels;
if (data.Length < num)
throw new DAQmxMemoryException("Span length too short. (Span length: " + data.Length.ToString() + ", required length: " + num.ToString() + ")");
IntPtr samplesPerChanWritten;
int errorCode = Interop.DAQmxWriteDigitalLines(taskHandle, numSamplesPerChan, autoStart, timeout, dataLayout > DAQmxDataLayout.GroupByChannel, data.ToArray(), out samplesPerChanWritten, IntPtr.Zero);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not write samples");
int int32 = samplesPerChanWritten.ToInt32();
if (int32 != numSamplesPerChan)
throw new DAQmxException("Could not write requested number of samples");
TotalSamplesPerChanWrite += (ulong)int32;
TotalSamplesWrite += (ulong)num;
}
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxTimescale
{
HostTime = 16126, // 0x00003EFE
IODeviceTime = 16127, // 0x00003EFF
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxUnits
{
FromCustomScale = 10065, // 0x00002751
Volts = 10348, // 0x0000286C
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxWindowTriggerWhen
{
EnteringWindow = 10163, // 0x000027B3
LeavingWindow = 10208, // 0x000027E0
}

View File

@ -0,0 +1,7 @@
namespace Helpers.DAQmx;
public enum DAQmxWriteRegenMode
{
AllowRegen = 10097, // 0x00002771
DoNotAllowRegen = 10158, // 0x000027AE
}

431
Helpers/DAQmx/Interop.cs Normal file
View File

@ -0,0 +1,431 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
#pragma warning disable IDE1006 // Naming Styles
#pragma warning disable SYSLIB1054 // Type or member is obsolete
namespace Helpers.DAQmx;
internal class Interop
{ // cSpell:disable
private const string lib = "DAQmx";
private static IntPtr libHandle = IntPtr.Zero;
static Interop() =>
NativeLibrary.SetDllImportResolver(typeof(Interop).Assembly, ImportResolver);
private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
if (libraryName == "DAQmx" && !(libHandle != IntPtr.Zero))
{
bool loaded;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
loaded = NativeLibrary.TryLoad("C:/Windows/System32/nicaiu.dll", assembly, searchPath, out libHandle);
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
loaded = NativeLibrary.TryLoad("/usr/local/lib64/libnidaqmxbase.so", assembly, searchPath, out libHandle);
if (!loaded)
loaded = NativeLibrary.TryLoad("/usr/local/lib/libnidaqmxbase.so", assembly, searchPath, out libHandle);
if (!loaded)
loaded = NativeLibrary.TryLoad("/usr/local/natinst/lib/libnidaqmx.so", assembly, searchPath, out libHandle);
if (!loaded)
loaded = NativeLibrary.TryLoad("/usr/lib/x86_64-linux-gnu/libnidaqmx.so", assembly, searchPath, out libHandle);
}
else
throw new PlatformNotSupportedException("Unsupported platform for DAQmx library.");
if (!loaded)
throw new DllNotFoundException($"Failed to load {lib} library.");
}
return libHandle;
}
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxGetSampClkRate(IntPtr taskHandle, ref double data);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxSetSampClkRate(IntPtr taskHandle, double data);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxGetSampClkMaxRate(IntPtr taskHandle, ref double data);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxSetWriteRegenMode(IntPtr taskHandle, int data);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCreateAIVoltageChan(
IntPtr taskHandle,
string physicalChannel,
string nameToAssignToChannel,
int terminalConfig,
double minVal,
double maxVal,
int units,
string customScaleName);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCreateAOVoltageChan(
IntPtr taskHandle,
string physicalChannel,
string nameToAssignToChannel,
double minVal,
double maxVal,
int units,
string customScaleName);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCreateDOChan(
IntPtr taskHandle,
string lines,
string nameToAssignToLines,
int lineGrouping);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxGetErrorString(
int errorCode,
StringBuilder errorString,
uint buffersize);
#if unsafe
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe int DAQmxReadAnalogF64(
IntPtr taskHandle,
int numSampsPerChan,
double timeout,
int fillMode,
double* readArray,
uint arraySizeInSamps,
out IntPtr sampsPerChanRead,
IntPtr reserved);
#endif
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxReadAnalogScalarF64(
IntPtr taskHandle,
double timeout,
out double value,
IntPtr reserved);
#if unsafe
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe int DAQmxReadBinaryI16(
IntPtr taskHandle,
int numSampsPerChan,
double timeout,
int fillMode,
bool* readArray,
uint arraySizeInSamps,
out IntPtr sampsPerChanRead,
IntPtr reserved);
#endif
#if unsafe
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe int DAQmxReadBinaryU16(
IntPtr taskHandle,
int numSampsPerChan,
double timeout,
int fillMode,
ushort* readArray,
uint arraySizeInSamps,
out IntPtr sampsPerChanRead,
IntPtr reserved);
#endif
#if unsafe
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe int DAQmxReadBinaryI32(
IntPtr taskHandle,
int numSampsPerChan,
double timeout,
int fillMode,
int* readArray,
uint arraySizeInSamps,
out IntPtr sampsPerChanRead,
IntPtr reserved);
#endif
#if unsafe
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe int DAQmxReadBinaryU32(
IntPtr taskHandle,
int numSampsPerChan,
double timeout,
int fillMode,
uint* readArray,
uint arraySizeInSamps,
out IntPtr sampsPerChanRead,
IntPtr reserved);
#endif
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxConfigureLogging(
IntPtr taskHandle,
string filePath,
int loggingMode,
string groupName,
int operation);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxLoadTask(string taskName, out IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCreateTask(string taskName, out IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxAddGlobalChansToTask(IntPtr taskHandle, string[] channelNames);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxStartTask(IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxStopTask(IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxClearTask(IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxWaitUntilTaskDone(IntPtr taskHandle, double timeToWait);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxWaitForValidTimestamp(
IntPtr taskHandle,
int timestampEvent,
double timeout,
CVIAbsoluteTime timestamp);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxIsTaskDone(IntPtr taskHandle, out uint isTaskDone);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxTaskControl(IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxGetNthTaskChannel(IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxGetNthTaskDevice(IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxGetTaskAttribute(IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCfgSampClkTiming(
IntPtr taskHandle,
string source,
double rate,
int activeEdge,
int sampleMode,
ulong sampsPerChan);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCfgHandshakingTiming(
IntPtr taskHandle,
int sampleMode,
ulong sampsPerChan);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCfgBurstHandshakingTimingImportClock(
IntPtr taskHandle,
int sampleMode,
ulong sampsPerChan,
double sampleClkRate,
string sampleClkSrc,
int sampleClkActiveEdge,
int pauseWhen,
int readyEventActiveLevel);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCfgBurstHandshakingTimingExportClock(
IntPtr taskHandle,
int sampleMode,
ulong sampsPerChan,
double sampleClkRate,
string sampleClkOutpTerm,
int sampleClkPulsePolarity,
int pauseWhen,
int readyEventActiveLevel);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCfgChangeDetectionTiming(
IntPtr taskHandle,
string risingEdgeChan,
string fallingEdgeChan,
int sampleMode,
ulong sampsPerChan);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCfgImplicitTiming(
IntPtr taskHandle,
int sampleMode,
ulong sampsPerChan);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxCfgPipelinedSampClkTiming(
IntPtr taskHandle,
string source,
double rate,
int activeEdge,
int sampleMode,
ulong sampsPerChan);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxGetTimingAttribute(
IntPtr taskHandle,
int attribute,
out object value);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxSetTimingAttribute(
IntPtr taskHandle,
int attribute,
object value);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxResetTimingAttribute(IntPtr taskHandle, int attribute);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxGetTimingAttributeEx(
IntPtr taskHandle,
string deviceNames,
int attribute,
out object value);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxSetTimingAttributeEx(
IntPtr taskHandle,
string deviceNames,
int attribute,
object value);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxResetTimingAttributeEx(
IntPtr taskHandle,
string deviceNames,
int attribute);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxDisableStartTrig(IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgDigEdgeStartTrig(
IntPtr taskHandle,
string triggerSource,
int triggerEdge);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgAnlgEdgeStartTrig(
IntPtr taskHandle,
string triggerSource,
int triggerSlope,
double triggerLevel);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgAnlgMultiEdgeStartTrig(
IntPtr taskHandle,
string triggerSources,
int[] triggerSlopeArray,
double[] triggerLevelArray,
uint arraySize);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgAnlgWindowStartTrig(
IntPtr taskHandle,
string triggerSource,
int triggerWhen,
double windowTop,
double windowBottom);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgTimeStartTrig(
IntPtr taskHandle,
CVIAbsoluteTime when,
int timescale);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgDigPatternStartTrig(
IntPtr taskHandle,
string triggerSource,
string triggerPattern,
int triggerWhen);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxDisableRefTrig(IntPtr taskHandle);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgDigEdgeRefTrig(
IntPtr taskHandle,
string triggerSource,
int triggerEdge,
uint pretriggerSamples);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgAnlgEdgeRefTrig(
IntPtr taskHandle,
string triggerSource,
int triggerSlope,
double triggerLevel,
uint pretriggerSamples);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgAnlgMultiEdgeRefTrig(
IntPtr taskHandle,
string triggerSources,
int[] triggerSlopeArray,
double[] triggerLevelArray,
uint pretriggerSamples,
uint arraySize);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgAnlgWindowRefTrig(
IntPtr taskHandle,
string triggerSource,
int triggerWhen,
double windowTop,
double windowBottom,
uint pretriggerSamples);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxCfgDigPatternRefTrig(
IntPtr taskHandle,
string triggerSource,
string triggerPattern,
int triggerWhen,
uint pretriggerSamples);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxGetTrigAttribute(
IntPtr taskHandle,
int attribute,
out object value);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxSetTrigAttribute(IntPtr taskHandle, int attribute, object value);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxResetTrigAttribute(IntPtr taskHandle, int attribute);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxWriteAnalogF64(
IntPtr taskHandle,
int numSampsPerChan,
bool autoStart,
double timeout,
bool dataLayout,
double[] writeArray,
out IntPtr sampsPerChanWritten,
IntPtr reserved);
[DllImport("DAQmx", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxWriteDigitalLines(
IntPtr taskHandle,
int numSampsPerChan,
bool autoStart,
double timeout,
bool dataLayout,
byte[] writeArray,
out IntPtr sampsPerChanWritten,
IntPtr reserved);
}

View File

@ -1,16 +1,22 @@
using CliWrap;
using File_Watcher.Models;
#if ShellProgressBar
using ShellProgressBar;
#endif
using System.Collections.ObjectModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Text.Json;
using View_by_Distance.Metadata.Models;
using View_by_Distance.Metadata.Models.Stateless;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Stateless;
using Phares.Metadata.Models;
using Phares.Metadata.Models.Stateless;
using Phares.Shared.Models;
using Phares.Shared.Models.Stateless;
namespace File_Watcher.Helpers;
@ -20,13 +26,25 @@ internal static partial class DeterministicHashCodeHelper
private class Windows : IWindows, IDisposable
{
public long Ticks { get; init; }
public int? CurrentTick =>
#if ShellProgressBar
_ProgressBar?.CurrentTick;
#else
throw new NotSupportedException("ShellProgressBar is not supported in this context.");
#endif
#if ShellProgressBar
private ProgressBar? _ProgressBar;
private readonly ProgressBarOptions _ProgressBarOptions;
public int CurrentTick { get; internal set; }
#endif
public Windows() =>
#if ShellProgressBar
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
#else
throw new NotSupportedException("ShellProgressBar is not supported in this context.");
#endif
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient httpClient, Uri uri) =>
GetDeterministicHashCode(httpClient, uri);
@ -97,18 +115,26 @@ internal static partial class DeterministicHashCodeHelper
}
void IWindows.Tick() =>
#if ShellProgressBar
_ProgressBar?.Tick();
#else
throw new NotSupportedException("ShellProgressBar is not supported in this context.");
#endif
void IDisposable.Dispose()
{
#if ShellProgressBar
_ProgressBar?.Dispose();
#endif
GC.SuppressFinalize(this);
}
void IWindows.ConstructProgressBar(int maxTicks, string message)
{
#if ShellProgressBar
_ProgressBar?.Dispose();
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
#endif
}
ReadOnlyCollection<string> IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath)
@ -164,7 +190,7 @@ internal static partial class DeterministicHashCodeHelper
string sourceDirectory;
List<string> check = [];
string archiveEntryFile;
long ticks = DateTime.Now.Ticks;
Windows windows = new();
ReadOnlyCollection<FirstPass> collection;
string rootDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
if (!Directory.Exists(rootDirectory))
@ -187,7 +213,7 @@ internal static partial class DeterministicHashCodeHelper
archiveEntryFile = Path.Combine(sourceDirectory, zipArchiveEntry.Name);
zipArchiveEntry.ExtractToFile(archiveEntryFile);
}
collection = WindowsWork(logger, appSettings, ticks, sourceDirectory);
collection = WindowsWork(windows, logger, appSettings, sourceDirectory);
if (check.Count == collection.Count)
{
json = JsonSerializer.Serialize(collection.ToList(), FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
@ -198,12 +224,11 @@ internal static partial class DeterministicHashCodeHelper
return true;
}
private static ReadOnlyCollection<FirstPass> WindowsWork(ILogger<Worker>? logger, AppSettings appSettings, long ticks, string sourceDirectory)
private static ReadOnlyCollection<FirstPass> WindowsWork(IWindows windows, ILogger<Worker>? logger, AppSettings appSettings, string sourceDirectory)
{
ReadOnlyCollection<FirstPass> results;
Windows windows = new();
IWindows windowsInterface = windows;
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
logger?.LogInformation("{Ticks} {RootDirectory}", windows.Ticks, sourceDirectory);
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
int appSettingsMaxDegreeOfParallelism = appSettings.DeterministicHashCodeConfiguration.MaxDegreeOfParallelism;
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).AsReadOnly();
@ -299,7 +324,7 @@ internal static partial class DeterministicHashCodeHelper
return result;
}
private static ReadOnlyCollection<FirstPass> WindowsAsynchronousWork(AppSettings appSettings, Windows windows, ReadOnlyCollection<string> files, A_Metadata metadata, int appSettingsMaxDegreeOfParallelism)
private static ReadOnlyCollection<FirstPass> WindowsAsynchronousWork(AppSettings appSettings, IWindows windows, ReadOnlyCollection<string> files, A_Metadata metadata, int appSettingsMaxDegreeOfParallelism)
{
List<FirstPass> results = [];
FirstPass firstPass;

503
Helpers/DiskInfoHelper.cs Normal file
View File

@ -0,0 +1,503 @@
using File_Watcher.Models;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Watcher.Helpers;
internal static partial class DiskInfoHelper
{
public record DiskDrive(string? Caption,
string? DeviceID,
string? FirmwareRevision,
uint? Index,
string? Model,
string? Name,
uint? Partitions,
DiskPartition[]? PartitionCollection,
string? SerialNumber,
ulong? Size,
string? Status,
string? SystemName,
ulong? TotalCylinders,
ulong? TotalHeads)
{
internal static DiskDrive Get(DiskDrive diskDrive, DiskPartition[] diskPartitions, LogicalDrive[] logicalDrives)
{
DiskDrive result;
DiskPartition[] collection = DiskPartition.Get((from l in diskPartitions where l.DiskIndex == diskDrive.Index select l).ToArray(), logicalDrives);
result = new(Caption: diskDrive.Caption,
DeviceID: diskDrive.DeviceID,
FirmwareRevision: diskDrive.FirmwareRevision,
Index: diskDrive.Index,
Model: diskDrive.Model,
Name: diskDrive.Name,
Partitions: diskDrive.Partitions,
PartitionCollection: collection,
SerialNumber: diskDrive.SerialNumber,
Size: diskDrive.Size,
Status: diskDrive.Status,
SystemName: diskDrive.SystemName,
TotalCylinders: diskDrive.TotalCylinders,
TotalHeads: diskDrive.TotalHeads);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(DiskDrive[]))]
private partial class DiskDriveArraySourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Dictionary<string, object>))]
private partial class DictionaryStringObjectSourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(JsonElement))]
private partial class JsonElementSourceGenerationContext : JsonSerializerContext
{
}
public record DiskPartition(bool? BootPartition,
string? Caption,
string? Description,
string? DeviceID,
uint? DiskIndex,
uint? Index,
LogicalDrive[]? LogicalDrives,
ulong? Size,
ulong? StartingOffset,
string? SystemName,
string? Type)
{
internal static DiskPartition[] Get(DiskPartition[] diskPartitions, LogicalDrive[] logicalDrives)
{
List<DiskPartition> results = [];
ulong lowerMatch;
ulong upperMatch;
LogicalDrive[] collection;
DiskPartition diskPartition;
foreach (DiskPartition p in diskPartitions)
{
if (p.Size is null)
continue;
lowerMatch = p.Size.Value - 10240;
upperMatch = p.Size.Value + 10240;
collection = (from l in logicalDrives where l.DriveType != 4 && l.Size > lowerMatch && l.Size < upperMatch select l).ToArray();
diskPartition = new(BootPartition: p.BootPartition,
Caption: p.Caption,
Description: p.Description,
DeviceID: p.DeviceID,
DiskIndex: p.DiskIndex,
Index: p.Index,
LogicalDrives: collection,
Size: p.Size,
StartingOffset: p.StartingOffset,
SystemName: p.SystemName,
Type: p.Type);
results.Add(diskPartition);
}
return results.ToArray();
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(DiskPartition[]))]
private partial class DiskPartitionSourceGenerationContext : JsonSerializerContext
{
}
public record LogicalDrive(string? Caption,
string? DeviceID,
uint? DriveType,
string? FileSystem,
ulong? FreeSpace,
string? Name,
ulong? PercentageFree,
ulong? PercentageUsed,
string? ProviderName,
ulong? Size,
string? SystemName,
string? VolumeName,
string? VolumeSerialNumber);
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(LogicalDrive[]))]
private partial class LogicalDriveSourceGenerationContext : JsonSerializerContext
{
}
public record Record(long AvailableFreeSpace,
string DriveFormat,
string DriveType,
bool IsReady,
char Name,
ulong PercentageFree,
ulong PercentageUsed,
long TotalFreeSpace,
long TotalSize,
string VolumeLabel)
{
public static Record Get(DriveInfo driveInfo) =>
new(AvailableFreeSpace: driveInfo.AvailableFreeSpace,
DriveFormat: driveInfo.DriveFormat,
DriveType: driveInfo.DriveType.ToString(),
IsReady: driveInfo.IsReady,
Name: driveInfo.Name.ToUpper()[0],
PercentageUsed: (ulong)(Math.Round(driveInfo.AvailableFreeSpace / (double)driveInfo.TotalSize, 2) * 100),
PercentageFree: (ulong)(Math.Round((driveInfo.TotalSize - driveInfo.AvailableFreeSpace) / (double)driveInfo.TotalSize, 2) * 100),
TotalFreeSpace: driveInfo.TotalFreeSpace,
TotalSize: driveInfo.TotalSize,
VolumeLabel: driveInfo.VolumeLabel);
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Record[]))]
private partial class RecordSourceGenerationContext : JsonSerializerContext
{
}
private record Win32(string? DiskDrive,
string? Processor,
string? LogicalDisk,
string? DiskPartition,
string? NetworkAdapter);
internal static bool WriteDiskInfo(AppSettings appSettings, ILogger<Worker> logger)
{
string? json = WriteRecord();
ReadOnlyCollection<DiskDrive> devices = GetDrives(appSettings, logger);
string yaml = GetYetAnotherMarkupLanguage(devices);
ReadOnlyCollection<string> normalized = GetNormalized(appSettings, logger, devices);
string text = string.Join(Environment.NewLine, normalized);
string markdown = string.Concat("# ",
Environment.MachineName.ToLower(),
Environment.NewLine,
Environment.NewLine,
"## Normalized",
Environment.NewLine,
Environment.NewLine,
"```log",
Environment.NewLine,
text,
Environment.NewLine,
"```",
Environment.NewLine,
Environment.NewLine,
"## json",
Environment.NewLine,
Environment.NewLine,
"```json",
Environment.NewLine,
json,
Environment.NewLine,
"```",
Environment.NewLine,
Environment.NewLine,
"## yaml",
Environment.NewLine,
Environment.NewLine,
"```yaml",
Environment.NewLine,
yaml,
Environment.NewLine,
"```",
Environment.NewLine);
WriteAllText(Path.Combine(appSettings.DiskInfoConfiguration.Destination, $"{Environment.MachineName.ToLower()}.md"), markdown);
return true;
}
private static string WriteRecord()
{
string result;
Record record;
List<Record> records = [];
DriveInfo[] drives = DriveInfo.GetDrives();
foreach (DriveInfo driveInfo in drives)
{
record = Record.Get(driveInfo);
records.Add(record);
}
result = JsonSerializer.Serialize(records.ToArray(), RecordSourceGenerationContext.Default.RecordArray);
return result;
}
private static ReadOnlyCollection<DiskDrive> GetDrives(AppSettings appSettings, ILogger<Worker> logger)
{
#pragma warning disable CA1416
List<DiskDrive> results = [];
Win32 win32 = GetWin32(appSettings, logger);
if (win32.DiskDrive is not null && win32.DiskPartition is not null && win32.LogicalDisk is not null)
{
DiskDrive diskDrive;
string diskDriveJson = win32.DiskDrive[0] == '[' ? win32.DiskDrive : $"[{win32.DiskDrive}]";
string logicalDiskJson = win32.LogicalDisk[0] == '[' ? win32.LogicalDisk : $"[{win32.LogicalDisk}]";
string diskPartitionJson = win32.DiskPartition[0] == '[' ? win32.DiskPartition : $"[{win32.DiskPartition}]";
DiskDrive[] diskDrives = JsonSerializer.Deserialize(diskDriveJson, DiskDriveArraySourceGenerationContext.Default.DiskDriveArray) ??
throw new NullReferenceException(nameof(DiskDrive));
LogicalDrive[] logicalDrives = JsonSerializer.Deserialize(logicalDiskJson, LogicalDriveSourceGenerationContext.Default.LogicalDriveArray) ??
throw new NullReferenceException(nameof(LogicalDrive));
DiskPartition[] diskPartitions = JsonSerializer.Deserialize(diskPartitionJson, DiskPartitionSourceGenerationContext.Default.DiskPartitionArray) ??
throw new NullReferenceException(nameof(DiskPartition));
foreach (DiskDrive d in diskDrives)
{
diskDrive = DiskDrive.Get(d, diskPartitions, logicalDrives);
results.Add(diskDrive);
}
}
return results.AsReadOnly();
#pragma warning restore
}
private static Win32 GetWin32(AppSettings appSettings, ILogger<Worker> logger)
{
Win32 win32;
Process? process;
string[] segments;
string standardError;
string standardOutput;
string? diskDrive = null;
string? processor = null;
string? logicalDisk = null;
string? diskPartition = null;
string? networkAdapter = null;
ProcessStartInfo processStartInfo;
string fileName = "powershell.exe";
string date = DateTime.Now.ToString("yyyy-MM-dd");
foreach (string className in appSettings.DiskInfoConfiguration.Classes)
{
segments = className.Split(' ');
if (segments[0].Length < 3)
continue;
processStartInfo = new(fileName, $"-NoProfile -ExecutionPolicy ByPass Get-WmiObject {className} | ConvertTo-JSON")
{
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false
};
try
{
process = Process.Start(processStartInfo);
if (process is not null)
{
for (int j = 1; j < 45; j++)
{
_ = process.WaitForExit(1000);
if (process.HasExited)
break;
}
if (!process.HasExited)
{
logger.LogWarning($"// {segments[0]} Never exited!");
if (segments[0] is "Win32_DiskDrive" or "Win32_DiskPartition" or "Win32_LogicalDisk")
break;
}
else
{
standardError = process.StandardError.ReadToEnd();
standardOutput = process.StandardOutput.ReadToEnd();
logger.LogInformation("// {className}{line}{error}{line}{line}// {output}", segments[0], Environment.NewLine, standardError, Environment.NewLine, Environment.NewLine, standardOutput);
if (string.IsNullOrEmpty(standardError))
{
if (segments[0] == "Win32_DiskDrive")
diskDrive = standardOutput;
else if (segments[0] == "Win32_DiskPartition")
diskPartition = standardOutput;
else if (segments[0] == "Win32_LogicalDisk")
logicalDisk = standardOutput;
else if (segments[0] == "Win32_NetworkAdapter")
networkAdapter = standardOutput;
else if (segments[0] == "Win32_Processor")
processor = standardOutput;
WriteAllText(Path.Combine(appSettings.DiskInfoConfiguration.Destination, $"{Environment.MachineName.ToLower()}-{segments[0]}-{date}.json"), standardOutput);
}
}
}
process?.Dispose();
}
catch (Exception ex)
{
logger.LogError(ex, "Error:");
}
}
win32 = new(DiskDrive: diskDrive,
Processor: processor,
LogicalDisk: logicalDisk,
DiskPartition: diskPartition,
NetworkAdapter: networkAdapter);
return win32;
}
public static Dictionary<string, object> DeserializeAndFlatten(string json, char? remove)
{
Dictionary<string, object> results = [];
JsonElement jsonElement = JsonSerializer.Deserialize(json, JsonElementSourceGenerationContext.Default.JsonElement);
FillDictionaryFromJToken(results, jsonElement, string.Empty, remove);
return results;
}
private static void FillDictionaryFromJToken(Dictionary<string, object> results, JsonElement jsonElement, string prefix, char? remove)
{
switch (jsonElement.ValueKind)
{
case JsonValueKind.Object:
foreach (JsonProperty jsonProperty in jsonElement.EnumerateObject())
{
FillDictionaryFromJToken(results, jsonProperty.Value, Join(prefix, jsonProperty.Name), remove);
}
break;
case JsonValueKind.Array:
int index = 0;
foreach (JsonElement value in jsonElement.EnumerateArray())
{
FillDictionaryFromJToken(results, value, Join(prefix, index.ToString()), remove);
index++;
}
break;
case JsonValueKind.String:
if (remove is null)
{
results.Add(prefix, jsonElement.ToString());
}
else
{
results.Add(prefix, jsonElement.ToString().Replace(remove.Value, '_'));
}
break;
case JsonValueKind.True:
case JsonValueKind.False:
case JsonValueKind.Number:
results.Add(prefix, jsonElement.ToString());
break;
}
}
private static string Join(string prefix, string name) =>
string.IsNullOrEmpty(prefix) ? name : prefix + "." + name;
private static string GetYetAnotherMarkupLanguage(ReadOnlyCollection<DiskDrive> devices)
{
string result;
List<string> results = [];
string json = JsonSerializer.Serialize(devices.ToArray(), DiskDriveArraySourceGenerationContext.Default.DiskDriveArray);
Dictionary<string, object> keyValuePairs = DeserializeAndFlatten(json, ':');
string[] lines = JsonSerializer.Serialize(keyValuePairs, DictionaryStringObjectSourceGenerationContext.Default.DictionaryStringObject).Split(Environment.NewLine);
for (int i = 1; i < lines.Length - 1; i++)
{
results.Add(lines[i].Trim()
.Trim(',')
.Trim('"')
.Replace("\": \"", ": ")
.Replace("\": ", ": "));
}
result = string.Join(Environment.NewLine, results);
return result;
}
private static string GetSizeWithSuffix(ulong value)
{
string result;
int i = 0;
double displayValue = value * 1f;
string[] SizeSuffixes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
while (Math.Round(displayValue / 1024f) >= 1)
{
displayValue /= 1024;
i++;
}
result = string.Format("{0:n1} {1}", displayValue, SizeSuffixes[i]);
return result;
}
private static void WriteAllText(string path, string text)
{
string check = !File.Exists(path) ? string.Empty : File.ReadAllText(path);
if (check != text)
File.WriteAllText(path, text);
}
private static ReadOnlyCollection<string> GetNormalized(AppSettings appSettings, ILogger<Worker> logger, ReadOnlyCollection<DiskDrive> drives)
{
List<string> results = [];
decimal free;
decimal used;
string display;
int deviceCount;
int offsetCount;
string deviceSize;
int partitionCount;
results.Add("Max");
string offsetDisplay;
string partitionSize;
decimal devicePercent;
string logicalDriveUsed;
string logicalDriveSize;
decimal partitionPercent;
int logicalDriveFreeCount;
int logicalDriveUsedCount;
decimal partitionDecimalSize;
string logicalDriveFreeSpace;
decimal logicalDriveDecimalFreeSpace;
DiskInfoConfiguration diskInfoConfiguration = appSettings.DiskInfoConfiguration;
results.Add($"{new string('-', diskInfoConfiguration.Bars)} Value of Max Argument");
foreach (DiskDrive drive in drives.OrderBy(l => l.Index))
{
if (drive.Size is null || drive.PartitionCollection is null)
continue;
devicePercent = drive.Size.Value / diskInfoConfiguration.Max;
deviceSize = GetSizeWithSuffix(drive.Size.Value);
results.Add($"{drive.DeviceID} - Cylinders: {drive.TotalCylinders} - {drive.Model}");
deviceCount = (int)Math.Round(devicePercent * diskInfoConfiguration.Bars);
results.Add($"{new string('-', deviceCount)} {Math.Round(devicePercent, 2) * 100:000}% of Max Argument {deviceSize}");
foreach (DiskPartition partition in drive.PartitionCollection.OrderBy(l => l.Index))
{
if (partition.Size is null || partition.StartingOffset is null || partition.LogicalDrives is null)
continue;
partitionPercent = partition.Size.Value / diskInfoConfiguration.Max;
partitionSize = GetSizeWithSuffix(partition.Size.Value);
partitionCount = (int)Math.Round(partitionPercent * diskInfoConfiguration.Bars);
offsetCount = (int)Math.Round(partition.StartingOffset.Value / diskInfoConfiguration.Max * diskInfoConfiguration.Bars);
offsetDisplay = new string('_', offsetCount);
results.Add($"{partition.DeviceID} - {string.Join(", ", partition.LogicalDrives.Select(l => l.DeviceID))}");
results.Add($"{offsetDisplay}{new string('-', partitionCount)}{new string('_', diskInfoConfiguration.Bars - offsetCount - partitionCount)} {Math.Round(partitionPercent, 2) * 100:000}% of Disk {partitionSize}");
foreach (LogicalDrive logicalDrive in partition.LogicalDrives)
{
if (logicalDrive.Size is null || logicalDrive.FreeSpace is null)
continue;
if ((int)Math.Round(logicalDrive.Size.Value / diskInfoConfiguration.Max * diskInfoConfiguration.Bars) != (int)Math.Round(partition.Size.Value / diskInfoConfiguration.Max * diskInfoConfiguration.Bars))
{
logger.LogWarning("logicalDrive.Size !~ partition.Size");
break;
}
partitionDecimalSize = partition.Size.Value;
logicalDriveDecimalFreeSpace = logicalDrive.FreeSpace.Value;
logicalDriveSize = GetSizeWithSuffix(logicalDrive.Size.Value);
logicalDriveFreeSpace = GetSizeWithSuffix(logicalDrive.FreeSpace.Value);
logicalDriveUsed = GetSizeWithSuffix(logicalDrive.Size.Value - logicalDrive.FreeSpace.Value);
logicalDriveFreeCount = (int)Math.Round(logicalDriveDecimalFreeSpace / diskInfoConfiguration.Max * diskInfoConfiguration.Bars);
display = string.IsNullOrEmpty(logicalDrive.DeviceID) ? "Partition" : logicalDrive.DeviceID;
logicalDriveUsedCount = (int)Math.Round((partitionDecimalSize - logicalDriveDecimalFreeSpace) / diskInfoConfiguration.Max * diskInfoConfiguration.Bars);
free = (int)(Math.Round(logicalDriveDecimalFreeSpace / partitionDecimalSize, 2) * 100);
used = (int)(Math.Round((partitionDecimalSize - logicalDriveDecimalFreeSpace) / partitionDecimalSize, 2) * 100);
results.Add($"{offsetDisplay}{new string('-', logicalDriveUsedCount)}{new string('*', logicalDriveFreeCount)}{new string('_', diskInfoConfiguration.Bars - offsetCount - logicalDriveUsedCount - logicalDriveFreeCount)} {used:000}% of [{display}] {logicalDriveUsed} ({free:000}% {logicalDriveFreeSpace} free)");
}
}
}
return results.AsReadOnly();
}
}

View File

@ -68,7 +68,7 @@ internal static partial class HelperCamstarOracle
return results;
}
internal static bool Check(AppSettings appSettings, ILogger<Worker> logger, CancellationToken cancellationToken)
internal static bool Check(AppSettings appSettings, IHttpClientFactory httpClientFactory, ILogger<Worker> logger, CancellationToken cancellationToken)
{
if (_MonIn is null)
throw new NullReferenceException(nameof(_MonIn));
@ -100,6 +100,7 @@ internal static partial class HelperCamstarOracle
File.WriteAllLines(Path.Combine(directory, $"{dateTime.Ticks}.tsv"), lines);
if (_LastValue is null || _LastUpload is null || _LastValue.Value != lines.Count || new TimeSpan(dateTime.Ticks - _LastUpload.Value.Ticks).TotalMinutes > 5)
{
Heartbeat(appSettings, httpClientFactory, logger, State.Up, cancellationToken);
Task<HttpResponseMessage> httpResponseMessage = _MonIn.SendPerformanceMessage(camstarOracleConfiguration.MonitorApplicationSite, camstarOracleConfiguration.MonitorApplicationResource, performanceName, value: lines.Count, description: string.Empty);
httpResponseMessage.Wait(cancellationToken);
if (httpResponseMessage.Result.StatusCode != System.Net.HttpStatusCode.OK)

View File

@ -17,7 +17,7 @@ internal static partial class HelperInfinityQS
}
}
private static void RunMI()
private static void RunMI(string decryptedPassword)
{
#pragma warning disable CA1416
string processName = "iispcmi.exe";
@ -27,7 +27,7 @@ internal static partial class HelperInfinityQS
Domain = "Infineon",
UseShellExecute = false,
UserName = "ecfisysadmin",
PasswordInClearText = "j(1(P%xB=g}3w9db",
PasswordInClearText = decryptedPassword,
WorkingDirectory = "C:/Program Files (x86)/InfinityQS International/ProFicient/Applications"
};
TimeSpan timeSpan = new(DateTime.Now.AddDays(7).Ticks - DateTime.Now.Ticks);
@ -36,10 +36,11 @@ internal static partial class HelperInfinityQS
#pragma warning restore CA1416
}
internal static bool Select(AppSettings appSettings, ILogger<Worker> logger)
internal static bool ProcessStart(AppSettings appSettings, ILogger<Worker> logger)
{
logger.LogInformation(appSettings.FileWatcherConfiguration.Company);
RunMI();
string decrypted = RijndaelEncryption.Decrypt(appSettings.InfinityQSConfiguration.EncryptedPassword, appSettings.FileWatcherConfiguration.Company);
RunMI(decrypted);
return true;
}
}

View File

@ -125,7 +125,7 @@ internal static partial class HelperSerial
// }
byte[] documentDelimiter =
[
Convert.ToByte(32),
Convert.ToByte(32),
Convert.ToByte(83),
Convert.ToByte(116),
Convert.ToByte(97),

View File

@ -0,0 +1,114 @@
using File_Watcher.Models;
using System.Collections.ObjectModel;
using System.Net.Mail;
namespace File_Watcher.Helpers;
internal static partial class InfinityQSProjectHelper
{
private record Record(ReadOnlyCollection<string> FilteredLines,
DateTime LastWriteTimeUtc,
string Path);
private static long _LastReview = DateTime.UtcNow.Ticks;
private static readonly Dictionary<string, Record> _KeyValuePairs = [];
internal static bool SendEmail(AppSettings appSettings, ILogger<Worker> logger)
{
InfinityQSProjectConfiguration configuration = appSettings.InfinityQSProjectConfiguration;
Clear(logger, configuration);
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(logger, configuration);
SendEmail(logger, configuration, keyValuePairs);
_LastReview = DateTime.UtcNow.Ticks;
return true;
}
private static void Clear(ILogger<Worker> logger, InfinityQSProjectConfiguration configuration)
{
long check = DateTime.UtcNow.AddHours(-configuration.ClearEveryHours).Ticks;
foreach (KeyValuePair<string, Record> keyValuePair in _KeyValuePairs)
{
if (keyValuePair.Value.LastWriteTimeUtc.Ticks < check)
{
_ = _KeyValuePairs.Remove(keyValuePair.Key);
logger.LogDebug("Clear File:{file}", keyValuePair.Key);
}
}
}
private static ReadOnlyDictionary<string, Record> GetKeyValuePairs(ILogger<Worker> logger, InfinityQSProjectConfiguration configuration)
{
bool check;
Record? record;
string[] lines;
FileInfo fileInfo;
List<string> filtered = [];
Dictionary<string, Record> results = [];
string[] files = Directory.GetFiles(configuration.SourceDirectory, configuration.SearchPattern, SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
check = false;
filtered.Clear();
fileInfo = new(file);
if (fileInfo.LastWriteTimeUtc.Ticks < _LastReview)
{
logger.LogDebug("Old File:{file}", file);
continue;
}
if (_KeyValuePairs.ContainsKey(fileInfo.FullName))
{
logger.LogDebug("Verified File:{file}", file);
continue;
}
lines = File.ReadAllLines(fileInfo.FullName);
foreach (string line in lines)
{
if (!check && line.Contains(configuration.Search))
{
check = true;
continue;
}
if (check)
{
if (line.StartsWith(configuration.Search[0]))
break;
filtered.Add(line);
}
}
record = new(FilteredLines: filtered.AsReadOnly(),
LastWriteTimeUtc: fileInfo.LastWriteTimeUtc,
Path: fileInfo.FullName);
results.Add(fileInfo.FullName, record);
}
return results.AsReadOnly();
}
private static void SendEmail(ILogger<Worker> logger, InfinityQSProjectConfiguration configuration, ReadOnlyDictionary<string, Record> keyValuePairs)
{
string body;
foreach (KeyValuePair<string, Record> keyValuePair in keyValuePairs)
{
logger.LogDebug("File:{file}", keyValuePair.Key);
body = $"InfinityQS Project Change Detected{Environment.NewLine}File:{keyValuePair.Key}{Environment.NewLine}LastWriteTimeUtc:{keyValuePair.Value:O}{Environment.NewLine}{string.Join(Environment.NewLine, keyValuePair.Value.FilteredLines)}";
logger.LogWarning("SendEmail:{body}", body);
SendEmail(configuration.From, configuration.To, configuration.SimpleMailTransferProtocolServer, configuration.Subject, body);
}
}
private static void SendEmail(string from, string to, string simpleMailTransferProtocolServer, string subject, string body)
{
SmtpClient smtpClient = new(simpleMailTransferProtocolServer);
MailMessage mailMessage = new()
{
From = new MailAddress(from),
Subject = subject,
Body = body,
Priority = MailPriority.High
};
mailMessage.To.Add(new MailAddress(to));
smtpClient.Send(mailMessage);
smtpClient.Dispose();
mailMessage.Dispose();
}
}

700
Helpers/LabJackT7Helper.cs Normal file
View File

@ -0,0 +1,700 @@
using File_Watcher.Models;
using System.Diagnostics;
using System.Net.Sockets;
namespace File_Watcher.Helpers;
#pragma warning disable IDE0300
internal static partial class LabJackT7Helper
{
private static ModbusTransmissionControlProtocolClient? _ModbusTransmissionControlProtocolClient;
private class ModbusTransmissionControlProtocolClient : IDisposable
{
private ushort _TransactionID;
private NetworkStream? _NetworkStream;
private TcpClient? _TransmissionControlProtocolClient;
public ModbusTransmissionControlProtocolClient(string hostname, int port) =>
Connect(hostname, port);
public void Connect(string hostname, int port)
{
if (_TransmissionControlProtocolClient is not null)
Close();
_TransmissionControlProtocolClient = new TcpClient(hostname, port);
_NetworkStream = _TransmissionControlProtocolClient.GetStream();
_TransactionID = 0;
}
public void Close()
{
_NetworkStream?.Close();
_NetworkStream = null;
_TransmissionControlProtocolClient?.Close();
_TransmissionControlProtocolClient = null;
}
public bool IsConnected()
{
if (_TransmissionControlProtocolClient is not null)
return _TransmissionControlProtocolClient.Connected;
return false;
}
public void SetTimeouts(int sendTimeout, int receiveTimeout)
{
if (_TransmissionControlProtocolClient == null)
throw new Exception("Not connected.");
_TransmissionControlProtocolClient.ReceiveTimeout = receiveTimeout;
_TransmissionControlProtocolClient.SendTimeout = sendTimeout;
}
/// <summary>
/// Write a byte array of data to the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The byte array of data to write.</param>
public void Write(ushort address, byte[] data)
{
if (_NetworkStream is null)
throw new Exception("Not connected.");
//Using Modbus function 16
//Create Modbus Command
if (data.Length > 254)
throw new Exception("Too many bytes. The maximum is 254.");
if (data.Length % 2 != 0)
throw new Exception("The number of bytes needs to be a multiple of 2.");
byte[] com = new byte[13 + data.Length];
com[7] = 16;
com[8] = (byte)(address >> 8);
com[9] = (byte)(address & 0xFF);
com[10] = 0;
com[11] = (byte)(data.Length / 2);
com[12] = (byte)data.Length;
Array.Copy(data, 0, com, 13, data.Length);
SetHeader(com);
_NetworkStream.Write(com, 0, com.Length);
byte[] res = new byte[12];
int expectedSize = res.Length;
int size = _NetworkStream.Read(res, 0, res.Length);
Array.Resize(ref res, size);
ResponseErrorChecks(res, expectedSize, com);
}
/// <summary>
/// Read a byte array of data from the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The read byte array of data. The array length is
/// the amount of bytes to read.</param>
public void Read(ushort address, byte[] data)
{
if (_NetworkStream is null)
throw new Exception("Not connected.");
//Using Modbus function 3
//Create Modbus Command
if (data.Length > 254)
throw new Exception("Too many bytes. The maximum is 254.");
if (data.Length % 2 != 0)
throw new Exception("The number of bytes needs to be a multiple of 2.");
byte[] com = new byte[12];
com[7] = 3;
com[8] = (byte)(address >> 8);
com[9] = (byte)(address & 0xFF);
com[10] = 0;
com[11] = (byte)(data.Length / 2);
SetHeader(com);
_NetworkStream.Write(com, 0, com.Length);
byte[] res = new byte[9 + data.Length];
int expectedSize = res.Length;
int size = _NetworkStream.Read(res, 0, res.Length);
Array.Resize(ref res, size);
ResponseErrorChecks(res, expectedSize, com);
Array.Copy(res, 9, data, 0, data.Length);
}
/// <summary>
/// Write an ushort array of data to the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The ushort array of data to write.</param>
public void Write(ushort address, ushort[] data)
{
if (data.Length > 127)
throw new Exception("Too many shorts. The maximum is 127.");
byte[] bytes = new byte[data.Length * 2];
for (int i = 0; i < data.Length; i++)
{
BitConverter.GetBytes(data[i]).CopyTo(bytes, i * 2);
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes, i * 2, 2);
}
Write(address, bytes);
}
/// <summary>
/// Read an ushort array of data from the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The read ushort array of data. The array length
/// is the amount of shorts to read.</param>
public void Read(ushort address, ushort[] data)
{
if (data.Length > 127)
throw new Exception("Too many shorts. The maximum is 127.");
byte[] bytes = new byte[data.Length * 2];
Read(address, bytes);
for (int i = 0; i < data.Length; i++)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes, i * 2, 2);
data[i] = BitConverter.ToUInt16(bytes, i * 2);
}
}
/// <summary>
/// Write an uint array of data to the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The uint array of data to write.</param>
public void Write(ushort address, uint[] data)
{
if (data.Length > 63)
throw new Exception("Too many uint. The maximum is 63.");
byte[] bytes = new byte[data.Length * 4];
for (int i = 0; i < data.Length; i++)
{
BitConverter.GetBytes(data[i]).CopyTo(bytes, i * 4);
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes, i * 4, 4);
}
Write(address, bytes);
}
/// <summary>
/// Read an uint array of data from the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The read uint array of data. The array length is
/// the amount of ints to read.</param>
public void Read(ushort address, uint[] data)
{
if (data.Length > 63)
throw new Exception("Too many ints. The maximum is 63.");
byte[] bytes = new byte[data.Length * 4];
Read(address, bytes);
for (int i = 0; i < data.Length; i++)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes, i * 4, 4);
data[i] = BitConverter.ToUInt32(bytes, i * 4);
}
}
/// <summary>
/// Write an int array of data to the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The int array of data to write.</param>
public void Write(ushort address, int[] data)
{
if (data.Length > 63)
throw new Exception("Too many ints. The maximum is 63.");
byte[] bytes = new byte[data.Length * 4];
for (int i = 0; i < data.Length; i++)
{
BitConverter.GetBytes(data[i]).CopyTo(bytes, i * 4);
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes, i * 4, 4);
}
Write(address, bytes);
}
/// <summary>
/// Read an int array of data from the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The read int array of data. The array length is
/// the amount of ints to read.</param>
public void Read(ushort address, int[] data)
{
if (data.Length > 63)
throw new Exception("Too many ints. The maximum is 63.");
byte[] bytes = new byte[data.Length * 4];
Read(address, bytes);
for (int i = 0; i < data.Length; i++)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes, i * 4, 4);
data[i] = BitConverter.ToInt32(bytes, i * 4);
}
}
/// <summary>
/// Write a float array of data to the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The float array of data to write.</param>
public void Write(ushort address, float[] data)
{
if (data.Length > 63)
throw new Exception("Too many floats. The maximum is 63.");
byte[] bytes = new byte[data.Length * 4];
for (int i = 0; i < data.Length; i++)
{
BitConverter.GetBytes(data[i]).CopyTo(bytes, i * 4);
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes, i * 4, 4);
}
Write(address, bytes);
}
/// <summary>
/// Reads a float array of data from the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The read float array of data. The array length is
/// the amount of floats to read.</param>
public void Read(ushort address, float[] data)
{
if (data.Length > 63)
throw new Exception("Too many floats. The maximum is 63.");
byte[] bytes = new byte[data.Length * 4];
Read(address, bytes);
for (int i = 0; i < data.Length; i++)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes, i * 4, 4);
data[i] = BitConverter.ToSingle(bytes, i * 4);
}
}
/// <summary>
/// Write a single ushort of data to the Modbus device.
/// </summary>
/// <param name="address">The register address.</param>
/// <param name="data">The ushort data to write.</param>
public void Write(ushort address, ushort data)
{
ushort[] dataArray = new ushort[1];
dataArray[0] = data;
Write(address, dataArray);
}
/// <summary>
/// Read a single ushort of data from the Modbus device.
/// </summary>
/// <param name="address">The register address.</param>
/// <param name="data">The read ushort data.</param>
public void Read(ushort address, ref ushort data)
{
ushort[] dataArray = new ushort[1];
Read(address, dataArray);
data = dataArray[0];
}
/// <summary>
/// Write a single uint of data to the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The uint data to write.</param>
public void Write(ushort address, uint data)
{
uint[] dataArray = new uint[1];
dataArray[0] = data;
Write(address, dataArray);
}
/// <summary>
/// Read a single uint of data from the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="value">The read uint data.</param>
public void Read(ushort address, ref uint data)
{
uint[] dataArray = new uint[1];
Read(address, dataArray);
data = dataArray[0];
}
/// <summary>
/// Write a single int of data to the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The int data to write.</param>
public void Write(ushort address, int data)
{
int[] dataArray = new int[1];
dataArray[0] = data;
Write(address, dataArray);
}
/// <summary>
/// Read a single int of data from the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The read int data.</param>
public void Read(ushort address, ref int data)
{
int[] dataArray = new int[1];
Read(address, dataArray);
data = dataArray[0];
}
/// <summary>
/// Write a single float of data to the Modbus device.
/// 1 uint = 2 registers.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The float data to write.</param>
public void Write(ushort address, float data)
{
float[] dataArray = new float[1];
dataArray[0] = data;
Write(address, dataArray);
}
/// <summary>
/// Read a single float of data from the Modbus device.
/// </summary>
/// <param name="address">The starting register address.</param>
/// <param name="data">The read float data.</param>
public void Read(ushort address, ref float data)
{
float[] dataArray = new float[1];
Read(address, dataArray);
data = dataArray[0];
}
/// <summary>
/// Sets the MBAP header of the Modbus TCP command.
/// </summary>
/// <param name="command">The byte array for the Modbus TCP command.
/// The Modbus request bytes 7+ need to be set beforehand. The MBAP
/// header bytes 0 to 6 will be updated based on the request bytes.
/// </param>
private void SetHeader(byte[] command)
{
//Transaction ID
ushort transID = _TransactionID;
if (_TransactionID >= 65535)
{
//Rollover global transaction ID to 0.
_TransactionID = 0;
}
else
{
//Increment global transaction ID.
_TransactionID++;
}
command[0] = (byte)(transID >> 8);
command[1] = (byte)(transID & 0xFF);
//Protocol ID
command[2] = 0;
command[3] = 0;
//Length
ushort length = (ushort)(command.Length - 6);
command[4] = (byte)(length >> 8);
command[5] = (byte)(length & 0xFF);
//Unit ID
command[6] = 1;
}
/// <summary>
/// Checks the Modbus response for errors.
/// </summary>
/// <param name="response">The Modbus response byte array.</param>
/// <param name="expectedSize">The expected response byte array length.</param>
/// <param name="command">The Modbus command byte array.</param>
private void ResponseErrorChecks(byte[] response, int expectedLength, byte[] command)
{
if (response.Length < expectedLength)
{
if (response.Length < 9)
{
throw new Exception("Invalid Modbus response.");
}
if ((response[7] & 0x80) > 0)
{
//Bit 7 set, indicating Modbus error
throw new Exception("Modbus exception code " + response[8] +
", " + GetExceptionCodeString(response[8]) + ".");
}
throw new Exception("Other Modbus response error.");
}
if (response[0] != command[0] || response[1] != command[1])
{
throw new Exception("Modbus transaction ID mismatch.");
}
}
/// <summary>
/// Get the Modbus exception name.
/// </summary>
/// <param name="code">The exception code.</param>
/// <returns>The exception name.</returns>
private string GetExceptionCodeString(uint code) =>
code switch
{
1 => "Illegal Function",
2 => "Illegal Data Address",
3 => "Illegal Data Value",
4 => "Slave Device Failure",
5 => "Acknowledge",
6 => "Slave Device Busy",
7 => "Negative Acknowledge",
8 => "Memory Parity Error",
10 => "Gateway Path Unavailable",
11 => "Gateway Target Device Failed to Respond",
_ => ""
};
void IDisposable.Dispose() =>
Close();
}
internal static bool ReadAll(AppSettings appSettings, ILogger<Worker> logger)
{
LabJackT7Configuration configuration = appSettings.LabJackT7Configuration;
_ModbusTransmissionControlProtocolClient ??= new(configuration.InternetProtocolAddress, configuration.Port);
ReadAllAnalog(_ModbusTransmissionControlProtocolClient, logger);
ReadAllDigitalIO(_ModbusTransmissionControlProtocolClient, logger);
if (configuration.InternetProtocolAddress == "false")
ReadAllAnalogMux80(_ModbusTransmissionControlProtocolClient, logger);
return true;
}
/// <summary>
/// Displays "AINxx : Values" readings.
/// </summary>
/// <param name="startingAddress">Starting Modbus address of
/// readings.</param>
/// <param name="values">Float analog input (AIN) readings.</param>
private static void DisplayAnalogInputReadings(ILogger<Worker> logger, ushort startingAddress, float[] values)
{
for (int i = 0; i < values.Length; i++)
{
logger.LogInformation("AIN" + (startingAddress + i * 2) / 2 + " : " + values[i] + " V");
}
}
/// <summary>
/// Displays all digital I/O readings.
/// </summary>
/// <param name="directions">Reading from T7 Modbus address
/// 2850 (DIO_DIRECTION).</param>
/// <param name="states">Reading from T7 Modbus address
/// 2800 (DIO_STATE).</param>
private static void DisplayDigitalIOReadings(ILogger<Worker> logger, uint directions, uint states)
{
string fioDirs = "";
string fioStates = "";
string eioDirs = "";
string eioStates = "";
string cioDirs = "";
string cioStates = "";
string mioDirs = "";
string mioStates = "";
for (int i = 0; i < 8; i++)
{
fioDirs += Convert.ToString((directions >> i) & 1);
fioStates += Convert.ToString((states >> i) & 1);
}
logger.LogInformation("FIO0-FIO7 directions = " + fioDirs + ", states = " + fioStates);
for (int i = 8; i < 16; i++)
{
eioDirs += Convert.ToString((directions >> i) & 1);
eioStates += Convert.ToString((states >> i) & 1);
}
logger.LogInformation("EIO0-EIO7 directions = " + eioDirs + ", states = " + eioStates);
for (int i = 16; i < 20; i++)
{
cioDirs += Convert.ToString((directions >> i) & 1);
cioStates += Convert.ToString((states >> i) & 1);
}
logger.LogInformation("CIO0-CIO3 directions = " + cioDirs + ", states = " + cioStates);
for (int i = 20; i < 23; i++)
{
mioDirs += Convert.ToString((directions >> i) & 1);
mioStates += Convert.ToString((states >> i) & 1);
}
logger.LogInformation("MIO0-MIO2 directions = " + mioDirs + ", states = " + mioStates);
}
/// <summary>
/// Configures range, negative channel, resolution index and settling
/// time for all analog inputs.
/// AIN_ALL_RANGE, AIN_ALL_NEGATIVE_CH, AIN_ALL_RESOLUTION_INDEX, and
/// AIN_ALL_SETTLING_US registers/settings are documented here:
/// https://labjack.com/support/datasheets/t-series/ain
/// </summary>
/// <param name="mb">The ModbusTransmissionControlProtocolClient to the connected T7 </param>
/// <param name="range">AIN_ALL_RANGE setting.</param>
/// <param name="negativeChannel">AIN_ALL_NEGATIVE_CH setting.</param>
/// <param name="resolutionIndex">AIN_ALL_RESOLUTION_INDEX setting.</param>
/// <param name="settling">AIN_ALL_SETTLING_US setting.</param>
private static void ConfigureAllAnalog(ModbusTransmissionControlProtocolClient mb, float range, ushort negativeChannel, ushort resolutionIndex, float settling)
{
ushort address;
ushort uint16Value;
float float32Value;
// Configure all analog input ranges.
address = 43900; // 43900 = AIN_ALL_RANGE
float32Value = range;
mb.Write(address, float32Value);
// Configure all analog input negative channels.
address = 43902; // 43902 = AIN_ALL_NEGATIVE_CH
uint16Value = negativeChannel;
mb.Write(address, uint16Value);
// Configure all analog input resolution indexes.
address = 43903; // 43903 = AIN_ALL_RESOLUTION_INDEX
uint16Value = resolutionIndex;
mb.Write(address, uint16Value);
// Configure all analog input settling times.
address = 43904; // 43904 = AIN_ALL_SETTLING_US
float32Value = settling;
mb.Write(address, float32Value);
}
/// <summary>
/// Example that configures, reads and displays all the analog
/// inputs (AIN0-AIN13) on the T7.
/// Analog inputs (AIN) registers used are documented here:
/// https://labjack.com/support/datasheets/t-series/ain
/// </summary>
/// <param name="mb">The ModbusTransmissionControlProtocolClient to the connected T7.</param>
private static void ReadAllAnalog(ModbusTransmissionControlProtocolClient modbusTransmissionControlProtocolClient, ILogger<Worker> logger)
{
logger.LogInformation("Reading AIN0-AIN13.");
// Configure all analog inputs.
// Ranges = +/-10 to.
// Negative Channels = 199 (single-ended)
// Resolution Indexes = 8
// Settlings = 0 (auto)
ConfigureAllAnalog(modbusTransmissionControlProtocolClient, 10.0f, 199, 8, 0);
// Read all 14 analog inputs.
ushort startAddress = 0; // 0 = AIN0
float[] analogInputReadings = new float[14]; // 14 analog input readings
modbusTransmissionControlProtocolClient.Read(startAddress, analogInputReadings);
DisplayAnalogInputReadings(logger, startAddress, analogInputReadings);
logger.LogInformation("");
}
/// <summary>
/// Example that reads and displays all the digital I/O (FIOs, EIOs,
/// CIOs, MIOs) on the T7.
/// Digital I/O registers used are documented here:
/// https://labjack.com/support/datasheets/t-series/digital-io
/// </summary>
/// <param name="modbusTransmissionControlProtocolClient">The ModbusTransmissionControlProtocolClient to the connected T7.</param>
private static void ReadAllDigitalIO(ModbusTransmissionControlProtocolClient modbusTransmissionControlProtocolClient, ILogger<Worker> logger)
{
logger.LogInformation("Reading FIOs, EIOs, CIOs and MIO directions and states.");
ushort address;
uint directions = 0;
uint states = 0;
// Read all digital I/O directions and states.
address = 2850; // 2850 = DIO_DIRECTION
modbusTransmissionControlProtocolClient.Read(address, ref directions);
address = 2800; // 2800 = DIO_STATE
modbusTransmissionControlProtocolClient.Read(address, ref states);
DisplayDigitalIOReadings(logger, directions, states);
logger.LogInformation("");
}
/// <summary>
/// Example that configures, reads and displays all the analog
/// inputs on the T7 with a Mux80 (AIN0-AIN3, AIN48-AIN127).
/// Analog inputs (AIN) registers used are documented here:
/// https://labjack.com/support/datasheets/t-series/ain
/// Extended channels AIN48+ are further documented here:
/// https://labjack.com/support/datasheets/t-series/ain/extended-channels
/// Mux80 data sheet can be found here:
/// https://labjack.com/support/datasheets/accessories/mux80
/// </summary>
/// <param name="modbusTransmissionControlProtocolClient">The ModbusTransmissionControlProtocolClient to the connected T7.</param>
private static void ReadAllAnalogMux80(ModbusTransmissionControlProtocolClient modbusTransmissionControlProtocolClient, ILogger<Worker> logger)
{
// Many registers to channels are incorrect. Check with Steve.
logger.LogInformation("Reading AIN0-AIN3, AIN48-AIN127.");
// Configure all analog inputs.
// Ranges = +/-10 to.
// Negative Channels = 199 (single-ended)
// Resolution Indexes = 1
// Settlings = 0 (auto)
ConfigureAllAnalog(modbusTransmissionControlProtocolClient, 10.0f, 199, 1, 0);
//Reading from 84 analog inputs with the Mux80.
ushort startAddress;
float[] analogInputReadings;
// Read from AIN0-AIN3 on the T7 terminals.
startAddress = 0; // 0 = AIN0
analogInputReadings = new float[4]; // 4 analog input readings.
modbusTransmissionControlProtocolClient.Read(startAddress, analogInputReadings);
DisplayAnalogInputReadings(logger, startAddress, analogInputReadings);
// Read from AIN48-AIN87 on Mux80.
startAddress = 96; // 96 = AIN48
analogInputReadings = new float[40]; // 40 analog input readings
modbusTransmissionControlProtocolClient.Read(startAddress, analogInputReadings);
DisplayAnalogInputReadings(logger, startAddress, analogInputReadings);
// Read from AIN88-AIN127 on Mux80.
startAddress = 176; // 176 = AIN88
analogInputReadings = new float[40]; // 40 analog input readings
modbusTransmissionControlProtocolClient.Read(startAddress, analogInputReadings);
DisplayAnalogInputReadings(logger, startAddress, analogInputReadings);
logger.LogInformation("");
}
}

View File

@ -0,0 +1,75 @@
using File_Watcher.Models;
using Helpers.DAQmx;
namespace File_Watcher.Helpers;
internal static partial class NationalInstrumentsHelper
{
private static Dictionary<string, DAQmxTask>? _DataAcquisitionTasks = null;
internal static bool WriteData(AppSettings appSettings, ILogger<Worker> logger)
{
double value;
LogNetToHoursSince(logger);
if (_DataAcquisitionTasks is null)
{
string name;
_DataAcquisitionTasks = [];
DAQmxTask dataAcquisitionTask;
const DAQmxUnits volts = DAQmxUnits.Volts;
NationalInstrumentsConfiguration ni = appSettings.NationalInstrumentsConfiguration;
const DAQmxInputTerminalConfiguration differential = DAQmxInputTerminalConfiguration.Differential;
const DAQmxInputTerminalConfiguration referencedSingleEnded = DAQmxInputTerminalConfiguration.ReferencedSingleEnded;
foreach (string physicalChannel in appSettings.NationalInstrumentsConfiguration.DifferentialPhysicalChannels.Distinct())
{
name = !physicalChannel.Contains('/') ? physicalChannel : physicalChannel.Split('/')[1];
dataAcquisitionTask = DAQmxTask.Create(name);
dataAcquisitionTask.CreateAnalogInputVoltageChannel(physicalChannel, name, differential, ni.MiniumValue, ni.MaximumValue, volts, ni.CustomScaleName);
_DataAcquisitionTasks.Add(name, dataAcquisitionTask);
}
foreach (string physicalChannel in appSettings.NationalInstrumentsConfiguration.ReferencedSingleEndedPhysicalChannels.Distinct())
{
name = !physicalChannel.Contains('/') ? physicalChannel : physicalChannel.Split('/')[1];
dataAcquisitionTask = DAQmxTask.Create(name);
dataAcquisitionTask.CreateAnalogInputVoltageChannel(physicalChannel, name, referencedSingleEnded, ni.MiniumValue, ni.MaximumValue, volts, ni.CustomScaleName);
_DataAcquisitionTasks.Add(name, dataAcquisitionTask);
}
}
foreach (KeyValuePair<string, DAQmxTask> keyValuePair in _DataAcquisitionTasks)
{
if (appSettings.NationalInstrumentsConfiguration.UsePointerMethod)
throw new NotSupportedException("Pointer method is not supported in this implementation.");
value = keyValuePair.Value.ReadAnalogScalarF64(appSettings.NationalInstrumentsConfiguration.ReadTimeout);
logger.LogInformation("{key}-{read}: {value}", keyValuePair.Key, keyValuePair.Value.TotalSamplesRead, value);
}
return true;
}
private static void LogNetToHoursSince(ILogger<Worker>? logger)
{
double secondsInAHour = 3600f;
long epoch = new DateTime(1970, 1, 1).Ticks;
long net8ReleaseDate = new DateTime(2023, 11, 14).Ticks;
long net9ReleaseDate = new DateTime(2024, 11, 12).Ticks;
long net10ReleaseDate = new DateTime(2026, 01, 01).Ticks;
long framework48ReleaseDate = new DateTime(2019, 04, 18).Ticks;
double net8TotalSeconds = new TimeSpan(net8ReleaseDate - epoch).TotalSeconds;
double net9TotalSeconds = new TimeSpan(net9ReleaseDate - epoch).TotalSeconds;
double net10TotalSeconds = new TimeSpan(net10ReleaseDate - epoch).TotalSeconds;
double framework48TotalSeconds = new TimeSpan(framework48ReleaseDate - epoch).TotalSeconds;
logger?.LogInformation("It has been {net8TotalSeconds} seconds since net8 was released", net8TotalSeconds);
logger?.LogInformation("It has been {net9TotalSeconds} seconds since net9 was released", net9TotalSeconds);
logger?.LogInformation("It has been {net10TotalSeconds} seconds since net10 was released", net10TotalSeconds);
logger?.LogInformation("It has been {framework48TotalSeconds} seconds since framework48 was released", framework48TotalSeconds);
double net8TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net8TotalSeconds) / secondsInAHour);
double net9TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net9TotalSeconds) / secondsInAHour);
double net10TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net10TotalSeconds) / secondsInAHour);
double framework48TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - framework48TotalSeconds) / secondsInAHour);
logger?.LogInformation("It has been {net8TotalHours} hours since net8 was released", net8TotalHours);
logger?.LogInformation("It has been {net9TotalHours} hours since net9 was released", net9TotalHours);
logger?.LogInformation("It has been {net10TotalHours} hours since net10 was released", net10TotalHours);
logger?.LogInformation("It has been {framework48TotalHours} hours since framework48 was released", framework48TotalHours);
}
}

45
Helpers/SeleniumHelper.cs Normal file
View File

@ -0,0 +1,45 @@
using File_Watcher.Models;
#if Selenium
using OpenQA.Selenium;
using OpenQA.Selenium.Edge;
#endif
namespace File_Watcher.Helpers;
internal static partial class SeleniumHelper
{
// <PackageReference Include="Selenium.WebDriver" Version="4.31.0" />
// <PackageReference Include="Selenium.WebDriver.MSEdgeDriver" Version="135.0.3179.85" />
internal static bool HyperTextMarkupLanguageToPortableNetworkGraphics(AppSettings appSettings, ILogger<Worker> logger)
{
if (!string.IsNullOrEmpty(appSettings.SeleniumConfiguration.UniformResourceLocator))
logger.LogInformation("This helper is disabled!");
#if Selenium
EdgeOptions edgeOptions = new();
foreach (string edgeOption in appSettings.SeleniumConfiguration.EdgeOptions)
edgeOptions.AddArgument(edgeOption);
EdgeDriver edgeDriver = new(edgeOptions);
string outputFile = Path.Combine(appSettings.SeleniumConfiguration.DestinationDirectory, $"{DateTime.Now:yyyy-MM-dd;HH-mi-ss-fff}.png");
try
{
edgeDriver.Navigate().GoToUrl(appSettings.SeleniumConfiguration.UniformResourceLocator);
#pragma warning disable CS8602, CS8604
int fullWidth = int.Parse(edgeDriver.ExecuteScript("return document.body.parentNode.scrollWidth").ToString());
int fullHeight = int.Parse(edgeDriver.ExecuteScript("return document.body.parentNode.scrollHeight").ToString());
#pragma warning restore CS8602, CS8604
edgeDriver.Manage().Window.Size = new(fullWidth, fullHeight);
Screenshot screenshot = edgeDriver.GetScreenshot();
screenshot.SaveAsFile(outputFile);
}
catch (Exception ex)
{
logger.LogError(ex, ex.Message);
}
edgeDriver.Close();
#endif
return true;
}
}

51
Helpers/SyncHelper.cs Normal file
View File

@ -0,0 +1,51 @@
using File_Watcher.Models;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Watcher.Helpers;
internal static partial class SyncHelper
{
private record Record(string RelativePath,
long Size,
long Ticks);
private record RelativePath(string Path,
Record[] Records);
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(RelativePath))]
private partial class RelativePathSourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Dictionary<string, object>))]
private partial class DictionaryStringObjectBSourceGenerationContext : JsonSerializerContext
{
}
internal static bool Check(AppSettings _, ILogger<Worker> __) =>
true;
internal static string GetReply(string body, Dictionary<string, object> keyValuePairs)
{
string? json;
RelativePath? relativePath;
if (!string.IsNullOrEmpty(body) && body[0] == '{')
{
File.WriteAllText(".json", body);
relativePath = JsonSerializer.Deserialize(body, RelativePathSourceGenerationContext.Default.RelativePath) ?? throw new NullReferenceException();
}
else
{
json = JsonSerializer.Serialize(keyValuePairs, DictionaryStringObjectBSourceGenerationContext.Default.DictionaryStringObject);
File.WriteAllText(".json", json);
relativePath = JsonSerializer.Deserialize(json, RelativePathSourceGenerationContext.Default.RelativePath) ?? throw new NullReferenceException();
}
if (relativePath is null)
{ }
return $"wait-{relativePath?.Records.Length}";
}
}

View File

@ -0,0 +1,129 @@
using File_Watcher.Models;
using System.Net.Sockets;
using System.Text;
namespace File_Watcher.Helpers;
internal static partial class TransmissionControlProtocolHelper
{
private record Record(BinaryReader BinaryReader,
BinaryWriter BinaryWriter,
NetworkStream NetworkStream,
List<long> ReadTimes);
private static long _LastWrite;
private static Record? _Record;
private static readonly object _Lock = new();
private static void ReadFiles(TransmissionControlProtocolConfiguration tcpConfiguration, ILogger<Worker> logger)
{
List<byte> bytes = [];
// byte nullByte = Convert.ToByte('\0');
string directory = GetDirectory(tcpConfiguration);
string[] files = Directory.GetFiles(directory, $"{tcpConfiguration.IPAddress}-*.raw", SearchOption.TopDirectoryOnly);
logger.LogInformation("Read {count} files", files.Length);
foreach (string file in files)
{
foreach (byte @byte in File.ReadAllBytes(file))
{
// if (@byte.Equals(nullByte))
// continue;
bytes.Add(@byte);
}
}
if (bytes.Count > 0)
{
string bytesFile = Path.Combine(directory, $"{tcpConfiguration.IPAddress}-{DateTime.Now.Ticks}.pcl");
File.WriteAllBytes(bytesFile, bytes.ToArray());
foreach (string file in files)
File.Delete(file);
}
}
private static void CreateClient(AppSettings appSettings, ILogger<Worker> logger)
{
logger.LogDebug(appSettings.TransmissionControlProtocolConfiguration.IPAddress);
TcpClient tcpClient = new(appSettings.TransmissionControlProtocolConfiguration.IPAddress, appSettings.TransmissionControlProtocolConfiguration.Port);
NetworkStream networkStream = tcpClient.GetStream();
_Record = new(BinaryReader: new(networkStream), BinaryWriter: new(networkStream), NetworkStream: networkStream, ReadTimes: []);
}
private static string GetDirectory(TransmissionControlProtocolConfiguration tcpConfiguration)
{
string result = Path.GetFullPath(Path.Combine(tcpConfiguration.Destination, tcpConfiguration.IPAddress));
if (!Directory.Exists(result))
_ = Directory.CreateDirectory(result);
return result;
}
private static void NetworkStreamCanRead(TransmissionControlProtocolConfiguration tcpConfiguration, ILogger<Worker> logger, NetworkStream networkStream)
{
List<byte> results = [];
byte[] bytes = new byte[1024];
string directory = GetDirectory(tcpConfiguration);
do
{
int count = networkStream.Read(bytes, 0, bytes.Length);
if (count > 0)
results.AddRange(bytes.Take(count));
}
while (networkStream.DataAvailable);
logger.LogInformation("Read {count} bytes", results.Count);
if (results.Count > 0)
{
bytes = results.ToArray();
File.WriteAllBytes(Path.Combine(directory, $"{tcpConfiguration.IPAddress}-{DateTime.Now.Ticks}.raw"), bytes);
if (!string.IsNullOrEmpty(tcpConfiguration.DelimiterPattern))
{
string content = Encoding.ASCII.GetString(bytes);
logger.LogDebug("Content {content}", content);
if (content.Contains(tcpConfiguration.DelimiterPattern))
ReadFiles(tcpConfiguration, logger);
}
}
}
internal static bool ReadWrite(AppSettings appSettings, ILogger<Worker> logger)
{
lock (_Lock)
{
if (!appSettings.TransmissionControlProtocolConfiguration.Server && _Record is not null && appSettings.TransmissionControlProtocolConfiguration.DelimiterSeconds > 0)
{
TimeSpan? timeSpan = _Record.ReadTimes.Count == 0 ? null : new(DateTime.Now.Ticks - _Record.ReadTimes[^1]);
if (timeSpan is not null && timeSpan.Value.TotalSeconds > appSettings.TransmissionControlProtocolConfiguration.DelimiterSeconds)
{
ReadFiles(appSettings.TransmissionControlProtocolConfiguration, logger);
_Record.ReadTimes.Clear();
}
}
if (!appSettings.TransmissionControlProtocolConfiguration.Server && _Record is not null)
{
TimeSpan timeSpan = new(DateTime.Now.Ticks - _LastWrite);
if (_LastWrite == 0 || timeSpan.TotalMinutes > 1)
{
try
{
_Record.NetworkStream.WriteByte(Convert.ToByte('\0'));
_LastWrite = DateTime.Now.Ticks;
}
catch (Exception)
{ }
}
}
if (!appSettings.TransmissionControlProtocolConfiguration.Server && (_Record?.NetworkStream is null || !_Record.NetworkStream.Socket.Connected))
CreateClient(appSettings, logger);
else if (appSettings.TransmissionControlProtocolConfiguration.Server)
throw new NotImplementedException($"Use {nameof(HelperTCP)}");
if (_Record?.NetworkStream is not null && _Record.NetworkStream.CanRead && _Record.NetworkStream.DataAvailable)
{
_Record.ReadTimes.Add(DateTime.Now.Ticks);
NetworkStreamCanRead(appSettings.TransmissionControlProtocolConfiguration, logger, _Record.NetworkStream);
}
if (appSettings.TransmissionControlProtocolConfiguration.Server && _Record?.NetworkStream is not null && _Record.NetworkStream.CanWrite)
throw new NotImplementedException($"Use {nameof(HelperTCP)}");
}
return true;
}
}

View File

@ -1,24 +1,30 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using View_by_Distance.Shared.Models;
using Phares.Shared.Models;
namespace File_Watcher.Models;
public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
CompassConfiguration CompassConfiguration,
DeterministicHashCodeConfiguration DeterministicHashCodeConfiguration,
DiskInfoConfiguration DiskInfoConfiguration,
DriveConfiguration DriveConfiguration,
EAFLogConfiguration EAFLogConfiguration,
EDADatabaseConfiguration EDADatabaseConfiguration,
FileWatcherConfiguration FileWatcherConfiguration,
InfinityQSConfiguration InfinityQSConfiguration,
InfinityQSProjectConfiguration InfinityQSProjectConfiguration,
IsoConfiguration IsoConfiguration,
LabJackT7Configuration LabJackT7Configuration,
MetadataSettings MetadataSettings,
MetrologyConfiguration MetrologyConfiguration,
NationalInstrumentsConfiguration NationalInstrumentsConfiguration,
NugetConfiguration NugetConfiguration,
ResultSettings ResultSettings,
SeleniumConfiguration SeleniumConfiguration,
SerialConfiguration SerialConfiguration,
StratusConfiguration StratusConfiguration,
SyncConfiguration SyncConfiguration,
TransmissionControlProtocolConfiguration TransmissionControlProtocolConfiguration,
WaferCounterConfiguration WaferCounterConfiguration)
{
@ -30,36 +36,48 @@ public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
CamstarOracleConfiguration? camstarOracleConfiguration = configurationRoot.GetSection(nameof(CamstarOracleConfiguration)).Get<CamstarOracleConfiguration>();
CompassConfiguration? compassConfiguration = configurationRoot.GetSection(nameof(CompassConfiguration)).Get<CompassConfiguration>();
DeterministicHashCodeConfiguration? deterministicHashCodeConfiguration = configurationRoot.GetSection(nameof(DeterministicHashCodeConfiguration)).Get<DeterministicHashCodeConfiguration>();
DiskInfoConfiguration? diskInfoConfiguration = configurationRoot.GetSection(nameof(DiskInfoConfiguration)).Get<DiskInfoConfiguration>();
DriveConfiguration? driveConfiguration = configurationRoot.GetSection(nameof(DriveConfiguration)).Get<DriveConfiguration>();
EAFLogConfiguration? eafLogConfiguration = configurationRoot.GetSection(nameof(EAFLogConfiguration)).Get<EAFLogConfiguration>();
EDADatabaseConfiguration? edaDatabaseConfiguration = configurationRoot.GetSection(nameof(EDADatabaseConfiguration)).Get<EDADatabaseConfiguration>();
FileWatcherConfiguration? fileWatcherConfiguration = configurationRoot.GetSection(nameof(FileWatcherConfiguration)).Get<FileWatcherConfiguration>();
InfinityQSConfiguration? infinityQSConfiguration = configurationRoot.GetSection(nameof(InfinityQSConfiguration)).Get<InfinityQSConfiguration>();
InfinityQSProjectConfiguration? infinityQSProjectConfiguration = configurationRoot.GetSection(nameof(InfinityQSProjectConfiguration)).Get<InfinityQSProjectConfiguration>();
IsoConfiguration? isoConfiguration = configurationRoot.GetSection(nameof(IsoConfiguration)).Get<IsoConfiguration>();
LabJackT7Configuration? labJackT7Configuration = configurationRoot.GetSection(nameof(LabJackT7Configuration)).Get<LabJackT7Configuration>();
MetadataSettings? metadataSettings = configurationRoot.GetSection(nameof(MetadataSettings)).Get<MetadataSettings>();
MetrologyConfiguration? metrologyConfiguration = configurationRoot.GetSection(nameof(MetrologyConfiguration)).Get<MetrologyConfiguration>();
NationalInstrumentsConfiguration? nationalInstrumentsConfiguration = configurationRoot.GetSection(nameof(NationalInstrumentsConfiguration)).Get<NationalInstrumentsConfiguration>();
NugetConfiguration? nugetConfiguration = configurationRoot.GetSection(nameof(NugetConfiguration)).Get<NugetConfiguration>();
ResultSettings? resultSettings = configurationRoot.GetSection(nameof(ResultSettings)).Get<ResultSettings>();
SeleniumConfiguration? seleniumConfiguration = configurationRoot.GetSection(nameof(SeleniumConfiguration)).Get<SeleniumConfiguration>();
SerialConfiguration? serialConfiguration = configurationRoot.GetSection(nameof(SerialConfiguration)).Get<SerialConfiguration>();
StratusConfiguration? stratusConfiguration = configurationRoot.GetSection(nameof(StratusConfiguration)).Get<StratusConfiguration>();
SyncConfiguration? syncConfiguration = configurationRoot.GetSection(nameof(SyncConfiguration)).Get<SyncConfiguration>();
TransmissionControlProtocolConfiguration? transmissionControlProtocolConfiguration = configurationRoot.GetSection(nameof(TransmissionControlProtocolConfiguration)).Get<TransmissionControlProtocolConfiguration>();
WaferCounterConfiguration? waferCounterConfiguration = configurationRoot.GetSection(nameof(WaferCounterConfiguration)).Get<WaferCounterConfiguration>();
#pragma warning restore IL3050, IL2026
if (camstarOracleConfiguration is null
|| compassConfiguration is null
|| deterministicHashCodeConfiguration is null
|| diskInfoConfiguration is null
|| driveConfiguration is null
|| eafLogConfiguration is null
|| edaDatabaseConfiguration is null
|| fileWatcherConfiguration is null
|| infinityQSConfiguration is null
|| infinityQSProjectConfiguration is null
|| isoConfiguration is null
|| labJackT7Configuration is null
|| metadataSettings is null
|| metrologyConfiguration is null
|| nationalInstrumentsConfiguration is null
|| nugetConfiguration is null
|| resultSettings is null
|| seleniumConfiguration is null
|| serialConfiguration is null
|| stratusConfiguration is null
|| syncConfiguration is null
|| transmissionControlProtocolConfiguration is null
|| waferCounterConfiguration is null
|| fileWatcherConfiguration?.Company is null)
@ -78,18 +96,24 @@ public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
result = new(camstarOracleConfiguration,
compassConfiguration,
deterministicHashCodeConfiguration,
diskInfoConfiguration,
driveConfiguration,
eafLogConfiguration,
edaDatabaseConfiguration,
fileWatcherConfiguration,
infinityQSConfiguration,
infinityQSProjectConfiguration,
isoConfiguration,
labJackT7Configuration,
metadataSettings,
metrologyConfiguration,
nationalInstrumentsConfiguration,
nugetConfiguration,
resultSettings,
seleniumConfiguration,
serialConfiguration,
stratusConfiguration,
syncConfiguration,
transmissionControlProtocolConfiguration,
waferCounterConfiguration);
Verify(result);

View File

@ -0,0 +1,24 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Watcher.Models;
public record DiskInfoConfiguration(int Bars,
string[] Classes,
string Destination,
decimal Max)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, DiskInfoConfigurationSourceGenerationContext.Default.DiskInfoConfiguration);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(DiskInfoConfiguration))]
internal partial class DiskInfoConfigurationSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -3,17 +3,9 @@ using System.Text.Json.Serialization;
namespace File_Watcher.Models;
public record Test(string Name,
long Value);
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Test[]))]
internal partial class TestCollectionSourceGenerationContext : JsonSerializerContext
{
}
public record InfinityQSConfiguration(string ConnectionString,
string DestinationDirectory,
string EncryptedPassword,
long SubGroupTime,
string TestsFile,
Test[] Tests)

View File

@ -0,0 +1,28 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Watcher.Models;
public record InfinityQSProjectConfiguration(string From,
int ClearEveryHours,
string Search,
string SearchPattern,
string SimpleMailTransferProtocolServer,
string SourceDirectory,
string Subject,
string To)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, InfinityQSProjectConfigurationSourceGenerationContext.Default.InfinityQSProjectConfiguration);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(InfinityQSProjectConfiguration))]
internal partial class InfinityQSProjectConfigurationSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,23 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Watcher.Models;
public record LabJackT7Configuration(string InternetProtocolAddress,
int Port,
string To)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, LabJackT7ConfigurationSourceGenerationContext.Default.LabJackT7Configuration);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(LabJackT7Configuration))]
internal partial class LabJackT7ConfigurationSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,27 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Watcher.Models;
public record NationalInstrumentsConfiguration(string CustomScaleName,
string[] DifferentialPhysicalChannels,
int MaximumValue,
int MiniumValue,
string[] ReferencedSingleEndedPhysicalChannels,
int ReadTimeout,
bool UsePointerMethod)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, NationalInstrumentsConfigurationSourceGenerationContext.Default.NationalInstrumentsConfiguration);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(NationalInstrumentsConfiguration))]
internal partial class NationalInstrumentsConfigurationSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,23 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Watcher.Models;
public record SeleniumConfiguration(string DestinationDirectory,
string[] EdgeOptions,
string UniformResourceLocator)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, SeleniumConfigurationSourceGenerationContext.Default.SeleniumConfiguration);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(SeleniumConfiguration))]
internal partial class SeleniumConfigurationSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,21 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Watcher.Models;
public record SyncConfiguration(string UniformResourceLocator)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, SyncConfigurationSourceGenerationContext.Default.SyncConfiguration);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(SyncConfiguration))]
internal partial class SyncConfigurationSourceGenerationContext : JsonSerializerContext
{
}

12
Models/Test.cs Normal file
View File

@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
namespace File_Watcher.Models;
public record Test(string Name,
long Value);
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Test[]))]
internal partial class TestCollectionSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -3,7 +3,9 @@ using System.Text.Json.Serialization;
namespace File_Watcher.Models;
public record TransmissionControlProtocolConfiguration(string Destination,
public record TransmissionControlProtocolConfiguration(string DelimiterPattern,
int DelimiterSeconds,
string Destination,
string GhostPCLFileName,
string IPAddress,
int Port,

View File

@ -0,0 +1,55 @@
#if Nancy
using Nancy;
using Nancy.Extensions;
namespace File_Watcher.NancyModules;
public class SyncModule : NancyModule
{
public SyncModule()
{
Get("/bob/v1/sync/", _ =>
{
string? result;
try
{
string query = Request.Url.Query;
IDictionary<string, IEnumerable<string>> collection = Nancy.Helpers.HttpUtility.ParseQueryString(query).ToDictionary();
result = collection is null ? "null" : collection.ToString();
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
});
Post("/bob/v1/sync/", _ =>
{
string result;
// Notification notification;
// ILog log = LogManager.GetLogger(typeof(SyncModule));
// log.Info($"Enter-{nameof(Post)}");
try
{
string body = Request.Body.AsString();
DynamicDictionary form = Request.Form;
Dictionary<string, object> keyValuePairs = form.ToDictionary();
string reply = Helpers.SyncHelper.GetReply(body, keyValuePairs);
result = reply;
}
catch (Exception ex)
{
// log.Fatal($"Exception-{nameof(Post)}{Environment.NewLine}{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}");
result = ex.Message;
throw;
}
// log.Info($"Return-{nameof(Post)}");
return result;
});
}
}
#endif

23
Startup.cs Normal file
View File

@ -0,0 +1,23 @@
#if Nancy
using Microsoft.Owin.Cors;
using Nancy.Owin;
using Owin;
namespace File_Watcher;
public class Startup
{
public Startup()
{ }
public void Configuration(IAppBuilder app)
{
_ = app.UseCors(CorsOptions.AllowAll);
_ = app.UseNancy();
}
}
#endif

View File

@ -1,4 +1,4 @@
using File_Watcher.Models;
using File_Watcher.Models;
using Microsoft.Extensions.Hosting.WindowsServices;
using System.Data;
@ -7,7 +7,6 @@ namespace File_Watcher;
public partial class Worker : BackgroundService
{
private bool? _First;
private readonly bool _IsWindowsService;
private readonly ILogger<Worker> _Logger;
private readonly AppSettings _AppSettings;
@ -22,8 +21,14 @@ public partial class Worker : BackgroundService
try
{ logger.LogInformation("<{folder}>", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)); }
catch (Exception) { }
_First = null;
_IsWindowsService = collection.Contains(nameof(WindowsServiceLifetime));
if (appSettings.FileWatcherConfiguration.Helper == nameof(Helpers.SyncHelper))
{
#if Nancy
_ = Microsoft.Owin.Hosting.WebApp.Start<Startup>(appSettings.SyncConfiguration.UniformResourceLocator);
#endif
logger.LogInformation("Server running on {url}", appSettings.SyncConfiguration.UniformResourceLocator);
}
}
public override Task StopAsync(CancellationToken cancellationToken)
@ -35,11 +40,13 @@ public partial class Worker : BackgroundService
protected override async Task ExecuteAsync(CancellationToken cancellationToken) =>
await Body(cancellationToken);
private async Task Body(CancellationToken cancellationToken)
{
if (!_IsWindowsService)
{
_Logger.LogInformation("Set break point and skip to run {_AppSettings.FileWatcherConfiguration.Helper}!", _AppSettings.FileWatcherConfiguration.Helper);
BodyInner(cancellationToken);
throw new EvaluateException($"Set break point and skip to run {_AppSettings.FileWatcherConfiguration.Helper}!");
}
if (!_IsWindowsService)
@ -52,40 +59,47 @@ public partial class Worker : BackgroundService
}
while (_IsWindowsService && !cancellationToken.IsCancellationRequested)
{
BodyInner(cancellationToken);
await Task.Delay(_AppSettings.FileWatcherConfiguration.MillisecondsDelay, cancellationToken);
try
{
BodyInner(cancellationToken);
await Task.Delay(_AppSettings.FileWatcherConfiguration.MillisecondsDelay, cancellationToken);
}
catch (Exception ex) { _Logger.LogError(ex, "Unexpected Error!"); }
}
}
private void BodyInner(CancellationToken cancellationToken)
{
_Logger.LogInformation("A) Next execute will be at {date}", DateTime.Now.AddMilliseconds(_AppSettings.FileWatcherConfiguration.MillisecondsDelay).ToString("yyyy-MM-dd hh:mm:ss.fff tt"));
if (_First is null || _First.Value)
{
_First = false;
if (_AppSettings.FileWatcherConfiguration.Helper == nameof(Helpers.HelperCamstarOracle))
Helpers.HelperCamstarOracle.Heartbeat(_AppSettings, _HttpClientFactory, _Logger, Infineon.Monitoring.MonA.State.Up, cancellationToken);
}
if (!Directory.Exists(_AppSettings.FileWatcherConfiguration.WatchDirectory))
_ = Directory.CreateDirectory(_AppSettings.FileWatcherConfiguration.WatchDirectory);
else
{
_ = _AppSettings.FileWatcherConfiguration.Helper switch
{
nameof(Helpers.SyncHelper) => Helpers.SyncHelper.Check(_AppSettings, _Logger),
nameof(Helpers.HelperNuget) => Helpers.HelperNuget.Sync(_AppSettings, _Logger),
nameof(Helpers.HelperTCP) => Helpers.HelperTCP.ReadWrite(_AppSettings, _Logger),
nameof(Helpers.HelperISO) => Helpers.HelperISO.DirectoryToISO(_AppSettings, _Logger),
nameof(Helpers.HelperCompass) => Helpers.HelperCompass.CopyFile(_AppSettings, _Logger),
nameof(Helpers.HelperStratus) => Helpers.HelperStratus.MoveFile(_AppSettings, _Logger),
nameof(Helpers.HelperEAFLog) => Helpers.HelperEAFLog.DeleteFiles(_AppSettings, _Logger),
nameof(Helpers.HelperInfinityQS) => Helpers.HelperInfinityQS.Select(_AppSettings, _Logger),
nameof(Helpers.LabJackT7Helper) => Helpers.LabJackT7Helper.ReadAll(_AppSettings, _Logger),
nameof(Helpers.DiskInfoHelper) => Helpers.DiskInfoHelper.WriteDiskInfo(_AppSettings, _Logger),
nameof(Helpers.HelperEventLog) => Helpers.HelperEventLog.ClearEventLogs(_AppSettings, _Logger),
nameof(Helpers.HelperInfinityQS) => Helpers.HelperInfinityQS.ProcessStart(_AppSettings, _Logger),
nameof(Helpers.HelperWaferCounter) => Helpers.HelperWaferCounter.MoveFile(_AppSettings, _Logger),
nameof(Helpers.HelperSerial) => Helpers.HelperSerial.ReadWrite(_AppSettings, _Logger, cancellationToken),
nameof(Helpers.HelperMetrologyFiles) => Helpers.HelperMetrologyFiles.SortAndDelete(_AppSettings, _Logger),
nameof(Helpers.HelperCamstarOracle) => Helpers.HelperCamstarOracle.Check(_AppSettings, _Logger, cancellationToken),
nameof(Helpers.InfinityQSProjectHelper) => Helpers.InfinityQSProjectHelper.SendEmail(_AppSettings, _Logger),
nameof(Helpers.NationalInstrumentsHelper) => Helpers.NationalInstrumentsHelper.WriteData(_AppSettings, _Logger),
nameof(Helpers.DeterministicHashCodeHelper) => Helpers.DeterministicHashCodeHelper.WindowsWork(_AppSettings, _Logger),
nameof(Helpers.TransmissionControlProtocolHelper) => Helpers.TransmissionControlProtocolHelper.ReadWrite(_AppSettings, _Logger),
#if Selenium
nameof(Helpers.SeleniumHelper) => Helpers.SeleniumHelper.HyperTextMarkupLanguageToPortableNetworkGraphics(_AppSettings, _Logger),
#endif
nameof(Helpers.HelperEDADatabase) => Helpers.HelperEDADatabase.SaveDataCollectionPlans(_AppSettings, _Logger, cancellationToken),
nameof(Helpers.HelperCamstarOracle) => Helpers.HelperCamstarOracle.Check(_AppSettings, _HttpClientFactory, _Logger, cancellationToken),
_ => throw new NotSupportedException()
};
}