2 Commits

Author SHA1 Message Date
f41583c533 national-instruments-helper-linux 2025-08-18 12:46:31 -07:00
5671959051 national-instruments-helper 2025-08-18 12:42:27 -07:00
35 changed files with 1124 additions and 34 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.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.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.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.IDE0010.severity = none # Add missing cases to switch statement (IDE0010)
dotnet_diagnostic.IDE0028.severity = error # IDE0028: Collection initialization can be simplified dotnet_diagnostic.IDE0028.severity = error # IDE0028: Collection initialization can be simplified
dotnet_diagnostic.IDE0031.severity = warning # Use null propagation (IDE0031) dotnet_diagnostic.IDE0031.severity = warning # Use null propagation (IDE0031)

4
.vscode/launch.json vendored
View File

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

View File

@ -42,6 +42,7 @@
"PDSF", "PDSF",
"pged", "pged",
"Phares", "Phares",
"Pinnable",
"Rijndael", "Rijndael",
"Serilog", "Serilog",
"SUBM", "SUBM",

22
.vscode/tasks.json vendored
View File

@ -7,8 +7,6 @@
"type": "process", "type": "process",
"args": [ "args": [
"user-secrets", "user-secrets",
"-p",
"${workspaceFolder}/File-Watcher.csproj",
"init" "init"
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
@ -19,8 +17,6 @@
"type": "process", "type": "process",
"args": [ "args": [
"user-secrets", "user-secrets",
"-p",
"${workspaceFolder}/File-Watcher.csproj",
"set", "set",
"_UserSecretsId", "_UserSecretsId",
"6516d19d6569" "6516d19d6569"
@ -43,19 +39,16 @@
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "build", "label": "Build",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
"build", "build"
"${workspaceFolder}/File-Watcher.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Format-Whitespaces", "label": "Format Whitespaces",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
@ -71,20 +64,17 @@
"args": [ "args": [
"publish", "publish",
"-r", "-r",
"win-x64", "linux-x64",
"-c", "-c",
"Release", "Release",
"-p:PublishAot=true", "-p:PublishAot=true"
"${workspaceFolder}/File-Watcher.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20", "label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20",
"type": "shell", "type": "shell",
"command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe", "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/linux-x64/publish/File-Folder-Helper.exe",
"args": [ "args": [
"s", "s",
"X", "X",

View File

@ -3,8 +3,9 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<UserSecretsIdBeforeOracle>b6f34b8e-5026-41d4-9c28-6516d19d6569</UserSecretsIdBeforeOracle> <UserSecretsIdBeforeOracle>b6f34b8e-5026-41d4-9c28-6516d19d6569</UserSecretsIdBeforeOracle>
<UserSecretsId>6062c774-99a9-4f4a-b42d-a9cb7fcbd8be</UserSecretsId> <UserSecretsId>6062c774-99a9-4f4a-b42d-a9cb7fcbd8be</UserSecretsId>
@ -12,11 +13,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CliWrap" Version="3.8.2" /> <PackageReference Include="CliWrap" Version="3.8.2" />
<PackageReference Include="DiscUtils.Iso9660" Version="0.16.13" /> <PackageReference Include="DiscUtils.Iso9660" Version="0.16.13" />
<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="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.16" /> <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.Configuration.UserSecrets" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
@ -25,7 +21,6 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" 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="Oracle.ManagedDataAccess.Core" Version="23.7.0" />
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.16" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" /> <PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
<PackageReference Include="System.Drawing.Common" Version="8.0.16" /> <PackageReference Include="System.Drawing.Common" Version="8.0.16" />
@ -34,4 +29,12 @@
<PackageReference Include="Phares.Shared" Version="8.0.118.14751" /> <PackageReference Include="Phares.Shared" Version="8.0.118.14751" />
<PackageReference Include="Phares.Metadata" Version="8.0.118.14751" /> <PackageReference Include="Phares.Metadata" Version="8.0.118.14751" />
</ItemGroup> </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> </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.DAQmxBaseGetErrorString(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
}

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

@ -0,0 +1,347 @@
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.DAQmxBaseCreateTask(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.DAQmxBaseConfigureLogging(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.DAQmxBaseCreateAIVoltageChan(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.DAQmxBaseCreateAOVoltageChan(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.DAQmxBaseCreateDOChan(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.DAQmxBaseReadAnalogF64(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.DAQmxBaseReadAnalogScalarF64(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;
}
#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.DAQmxBaseReadAnalogF64(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.DAQmxBaseStartTask(taskHandle);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not start Task");
TaskStartedUtc = DateTime.UtcNow;
}
public void Stop()
{
int errorCode = Interop.DAQmxBaseStopTask(taskHandle);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not stop Task");
}
public void Clear()
{
int errorCode = Interop.DAQmxBaseClearTask(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.DAQmxBaseCfgSampClkTiming(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.DAQmxBaseCfgHandshakingTiming(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.DAQmxBaseCfgBurstHandshakingTimingImportClock(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.DAQmxBaseCfgBurstHandshakingTimingExportClock(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.DAQmxBaseCfgChangeDetectionTiming(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.DAQmxBaseCfgImplicitTiming(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.DAQmxBaseCfgPipelinedSampClkTiming(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.DAQmxBaseGetSampClkRate(taskHandle, ref result);
if (sampleClkRate < 0)
throw new DAQmxException(sampleClkRate, "Could not get SampleClockRate");
return result;
}
set
{
int errorCode = Interop.DAQmxBaseSetSampClkRate(taskHandle, value);
if (errorCode < 0)
throw new DAQmxException(errorCode, "Could not set SampleClockRate");
}
}
public double SampleClockMaxRate
{
get
{
double result = 0.0;
int sampleClkMaxRate = Interop.DAQmxBaseGetSampClkMaxRate(taskHandle, ref result);
if (sampleClkMaxRate < 0)
throw new DAQmxException(sampleClkMaxRate, "Could not get SampleClockMaxRate");
return result;
}
}
public void DisableStartTrig()
{
int errorCode = Interop.DAQmxBaseDisableStartTrig(taskHandle);
if (errorCode < 0)
throw new DAQmxException(errorCode, "DisableStartTrig failed.");
}
public void CfgDigEdgeStartTrig(string triggerSource, DAQmxEdge triggerEdge)
{
int errorCode = Interop.DAQmxBaseCfgDigEdgeStartTrig(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.DAQmxBaseCfgAnlgEdgeStartTrig(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.DAQmxBaseCfgAnlgWindowStartTrig(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.DAQmxBaseCfgTimeStartTrig(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.DAQmxBaseCfgDigPatternStartTrig(taskHandle, triggerSource, triggerPattern, (int)triggerWhen);
if (errorCode < 0)
throw new DAQmxException(errorCode, "CfgDigPatternStartTrig failed.");
}
public void DisableRefTrig()
{
int errorCode = Interop.DAQmxBaseDisableRefTrig(taskHandle);
if (errorCode < 0)
throw new DAQmxException(errorCode, "DisableRefTrig failed.");
}
public void CfgDigEdgeRefTrig(string triggerSource, DAQmxEdge triggerEdge, uint pretriggerSamples)
{
int errorCode = Interop.DAQmxBaseCfgDigEdgeRefTrig(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.DAQmxBaseCfgAnlgEdgeRefTrig(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.DAQmxBaseCfgAnlgWindowRefTrig(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.DAQmxBaseCfgDigPatternRefTrig(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.DAQmxBaseWriteAnalogF64(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.DAQmxBaseWriteDigitalLines(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 = "DAQmxBase";
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 == "DAQmxBase" && !(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("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseGetSampClkRate(IntPtr taskHandle, ref double data);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseSetSampClkRate(IntPtr taskHandle, double data);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseGetSampClkMaxRate(IntPtr taskHandle, ref double data);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseSetWriteRegenMode(IntPtr taskHandle, int data);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCreateAIVoltageChan(
IntPtr taskHandle,
string physicalChannel,
string nameToAssignToChannel,
int terminalConfig,
double minVal,
double maxVal,
int units,
string customScaleName);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCreateAOVoltageChan(
IntPtr taskHandle,
string physicalChannel,
string nameToAssignToChannel,
double minVal,
double maxVal,
int units,
string customScaleName);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCreateDOChan(
IntPtr taskHandle,
string lines,
string nameToAssignToLines,
int lineGrouping);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseGetErrorString(
int errorCode,
StringBuilder errorString,
uint buffersize);
#if !unsafe
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe int DAQmxBaseReadAnalogF64(
IntPtr taskHandle,
int numSampsPerChan,
double timeout,
int fillMode,
double* readArray,
uint arraySizeInSamps,
out IntPtr sampsPerChanRead,
IntPtr reserved);
#endif
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseReadAnalogScalarF64(
IntPtr taskHandle,
double timeout,
out double value,
IntPtr reserved);
#if unsafe
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe int DAQmxBaseReadBinaryI16(
IntPtr taskHandle,
int numSampsPerChan,
double timeout,
int fillMode,
bool* readArray,
uint arraySizeInSamps,
out IntPtr sampsPerChanRead,
IntPtr reserved);
#endif
#if unsafe
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe int DAQmxBaseReadBinaryU16(
IntPtr taskHandle,
int numSampsPerChan,
double timeout,
int fillMode,
ushort* readArray,
uint arraySizeInSamps,
out IntPtr sampsPerChanRead,
IntPtr reserved);
#endif
#if unsafe
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe int DAQmxBaseReadBinaryI32(
IntPtr taskHandle,
int numSampsPerChan,
double timeout,
int fillMode,
int* readArray,
uint arraySizeInSamps,
out IntPtr sampsPerChanRead,
IntPtr reserved);
#endif
#if unsafe
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe int DAQmxBaseReadBinaryU32(
IntPtr taskHandle,
int numSampsPerChan,
double timeout,
int fillMode,
uint* readArray,
uint arraySizeInSamps,
out IntPtr sampsPerChanRead,
IntPtr reserved);
#endif
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseConfigureLogging(
IntPtr taskHandle,
string filePath,
int loggingMode,
string groupName,
int operation);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseLoadTask(string taskName, out IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCreateTask(string taskName, out IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseAddGlobalChansToTask(IntPtr taskHandle, string[] channelNames);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseStartTask(IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseStopTask(IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseClearTask(IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseWaitUntilTaskDone(IntPtr taskHandle, double timeToWait);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseWaitForValidTimestamp(
IntPtr taskHandle,
int timestampEvent,
double timeout,
CVIAbsoluteTime timestamp);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseIsTaskDone(IntPtr taskHandle, out uint isTaskDone);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseTaskControl(IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseGetNthTaskChannel(IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseGetNthTaskDevice(IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseGetTaskAttribute(IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCfgSampClkTiming(
IntPtr taskHandle,
string source,
double rate,
int activeEdge,
int sampleMode,
ulong sampsPerChan);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCfgHandshakingTiming(
IntPtr taskHandle,
int sampleMode,
ulong sampsPerChan);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCfgBurstHandshakingTimingImportClock(
IntPtr taskHandle,
int sampleMode,
ulong sampsPerChan,
double sampleClkRate,
string sampleClkSrc,
int sampleClkActiveEdge,
int pauseWhen,
int readyEventActiveLevel);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCfgBurstHandshakingTimingExportClock(
IntPtr taskHandle,
int sampleMode,
ulong sampsPerChan,
double sampleClkRate,
string sampleClkOutpTerm,
int sampleClkPulsePolarity,
int pauseWhen,
int readyEventActiveLevel);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCfgChangeDetectionTiming(
IntPtr taskHandle,
string risingEdgeChan,
string fallingEdgeChan,
int sampleMode,
ulong sampsPerChan);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCfgImplicitTiming(
IntPtr taskHandle,
int sampleMode,
ulong sampsPerChan);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseCfgPipelinedSampClkTiming(
IntPtr taskHandle,
string source,
double rate,
int activeEdge,
int sampleMode,
ulong sampsPerChan);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseGetTimingAttribute(
IntPtr taskHandle,
int attribute,
out object value);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseSetTimingAttribute(
IntPtr taskHandle,
int attribute,
object value);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseResetTimingAttribute(IntPtr taskHandle, int attribute);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseGetTimingAttributeEx(
IntPtr taskHandle,
string deviceNames,
int attribute,
out object value);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseSetTimingAttributeEx(
IntPtr taskHandle,
string deviceNames,
int attribute,
object value);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
internal static extern int DAQmxBaseResetTimingAttributeEx(
IntPtr taskHandle,
string deviceNames,
int attribute);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseDisableStartTrig(IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgDigEdgeStartTrig(
IntPtr taskHandle,
string triggerSource,
int triggerEdge);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgAnlgEdgeStartTrig(
IntPtr taskHandle,
string triggerSource,
int triggerSlope,
double triggerLevel);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgAnlgMultiEdgeStartTrig(
IntPtr taskHandle,
string triggerSources,
int[] triggerSlopeArray,
double[] triggerLevelArray,
uint arraySize);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgAnlgWindowStartTrig(
IntPtr taskHandle,
string triggerSource,
int triggerWhen,
double windowTop,
double windowBottom);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgTimeStartTrig(
IntPtr taskHandle,
CVIAbsoluteTime when,
int timescale);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgDigPatternStartTrig(
IntPtr taskHandle,
string triggerSource,
string triggerPattern,
int triggerWhen);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseDisableRefTrig(IntPtr taskHandle);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgDigEdgeRefTrig(
IntPtr taskHandle,
string triggerSource,
int triggerEdge,
uint pretriggerSamples);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgAnlgEdgeRefTrig(
IntPtr taskHandle,
string triggerSource,
int triggerSlope,
double triggerLevel,
uint pretriggerSamples);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgAnlgMultiEdgeRefTrig(
IntPtr taskHandle,
string triggerSources,
int[] triggerSlopeArray,
double[] triggerLevelArray,
uint pretriggerSamples,
uint arraySize);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgAnlgWindowRefTrig(
IntPtr taskHandle,
string triggerSource,
int triggerWhen,
double windowTop,
double windowBottom,
uint pretriggerSamples);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseCfgDigPatternRefTrig(
IntPtr taskHandle,
string triggerSource,
string triggerPattern,
int triggerWhen,
uint pretriggerSamples);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseGetTrigAttribute(
IntPtr taskHandle,
int attribute,
out object value);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseSetTrigAttribute(IntPtr taskHandle, int attribute, object value);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseResetTrigAttribute(IntPtr taskHandle, int attribute);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseWriteAnalogF64(
IntPtr taskHandle,
int numSampsPerChan,
bool autoStart,
double timeout,
bool dataLayout,
double[] writeArray,
out IntPtr sampsPerChanWritten,
IntPtr reserved);
[DllImport("DAQmxBase", CallingConvention = CallingConvention.StdCall)]
public static extern int DAQmxBaseWriteDigitalLines(
IntPtr taskHandle,
int numSampsPerChan,
bool autoStart,
double timeout,
bool dataLayout,
byte[] writeArray,
out IntPtr sampsPerChanWritten,
IntPtr reserved);
}

View File

@ -1,6 +1,12 @@
using CliWrap; using CliWrap;
using File_Watcher.Models; using File_Watcher.Models;
#if ShellProgressBar
using ShellProgressBar; using ShellProgressBar;
#endif
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
@ -21,13 +27,24 @@ internal static partial class DeterministicHashCodeHelper
{ {
public long Ticks { get; init; } public long Ticks { get; init; }
public int? CurrentTick => _ProgressBar?.CurrentTick; 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 ProgressBar? _ProgressBar;
private readonly ProgressBarOptions _ProgressBarOptions; private readonly ProgressBarOptions _ProgressBarOptions;
#endif
public Windows() => public Windows() =>
#if ShellProgressBar
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; _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) => DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient httpClient, Uri uri) =>
GetDeterministicHashCode(httpClient, uri); GetDeterministicHashCode(httpClient, uri);
@ -98,18 +115,26 @@ internal static partial class DeterministicHashCodeHelper
} }
void IWindows.Tick() => void IWindows.Tick() =>
#if ShellProgressBar
_ProgressBar?.Tick(); _ProgressBar?.Tick();
#else
throw new NotSupportedException("ShellProgressBar is not supported in this context.");
#endif
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
#if ShellProgressBar
_ProgressBar?.Dispose(); _ProgressBar?.Dispose();
#endif
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
void IWindows.ConstructProgressBar(int maxTicks, string message) void IWindows.ConstructProgressBar(int maxTicks, string message)
{ {
#if ShellProgressBar
_ProgressBar?.Dispose(); _ProgressBar?.Dispose();
_ProgressBar = new(maxTicks, message, _ProgressBarOptions); _ProgressBar = new(maxTicks, message, _ProgressBarOptions);
#endif
} }
ReadOnlyCollection<string> IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath) ReadOnlyCollection<string> IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath)

View File

@ -0,0 +1,76 @@
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)
value = keyValuePair.Value.ReadAnalogF64(appSettings.NationalInstrumentsConfiguration.ReadTimeout);
else
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);
}
}

View File

@ -16,6 +16,7 @@ public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
IsoConfiguration IsoConfiguration, IsoConfiguration IsoConfiguration,
MetadataSettings MetadataSettings, MetadataSettings MetadataSettings,
MetrologyConfiguration MetrologyConfiguration, MetrologyConfiguration MetrologyConfiguration,
NationalInstrumentsConfiguration NationalInstrumentsConfiguration,
NugetConfiguration NugetConfiguration, NugetConfiguration NugetConfiguration,
ResultSettings ResultSettings, ResultSettings ResultSettings,
SeleniumConfiguration SeleniumConfiguration, SeleniumConfiguration SeleniumConfiguration,
@ -42,6 +43,7 @@ public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
IsoConfiguration? isoConfiguration = configurationRoot.GetSection(nameof(IsoConfiguration)).Get<IsoConfiguration>(); IsoConfiguration? isoConfiguration = configurationRoot.GetSection(nameof(IsoConfiguration)).Get<IsoConfiguration>();
MetadataSettings? metadataSettings = configurationRoot.GetSection(nameof(MetadataSettings)).Get<MetadataSettings>(); MetadataSettings? metadataSettings = configurationRoot.GetSection(nameof(MetadataSettings)).Get<MetadataSettings>();
MetrologyConfiguration? metrologyConfiguration = configurationRoot.GetSection(nameof(MetrologyConfiguration)).Get<MetrologyConfiguration>(); MetrologyConfiguration? metrologyConfiguration = configurationRoot.GetSection(nameof(MetrologyConfiguration)).Get<MetrologyConfiguration>();
NationalInstrumentsConfiguration? nationalInstrumentsConfiguration = configurationRoot.GetSection(nameof(NationalInstrumentsConfiguration)).Get<NationalInstrumentsConfiguration>();
NugetConfiguration? nugetConfiguration = configurationRoot.GetSection(nameof(NugetConfiguration)).Get<NugetConfiguration>(); NugetConfiguration? nugetConfiguration = configurationRoot.GetSection(nameof(NugetConfiguration)).Get<NugetConfiguration>();
ResultSettings? resultSettings = configurationRoot.GetSection(nameof(ResultSettings)).Get<ResultSettings>(); ResultSettings? resultSettings = configurationRoot.GetSection(nameof(ResultSettings)).Get<ResultSettings>();
SeleniumConfiguration? seleniumConfiguration = configurationRoot.GetSection(nameof(SeleniumConfiguration)).Get<SeleniumConfiguration>(); SeleniumConfiguration? seleniumConfiguration = configurationRoot.GetSection(nameof(SeleniumConfiguration)).Get<SeleniumConfiguration>();
@ -63,6 +65,7 @@ public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
|| isoConfiguration is null || isoConfiguration is null
|| metadataSettings is null || metadataSettings is null
|| metrologyConfiguration is null || metrologyConfiguration is null
|| nationalInstrumentsConfiguration is null
|| nugetConfiguration is null || nugetConfiguration is null
|| resultSettings is null || resultSettings is null
|| seleniumConfiguration is null || seleniumConfiguration is null
@ -96,6 +99,7 @@ public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
isoConfiguration, isoConfiguration,
metadataSettings, metadataSettings,
metrologyConfiguration, metrologyConfiguration,
nationalInstrumentsConfiguration,
nugetConfiguration, nugetConfiguration,
resultSettings, resultSettings,
seleniumConfiguration, seleniumConfiguration,

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

@ -1,3 +1,5 @@
#if Nancy
using Nancy; using Nancy;
using Nancy.Extensions; using Nancy.Extensions;
@ -48,4 +50,6 @@ public class SyncModule : NancyModule
}); });
} }
} }
#endif

View File

@ -1,3 +1,5 @@
#if Nancy
using Microsoft.Owin.Cors; using Microsoft.Owin.Cors;
using Nancy.Owin; using Nancy.Owin;
using Owin; using Owin;
@ -16,4 +18,6 @@ public class Startup
_ = app.UseNancy(); _ = app.UseNancy();
} }
} }
#endif

View File

@ -24,7 +24,9 @@ public partial class Worker : BackgroundService
_IsWindowsService = collection.Contains(nameof(WindowsServiceLifetime)); _IsWindowsService = collection.Contains(nameof(WindowsServiceLifetime));
if (appSettings.FileWatcherConfiguration.Helper == nameof(Helpers.SyncHelper)) if (appSettings.FileWatcherConfiguration.Helper == nameof(Helpers.SyncHelper))
{ {
#if Nancy
_ = Microsoft.Owin.Hosting.WebApp.Start<Startup>(appSettings.SyncConfiguration.UniformResourceLocator); _ = Microsoft.Owin.Hosting.WebApp.Start<Startup>(appSettings.SyncConfiguration.UniformResourceLocator);
#endif
logger.LogInformation("Server running on {url}", appSettings.SyncConfiguration.UniformResourceLocator); logger.LogInformation("Server running on {url}", appSettings.SyncConfiguration.UniformResourceLocator);
} }
} }
@ -41,11 +43,6 @@ public partial class Worker : BackgroundService
private async Task Body(CancellationToken cancellationToken) private async Task Body(CancellationToken cancellationToken)
{ {
if (!_IsWindowsService)
{
_Logger.LogInformation("Set break point and skip to run {_AppSettings.FileWatcherConfiguration.Helper}!", _AppSettings.FileWatcherConfiguration.Helper);
throw new EvaluateException($"Set break point and skip to run {_AppSettings.FileWatcherConfiguration.Helper}!");
}
if (!_IsWindowsService) if (!_IsWindowsService)
{ {
for (int i = 0; i < int.MaxValue; i++) for (int i = 0; i < int.MaxValue; i++)
@ -87,6 +84,7 @@ public partial class Worker : BackgroundService
nameof(Helpers.HelperWaferCounter) => Helpers.HelperWaferCounter.MoveFile(_AppSettings, _Logger), nameof(Helpers.HelperWaferCounter) => Helpers.HelperWaferCounter.MoveFile(_AppSettings, _Logger),
nameof(Helpers.HelperSerial) => Helpers.HelperSerial.ReadWrite(_AppSettings, _Logger, cancellationToken), nameof(Helpers.HelperSerial) => Helpers.HelperSerial.ReadWrite(_AppSettings, _Logger, cancellationToken),
nameof(Helpers.HelperMetrologyFiles) => Helpers.HelperMetrologyFiles.SortAndDelete(_AppSettings, _Logger), nameof(Helpers.HelperMetrologyFiles) => Helpers.HelperMetrologyFiles.SortAndDelete(_AppSettings, _Logger),
nameof(Helpers.NationalInstrumentsHelper) => Helpers.NationalInstrumentsHelper.WriteData(_AppSettings, _Logger),
nameof(Helpers.DeterministicHashCodeHelper) => Helpers.DeterministicHashCodeHelper.WindowsWork(_AppSettings, _Logger), nameof(Helpers.DeterministicHashCodeHelper) => Helpers.DeterministicHashCodeHelper.WindowsWork(_AppSettings, _Logger),
#if Selenium #if Selenium
nameof(Helpers.SeleniumHelper) => Helpers.SeleniumHelper.HyperTextMarkupLanguageToPortableNetworkGraphics(_AppSettings, _Logger), nameof(Helpers.SeleniumHelper) => Helpers.SeleniumHelper.HyperTextMarkupLanguageToPortableNetworkGraphics(_AppSettings, _Logger),