national-instruments-helper

This commit is contained in:
2025-08-18 12:42:27 -07:00
parent 9b61eceb80
commit 5671959051
35 changed files with 1118 additions and 24 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)

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

@ -42,6 +42,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

@ -12,11 +12,6 @@
<ItemGroup>
<PackageReference Include="CliWrap" Version="3.8.2" />
<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.Extensions.Configuration.UserSecrets" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
@ -34,4 +29,12 @@
<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
}

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.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;
}
#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,6 +1,12 @@
using CliWrap;
using File_Watcher.Models;
#if ShellProgressBar
using ShellProgressBar;
#endif
using System.Collections.ObjectModel;
using System.Drawing;
using System.Drawing.Imaging;
@ -21,13 +27,24 @@ internal static partial class DeterministicHashCodeHelper
{
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 readonly ProgressBarOptions _ProgressBarOptions;
#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);
@ -98,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)

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);
}
}

View File

@ -16,6 +16,7 @@ public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
IsoConfiguration IsoConfiguration,
MetadataSettings MetadataSettings,
MetrologyConfiguration MetrologyConfiguration,
NationalInstrumentsConfiguration NationalInstrumentsConfiguration,
NugetConfiguration NugetConfiguration,
ResultSettings ResultSettings,
SeleniumConfiguration SeleniumConfiguration,
@ -42,6 +43,7 @@ public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
IsoConfiguration? isoConfiguration = configurationRoot.GetSection(nameof(IsoConfiguration)).Get<IsoConfiguration>();
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>();
@ -63,6 +65,7 @@ public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
|| isoConfiguration is null
|| metadataSettings is null
|| metrologyConfiguration is null
|| nationalInstrumentsConfiguration is null
|| nugetConfiguration is null
|| resultSettings is null
|| seleniumConfiguration is null
@ -96,6 +99,7 @@ public record AppSettings(CamstarOracleConfiguration CamstarOracleConfiguration,
isoConfiguration,
metadataSettings,
metrologyConfiguration,
nationalInstrumentsConfiguration,
nugetConfiguration,
resultSettings,
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.Extensions;
@ -48,4 +50,6 @@ public class SyncModule : NancyModule
});
}
}
}
#endif

View File

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

View File

@ -24,7 +24,9 @@ public partial class Worker : BackgroundService
_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);
}
}
@ -87,6 +89,7 @@ public partial class Worker : BackgroundService
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.NationalInstrumentsHelper) => Helpers.NationalInstrumentsHelper.WriteData(_AppSettings, _Logger),
nameof(Helpers.DeterministicHashCodeHelper) => Helpers.DeterministicHashCodeHelper.WindowsWork(_AppSettings, _Logger),
#if Selenium
nameof(Helpers.SeleniumHelper) => Helpers.SeleniumHelper.HyperTextMarkupLanguageToPortableNetworkGraphics(_AppSettings, _Logger),