diff --git a/.gitignore b/.gitignore
index edc36f2..40d838c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -216,4 +216,5 @@ pip-log.txt
*.mo
#Mr Developer
-.mr.developer.cfg
\ No newline at end of file
+.mr.developer.cfg
+/nuget.config
diff --git a/NetDAQmx.sln b/NetDAQmx.sln
index 3dc4be6..3fa2e72 100644
--- a/NetDAQmx.sln
+++ b/NetDAQmx.sln
@@ -13,20 +13,54 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
readme.md = readme.md
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetDaqmx.Tests", "NetDaqmx.Tests\NetDaqmx.Tests.csproj", "{50560A28-0BDD-4F44-8FD4-22D42F85DAF1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Debug|x64.ActiveCfg = Debug|x64
+ {3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Debug|x64.Build.0 = Debug|x64
+ {3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Debug|x86.ActiveCfg = Debug|x86
+ {3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Debug|x86.Build.0 = Debug|x86
{3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Release|x64.ActiveCfg = Release|x64
+ {3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Release|x64.Build.0 = Release|x64
+ {3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Release|x86.ActiveCfg = Release|x86
+ {3E0D153A-24B3-4587-A7A1-6B59FFE157AA}.Release|x86.Build.0 = Release|x86
{D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Debug|x64.ActiveCfg = Debug|x64
+ {D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Debug|x64.Build.0 = Debug|x64
+ {D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Debug|x86.ActiveCfg = Debug|x86
+ {D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Debug|x86.Build.0 = Debug|x86
{D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Release|x64.ActiveCfg = Release|x64
+ {D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Release|x64.Build.0 = Release|x64
+ {D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Release|x86.ActiveCfg = Release|x86
+ {D22D6FF4-D0A1-457D-8A9C-0D4AD207DDDE}.Release|x86.Build.0 = Release|x86
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Debug|Any CPU.Build.0 = Debug|x86
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Debug|x64.Build.0 = Debug|Any CPU
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Debug|x86.Build.0 = Debug|Any CPU
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Release|x64.ActiveCfg = Release|Any CPU
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Release|x64.Build.0 = Release|Any CPU
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Release|x86.ActiveCfg = Release|Any CPU
+ {50560A28-0BDD-4F44-8FD4-22D42F85DAF1}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/NetDAQmx/DllWrapper.cs b/NetDAQmx/DllWrapper.cs
new file mode 100644
index 0000000..eca3ec2
--- /dev/null
+++ b/NetDAQmx/DllWrapper.cs
@@ -0,0 +1,241 @@
+using NetDAQmx.Helpers;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace NetDAQmx;
+
+///
+/// The main DLL wrapper of nicaiu.dll
+///
+public static class DllWrapper
+{
+ ///
+ /// Reads all available samples parameter
+ ///
+ public const int DAQmx_Val_Auto = -1;
+ ///
+ /// Values for the Line Grouping parameter of DAQmxCreateDIChan and DAQmxCreateDOChan
+ ///
+ public enum DAQmxLineGrouping
+ {
+ ///
+ /// One Channel For Each Line
+ ///
+ ChanPerLine = 0,
+ ///
+ /// One Channel For All Lines
+ ///
+ ChanForAllLines = 1
+ }
+
+ ///
+ /// Values for the Data Layout parameter of DAQmxWriteAnalogF64, DAQmxWriteBinaryI16, DAQmxWriteDigitalU8, DAQmxWriteDigitalU32, DAQmxWriteDigitalLines
+ ///
+ public enum DAQmxDataLayout
+ {
+ ///
+ /// Group by Channel
+ ///
+ GroupByChannel = 0,
+ ///
+ /// Group by Scan Number
+ ///
+ GroupByScanNumber = 1
+ }
+
+ ///
+ /// Values for DAQmx_AI_TermCfg
+ ///
+ public enum DAQmxAITerminalConfiguration
+ {
+ ///
+ /// At run time, NI-DAQmx chooses the default terminal configuration for the channel
+ ///
+ Default = -1,
+ ///
+ /// Referenced single-ended mode
+ ///
+ RSE = 10083,
+ ///
+ /// Non-referenced single-ended mode
+ ///
+ NRSE = 10078,
+ ///
+ /// Differential mode
+ ///
+ Differential = 10106,
+ ///
+ /// Pseudodifferential mode
+ ///
+ PseudoDiff = 12529
+ }
+
+ ///
+ /// Values for DAQmx_AO_Voltage_Units
+ ///
+ public enum DAQmxAOVoltageUnits
+ {
+ ///
+ /// Volts
+ ///
+ Volts = 10348,
+ ///
+ /// From Custom Scale
+ ///
+ FromCustomScale = 10065
+ }
+
+ private const string DllPath = @"nicaiu.dll";
+
+ ///
+ /// Get the connected to the system devices
+ ///
+ /// Buffer where device names will be stored
+ /// Size of the buffer
+ ///
+ [DllImport(DllPath, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
+ private static extern int DAQmxGetSysDevNames([Out] char[] data, uint bufferSize);
+
+ ///
+ /// Indicates the names of all devices installed in the system
+ ///
+ /// Buffer to store device names
+ /// The error code returned by the function in the event of an error or warning. A value of 0 indicates success. A positive value indicates a warning. A negative value indicates an error.
+ internal static int DAQmxGetSysDevNames(char[] data)
+ {
+ return DAQmxGetSysDevNames(data, (uint)data.Length);
+ }
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxGetPhysicalChanDOPortWidth(string physicalChannel, out uint data);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxCreateTask(string taskName, out IntPtr taskHandle);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxCreateDOChan(IntPtr taskHandle, string lines, string nameToAssignToLines, DAQmxLineGrouping lineGrouping);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxCreateAIVoltageChan(IntPtr taskHandle, string physicalChannel, string nameToAssignToChannel, DAQmxAITerminalConfiguration terminalConfig, double minVal, double maxVal, DAQmxAOVoltageUnits units, string? customScaleName = null);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxCreateAOVoltageChan(IntPtr taskHandle, string physicalChannel, string nameToAssignToChannel, double minVal, double maxVal, DAQmxAOVoltageUnits units, string? customScaleName = null);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxWriteDigitalLines(IntPtr taskHandle, int numSampsPerChan, bool autoStart, double timeout, DAQmxDataLayout dataLayout, byte[] writeArray, out int sampsPerChanWritten, IntPtr reserved);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ private static extern int DAQmxWriteDigitalU8(IntPtr taskHandle, int numSampsPerChan, bool autoStart, double timeout, DAQmxDataLayout dataLayout, byte[] writeArray, out int sampsPerChanWritten, IntPtr reserved);
+
+ internal static int DAQmxWriteDigitalU8(IntPtr taskHandle, int numSampsPerChan, bool autoStart, double timeout, DAQmxDataLayout dataLayout, byte[] writeArray, out int sampsPerChanWritten)
+ {
+ return DAQmxWriteDigitalU8(taskHandle, numSampsPerChan, autoStart, timeout, dataLayout, writeArray, out sampsPerChanWritten, IntPtr.Zero);
+ }
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ private static extern int DAQmxWriteAnalogScalarF64(IntPtr taskHandle, bool autoStart, double timeout, double value, IntPtr reserved);
+
+ internal static int DAQmxWriteAnalogScalarF64(IntPtr taskHandle, bool autoStart, double timeout, double value)
+ {
+ return DAQmxWriteAnalogScalarF64(taskHandle, autoStart, timeout, value, IntPtr.Zero);
+ }
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ private static extern int DAQmxReadDigitalLines(IntPtr taskHandle, int numSampsPerChan, double timeout, DAQmxDataLayout fillMode, byte[] readArray, uint arraySizeInBytes, out int sampsPerChanRead, out int numBytesPerSamp, IntPtr reserved);
+ internal static int DAQmxReadDigitalLines(IntPtr taskHandle, int numSampsPerChan, double timeout, DAQmxDataLayout fillMode, byte[] readArray, uint arraySizeInBytes, out int sampsPerChanRead, out int numBytesPerSamp)
+ {
+ return DAQmxReadDigitalLines(taskHandle, numSampsPerChan, timeout, fillMode, readArray, arraySizeInBytes, out sampsPerChanRead, out numBytesPerSamp, IntPtr.Zero);
+ }
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ private static extern int DAQmxReadAnalogScalarF64(
+ IntPtr taskHandle,
+ double timeout,
+ out double value,
+ IntPtr reserved
+);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ private static extern int DAQmxReadAnalogF64(
+ IntPtr taskHandle,
+ int numSampsPerChan,
+ double timeout,
+ DAQmxDataLayout fillMode,
+ double[] readArray,
+ uint arraySizeInSamps,
+ out int sampsPerChanRead,
+ IntPtr reserved
+ );
+
+ internal static int DAQmxReadAnalogF64(DaqTask daqTask,
+ int numSampsPerChan,
+ double timeout,
+ DAQmxDataLayout fillMode,
+ double[] readArray,
+ uint arraySizeInSamps,
+ out int sampsPerChanRead)
+ {
+ return DAQmxReadAnalogF64(daqTask.handle, numSampsPerChan, timeout, fillMode, readArray, arraySizeInSamps, out sampsPerChanRead, IntPtr.Zero);
+ }
+
+ internal static int DAQmxReadAnalogF64(DaqTask daqTask, double timeout, DAQmxDataLayout fillMode, double[] readArray, uint arraySizeInSamps, out int sampsPerChanRead, int numSampsPerChan = DAQmx_Val_Auto)
+ {
+ return DAQmxReadAnalogF64(daqTask, numSampsPerChan, timeout, fillMode, readArray, arraySizeInSamps, out sampsPerChanRead);
+ }
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ private static extern int DAQmxReadDigitalU8(IntPtr taskHandle, int numSampsPerChan, double timeout, DAQmxDataLayout fillMode, byte[] readArray, uint arraySizeInSamps, out int sampsPerChanRead, IntPtr reserved);
+
+ ///
+ /// Reads a specified digital port as a 8bit number
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int DAQmxReadDigitalU8(Helpers.DaqTask task, int numSampsPerChan, double timeout, DAQmxDataLayout fillMode, byte[] readArray, uint arraySizeInSamps, out int sampsPerChanRead)
+ {
+ return DAQmxReadDigitalU8(task.handle, numSampsPerChan, timeout, fillMode, readArray, arraySizeInSamps, out sampsPerChanRead, IntPtr.Zero);
+ }
+
+ internal static int DAQmxReadAnalogScalarF64(IntPtr taskHandle, double timeout, out double value)
+ {
+ return DAQmxReadAnalogScalarF64(taskHandle, timeout, out value, IntPtr.Zero);
+ }
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxClearTask(IntPtr taskHandle);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxResetDevice(string deviceName);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxGetDeviceAttribute(string deviceName, int attribute, IntPtr value);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxGetErrorString(int errorCode, StringBuilder errorString, uint bufferSize);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxGetExtendedErrorInfo(StringBuilder errorString, uint bufferSize);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxGetTaskName(IntPtr taskHandle, StringBuilder data, uint bufferSize);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxGetTaskChannels(IntPtr taskHandle, StringBuilder data, uint bufferSize);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxGetTaskNumChans(IntPtr taskHandle, out uint data);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxLoadTask(string taskName, out IntPtr taskHandle);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxStartTask(IntPtr taskHandle);
+
+ [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int DAQmxStopTask(IntPtr taskHandle);
+}
diff --git a/NetDAQmx/Helpers/DaqTask.cs b/NetDAQmx/Helpers/DaqTask.cs
new file mode 100644
index 0000000..77baeec
--- /dev/null
+++ b/NetDAQmx/Helpers/DaqTask.cs
@@ -0,0 +1,28 @@
+namespace NetDAQmx.Helpers;
+///
+/// The `Daq` functions usually operate on a "Task" handle. This handle should be closed when finished.
+/// To ensure that it will be closed, we created this IDisposable object.
+///
+public class DaqTask : IDisposable
+{
+ internal IntPtr handle;
+ ///
+ /// Construct a daq task with a name (default is empty string)
+ ///
+ /// The task name
+ public DaqTask(string taskName = "")
+ {
+ var status = DllWrapper.DAQmxCreateTask(taskName, out handle);
+ NIDAQ.ThrowError(status);
+ }
+
+ ///
+ /// Fun Fact! Dispose is not called in debug mode. However, it does work when we 'Start Without Debugging'
+ /// https://stackoverflow.com/questions/518352/does-dispose-still-get-called-when-exception-is-thrown-inside-of-a-using-stateme
+ ///
+ public void Dispose()
+ {
+ var status = DllWrapper.DAQmxClearTask(handle);
+ NIDAQ.ThrowError(status);
+ }
+}
diff --git a/NetDAQmx/NIDAQ.cs b/NetDAQmx/NIDAQ.cs
new file mode 100644
index 0000000..189baf1
--- /dev/null
+++ b/NetDAQmx/NIDAQ.cs
@@ -0,0 +1,358 @@
+using NetDAQmx.Helpers;
+using System.Text;
+using static NetDAQmx.DllWrapper;
+
+namespace NetDAQmx;
+
+///
+/// This would not be much of a library if the user had to call the raw DLL functions.
+/// This class provides more user-friendly functions for interacting with NI-DAQ and represents a NI-DAQ instance.
+///
+public class NIDAQ
+{
+ ///
+ /// Indicates the names of all devices installed in the system
+ ///
+ /// The buffer's length
+ /// The array of device's names
+ public static string[] GetSystemDevices(int bufferSize = 100)
+ {
+ // Create a buffer to store the device names
+ char[] buffer = new char[bufferSize];
+
+ // Call the DAQmxGetSysDevNames function
+ int status = DAQmxGetSysDevNames(buffer);
+
+ // Check the result and handle it accordingly
+ if (status == 0)
+ {
+ string deviceNames = new string(buffer).TrimEnd('\0'); ; // Convert char array to string
+ var result = deviceNames.Split('\0');
+ if (result.Length > 0 && string.IsNullOrEmpty(result[0])) // no devices attached
+ {
+ return Array.Empty();
+ }
+ return result;
+ }
+
+ Console.WriteLine("Error occurred: " + status);
+ return Array.Empty();
+ }
+
+ ///
+ /// The devices name in the system
+ ///
+ public string DeviceAlias { get; }
+
+ ///
+ /// Constructor
+ ///
+ /// The devices name in the system
+ public NIDAQ(string deviceAlias = "Dev0")
+ {
+ DeviceAlias = deviceAlias;
+ }
+
+ ///
+ /// Indicates in bits the width of digital output port
+ ///
+ /// The path to the port. E.g. - Dev1/port0
+ /// The width of digital output port
+ public static uint DAQmxGetPhysicalChanDOPortWidth(string identifier)
+ {
+ var status = DllWrapper.DAQmxGetPhysicalChanDOPortWidth(identifier, out uint portWidth);
+ ThrowError(status);
+
+ return portWidth;
+ }
+
+ ///
+ /// Indicates in bits the width of digital output port
+ ///
+ /// The number of port
+ /// The width of digital output port
+ public uint DAQmxGetPhysicalChanDOPortWidth(byte port)
+ {
+ return DAQmxGetPhysicalChanDOPortWidth($"{DeviceAlias}/port{port}");
+ }
+
+ ///
+ /// Writes a single digital output to be on or off
+ ///
+ /// The port number
+ /// The channel number
+ /// True to close the line, o/w open
+ public void WriteDOChannel(byte port, uint channel, bool close)
+ {
+ WriteDOSingleLine(DeviceAlias, port, channel, close);
+ }
+
+ ///
+ /// Creates a task and writes a single line of a DO port
+ ///
+ /// The device name. E.g. - "Dev1"
+ /// The port number
+ /// The channel number
+ /// to close the line, o/w open
+ public static void WriteDOSingleLine(string deviceAlias, byte port, uint channel, bool close)
+ {
+ string identifier = $"{deviceAlias}/port{port}/line{channel}";
+
+ using var task = new DaqTask();
+ var status = DllWrapper.DAQmxCreateDOChan(task.handle, identifier, "", DAQmxLineGrouping.ChanPerLine);
+ ThrowError(status);
+
+ byte[] data = new byte[] { close ? (byte)0 : (byte)1 };
+ status = DllWrapper.DAQmxWriteDigitalLines(task.handle, 1, true, 10.0, DAQmxDataLayout.GroupByChannel, data, out int written, IntPtr.Zero);
+ ThrowError(status);
+ }
+
+ ///
+ /// Reads a single line from the given port and channel
+ ///
+ /// The port you want to read from
+ /// The channel/line you want to read from
+ /// if the line is open. otherwise
+ public bool IsLineOpen(byte port, uint channel)
+ {
+ return IsLineOpen(DeviceAlias, port, channel);
+ }
+
+ ///
+ /// Reads a single line from the given port and channel
+ ///
+ /// The devices name in the system
+ /// The port you want to read from
+ /// The channel/line you want to read from
+ /// if the line is open. otherwise
+ public static bool IsLineOpen(string deviceAlias, byte port, uint channel)
+ {
+ string identifier = $"{deviceAlias}/port{port}/line{channel}";
+
+ using var task = new DaqTask();
+ var status = DllWrapper.DAQmxCreateDOChan(task.handle, identifier, "", 0);
+ ThrowError(status);
+
+ byte[] data = new byte[8];
+
+ status = DAQmxReadDigitalLines(task.handle, 1, 10.0, DAQmxDataLayout.GroupByChannel, data, (uint)data.Length, out int samples_per_channel_read, out int bytes_per_channel);
+ ThrowError(status);
+
+ return data[0] == 1;
+ }
+
+ ///
+ /// Creates channel(s) to generate digital signals and adds the channel(s) to the task you specify with taskHandle. You can group digital lines into one digital channel or separate them into multiple digital channels. If you specify one or more entire ports in lines by using port physical channel names, you cannot separate the ports into multiple channels. To separate ports into multiple channels, use this function multiple times with a different port each time.
+ ///
+ /// The task to which to add the channels that this function creates
+ /// The names of the digital lines used to create a virtual channel. You can specify a list or range of lines. Specifying a port and no lines is the equivalent of specifying all the lines of that port in order. Therefore, if you specify Dev1/port0 and port 0 has eight lines, this is expanded to Dev1/port0/line0:7.
+ /// Specifies whether to group digital lines into one or more virtual channels. If you specify one or more entire ports in lines, you must set lineGrouping to ChanForAllLines
+ /// The name of the created virtual channel(s). If you create multiple virtual channels with one call to this function, you can specify a list of names separated by commas. If you do not specify a name, NI-DAQmx uses the physical channel name as the virtual channel name. If you specify your own names for nameToAssignToLines, you must use the names when you refer to these channels in other NI-DAQmx functions.
+ public static void DAQmxCreateDOChan(DaqTask task, string lines, DAQmxLineGrouping lineGrouping, string nameToAssignToLines = "")
+ {
+ var status = DllWrapper.DAQmxCreateDOChan(task.handle, lines, nameToAssignToLines, lineGrouping);
+ ThrowError(status);
+ }
+
+ ///
+ /// Creates channel(s) to generate digital signals and adds the channel(s) to the task you specify with taskHandle. You can group digital lines into one digital channel or separate them into multiple digital channels. If you specify one or more entire ports in lines by using port physical channel names, you cannot separate the ports into multiple channels. To separate ports into multiple channels, use this function multiple times with a different port each time.
+ ///
+ /// The task to which to add the channels that this function creates
+ /// The port number
+ /// The line number
+ /// Specifies whether to group digital lines into one or more virtual channels. If you specify one or more entire ports in lines, you must set lineGrouping to DAQmx_Val_ChanForAllLines
+ /// The name of the created virtual channel(s). If you create multiple virtual channels with one call to this function, you can specify a list of names separated by commas. If you do not specify a name, NI-DAQmx uses the physical channel name as the virtual channel name. If you specify your own names for nameToAssignToLines, you must use the names when you refer to these channels in other NI-DAQmx functions.
+ public void DAQmxCreateDOChan(DaqTask task, byte port, int line, DAQmxLineGrouping lineGrouping, string nameToAssignToLines = "")
+ {
+ DAQmxCreateDOChan(task, $"{DeviceAlias}/port{port}/line{line}", lineGrouping, nameToAssignToLines);
+ }
+
+ ///
+ /// Creates channel(s) to generate digital signals and adds the channel(s) to the task you specify with taskHandle. You can group digital lines into one digital channel or separate them into multiple digital channels. If you specify one or more entire ports in lines by using port physical channel names, you cannot separate the ports into multiple channels. To separate ports into multiple channels, use this function multiple times with a different port each time.
+ ///
+ /// The task to which to add the channels that this function creates
+ /// The port number
+ /// The first line number to include
+ /// The last line number to include
+ /// Specifies whether to group digital lines into one or more virtual channels. If you specify one or more entire ports in lines, you must set lineGrouping to DAQmx_Val_ChanForAllLines
+ /// The name of the created virtual channel(s). If you create multiple virtual channels with one call to this function, you can specify a list of names separated by commas. If you do not specify a name, NI-DAQmx uses the physical channel name as the virtual channel name. If you specify your own names for nameToAssignToLines, you must use the names when you refer to these channels in other NI-DAQmx functions
+ public void DAQmxCreateDOChan(DaqTask task, byte port, byte lineStart, byte lineEnd, DAQmxLineGrouping lineGrouping, string nameToAssignToLines = "")
+ {
+ DAQmxCreateDOChan(task, $"{DeviceAlias}/port{port}/line{lineStart}:{lineEnd}", lineGrouping, nameToAssignToLines);
+ }
+
+ ///
+ /// Writes multiple 8-bit unsigned integer samples to a task that contains one or more digital output channels. Use this format for devices with up to 8 lines per port.
+ ///
+ /// The task to write samples to
+ /// The number of samples, per channel, to write. You must pass in a value of 0 or more in order for the sample to write. If you pass a negative number, this function returns an error
+ /// Specifies whether or not this function automatically starts the task if you do not start it
+ /// The amount of time, in seconds, to wait for this function to write all the samples. To specify an infinite wait, pass -1 (DAQmx_Val_WaitInfinitely). This function returns an error if the timeout elapses.
+ /// A value of 0 indicates to try once to write the submitted samples. If this function successfully writes all submitted samples, it does not return an error. Otherwise, the function returns a timeout error and returns the number of samples actually written
+ /// Specifies how the samples are arranged, either interleaved or noninterleaved
+ /// The array of 8-bit integer samples to write to the task
+ /// The actual number of samples per channel successfully written to the buffer
+ public static void DAQmxWriteDigitalU8(DaqTask task, int numSamplesPerChan, bool autoStart, double timeout, DAQmxDataLayout dataLayout, byte[] writeArray, out int sampsPerChanWritten)
+ {
+ var status = DllWrapper.DAQmxWriteDigitalU8(task.handle, numSamplesPerChan, autoStart, timeout, dataLayout, writeArray, out sampsPerChanWritten);
+ ThrowError(status);
+ }
+
+ public static int DAQmxReadDigitalU8(DaqTask task, int numSampsPerChan, double timeout, DAQmxDataLayout fillMode, byte[] readArray, uint arraySizeInSamps, out int sampsPerChanRead)
+ {
+ return DllWrapper.DAQmxReadDigitalU8(task, numSampsPerChan, timeout, fillMode, readArray, arraySizeInSamps, out sampsPerChanRead);
+ }
+
+ ///
+ /// Creates a task and writes an entire port with a specific value
+ ///
+ /// The port number
+ /// The data to write to the port
+ public void WritePort(byte port, byte data)
+ {
+ var identifier = $"{DeviceAlias}/port{port}";
+
+ using var task = new DaqTask();
+ DAQmxCreateDOChan(task, identifier, DAQmxLineGrouping.ChanForAllLines);
+
+ byte[] dataArray = new byte[] { data };
+ DAQmxWriteDigitalU8(task, 1, true, 10.0, DAQmxDataLayout.GroupByChannel, dataArray, out int written);
+ }
+
+ ///
+ /// Reading the value of the whole port as a byte
+ ///
+ /// The port number to read from
+ /// The value of the port
+ public byte ReadPort(byte port)
+ {
+ var identifier = $"{DeviceAlias}/port{port}";
+
+ using var task = new DaqTask();
+ DAQmxCreateDOChan(task, identifier, DAQmxLineGrouping.ChanForAllLines);
+ byte[] readArray = new byte[1];
+ var status = DAQmxReadDigitalU8(task, 1, 10.0, DAQmxDataLayout.GroupByChannel, readArray, (uint)readArray.Length, out int samples_per_channel_read);
+ ThrowError(status);
+
+ return readArray[0];
+ }
+ ///
+ /// Creates channel(s) to measure voltage and adds the channel(s) to the task you specify with taskHandle. If your measurement requires the use of internal excitation or you need the voltage to be scaled by excitation, call DAQmxCreateAIVoltageChanWithExcit.
+ ///
+ /// The task to which to add the channels that this function creates
+ /// The names of the physical channels to use to create virtual channels. You can specify a list or range of physical channels
+ /// The name(s) to assign to the created virtual channel(s). If you do not specify a name, NI-DAQmx uses the physical channel name as the virtual channel name. If you specify your own names for nameToAssignToChannel, you must use the names when you refer to these channels in other NI-DAQmx functions. If you create multiple virtual channels with one call to this function, you can specify a list of names separated by commas. If you provide fewer names than the number of virtual channels you create, NI-DAQmx automatically assigns names to the virtual channels.
+ /// The input terminal configuration for the channel
+ /// The minimum value, in units, that you expect to measure
+ /// The maximum value, in units, that you expect to measure
+ /// The units to use to return the voltage measurements
+ /// The name of a custom scale to apply to the channel. To use this parameter, you must set units to DAQmx_Val_FromCustomScale. If you do not set units to DAQmx_Val_FromCustomScale, you must set customScaleName to NULL
+ public static void DAQmxCreateAIVoltageChan(DaqTask task, string physicalChannel, string nameToAssignToChannel, DAQmxAITerminalConfiguration terminalConfig, double minVal, double maxVal, DAQmxAOVoltageUnits units, string? customScaleName = null)
+ {
+ var status = DllWrapper.DAQmxCreateAIVoltageChan(task.handle, physicalChannel, nameToAssignToChannel, terminalConfig, minVal, maxVal, units, customScaleName);
+ ThrowError(status);
+ }
+
+ ///
+ /// Creates channel(s) to measure voltage and adds the channel(s) to the task you specify with taskHandle. If your measurement requires the use of internal excitation or you need the voltage to be scaled by excitation, call DAQmxCreateAIVoltageChanWithExcit.
+ ///
+ /// The task to which to add the channels that this function creates
+ /// The line to read from
+ /// The name(s) to assign to the created virtual channel(s). If you do not specify a name, NI-DAQmx uses the physical channel name as the virtual channel name. If you specify your own names for nameToAssignToChannel, you must use the names when you refer to these channels in other NI-DAQmx functions. If you create multiple virtual channels with one call to this function, you can specify a list of names separated by commas. If you provide fewer names than the number of virtual channels you create, NI-DAQmx automatically assigns names to the virtual channels.
+ /// The input terminal configuration for the channel
+ /// The minimum value, in units, that you expect to measure
+ /// The maximum value, in units, that you expect to measure
+ /// The units to use to return the voltage measurements
+ /// The name of a custom scale to apply to the channel. To use this parameter, you must set units to DAQmx_Val_FromCustomScale. If you do not set units to DAQmx_Val_FromCustomScale, you must set customScaleName to NULL
+ public void DAQmxCreateAIVoltageChan(DaqTask task, byte analogInput, string nameToAssignToChannel, DAQmxAITerminalConfiguration terminalConfig, double minVal, double maxVal, DAQmxAOVoltageUnits units, string? customScaleName = null)
+ {
+ DAQmxCreateAIVoltageChan(task, $"{DeviceAlias}/ai{analogInput}", nameToAssignToChannel, terminalConfig, minVal, maxVal, units, customScaleName);
+ }
+
+ ///
+ /// Creates channel(s) to measure voltage and adds the channel(s) to the task you specify with taskHandle. If your measurement requires the use of internal excitation or you need the voltage to be scaled by excitation, call DAQmxCreateAIVoltageChanWithExcit.
+ ///
+ /// The task to which to add the channels that this function creates
+ /// The start of the range of the analog line
+ /// The end of the range of the analog line
+ /// The name(s) to assign to the created virtual channel(s). If you do not specify a name, NI-DAQmx uses the physical channel name as the virtual channel name. If you specify your own names for nameToAssignToChannel, you must use the names when you refer to these channels in other NI-DAQmx functions. If you create multiple virtual channels with one call to this function, you can specify a list of names separated by commas. If you provide fewer names than the number of virtual channels you create, NI-DAQmx automatically assigns names to the virtual channels.
+ /// The input terminal configuration for the channel
+ /// The minimum value, in units, that you expect to measure
+ /// The maximum value, in units, that you expect to measure
+ /// The units to use to return the voltage measurements
+ /// The name of a custom scale to apply to the channel. To use this parameter, you must set units to DAQmx_Val_FromCustomScale. If you do not set units to DAQmx_Val_FromCustomScale, you must set customScaleName to NULL
+ public void DAQmxCreateAIVoltageChan(DaqTask task, byte analogInputStart, byte analogInputEnd, string nameToAssignToChannel, DAQmxAITerminalConfiguration terminalConfig, double minVal, double maxVal, DAQmxAOVoltageUnits units, string? customScaleName = null)
+ {
+ DAQmxCreateAIVoltageChan(task, $"{DeviceAlias}/ai{analogInputStart}:{analogInputEnd}", nameToAssignToChannel, terminalConfig, minVal, maxVal, units, customScaleName);
+ }
+
+ ///
+ /// Reads a single floating-point sample from a task that contains a single analog input channel
+ ///
+ /// The task to read the sample from
+ /// The amount of time, in seconds, to wait for the function to read the sample(s). To specify an infinite wait, pass -1 (DAQmx_Val_WaitInfinitely). This function returns an error if the timeout elapses. A value of 0 indicates to try once to read the requested samples. If all the requested samples are read, the function is successful. Otherwise, the function returns a timeout error and returns the samples that were actually read
+ /// The sample read from the task
+ public static void DAQmxReadAnalogScalarF64(DaqTask task, double timeout, out double result)
+ {
+ var status = DllWrapper.DAQmxReadAnalogScalarF64(task.handle, timeout, out result);
+ ThrowError(status);
+ }
+
+ ///
+ /// Create a task and reads a single floating-point sample from a task that contains a single analog input channel
+ ///
+ /// The line to read from
+ /// The minimum value, in units, that you expect to measure
+ /// The maximum value, in units, that you expect to measure
+ ///
+ public double GetAnalogInputSingleLine(uint channel, double minValue, double maxValue)
+ {
+ using var task = new DaqTask();
+ DAQmxCreateAIVoltageChan(task, $"{DeviceAlias}/ai{channel}", "", DAQmxAITerminalConfiguration.RSE, minValue, maxValue, DAQmxAOVoltageUnits.Volts);
+ DAQmxReadAnalogScalarF64(task, 10, out double result);
+ return result;
+ }
+
+ ///
+ /// Creates channel(s) to generate voltage and adds the channel(s) to the task you specify with taskHandle, and then writes a floating-point sample to a task that contains a single analog output channel.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void SetAnalogInputValue(uint channel, double value, double minVal = 0, double maxVal = 5)
+ {
+ using var task = new DaqTask();
+ var status = DAQmxCreateAOVoltageChan(task.handle, $"{DeviceAlias}/ao{channel}", "", minVal, maxVal, DAQmxAOVoltageUnits.Volts);
+ ThrowError(status);
+ status = DAQmxWriteAnalogScalarF64(task.handle, true, 10, value);
+ ThrowError(status);
+ }
+
+ public double GetAnalogInputSingleLine(uint channel, double minValue, double maxValue, double[] readArray)
+ {
+ using var task = new DaqTask();
+ DAQmxCreateAIVoltageChan(task, $"{DeviceAlias}/ai{channel}", "", DAQmxAITerminalConfiguration.RSE, minValue, maxValue, DAQmxAOVoltageUnits.Volts);
+ var status = DAQmxReadAnalogF64(task, 10, DAQmxDataLayout.GroupByChannel, readArray, (uint)readArray.Length, out _, readArray.Length);
+ ThrowError(status);
+ return readArray.Average();
+ }
+ ///
+ /// Handle errors here using DAQmxGetErrorString (or try DAQmxGetExtendedErrorInfo).
+ ///
+ public static void ThrowError(int code)
+ {
+ // No problems
+ if (code == 0)
+ return;
+
+ // Give us a message for that error code.
+ var error = new StringBuilder(2000);
+ DAQmxGetErrorString(code, error, 2000);
+ if (error.ToString().Trim().Length > 0)
+ throw new Exception(error.ToString());
+
+ // No message? Then just throw the error code.
+ throw new Exception(code + "");
+ }
+}
diff --git a/NetDAQmx/NetDAQmx.csproj b/NetDAQmx/NetDAQmx.csproj
index 132c02c..bd64ba4 100644
--- a/NetDAQmx/NetDAQmx.csproj
+++ b/NetDAQmx/NetDAQmx.csproj
@@ -1,9 +1,18 @@
-
+
-
- net6.0
- enable
- enable
-
+
+ net7.0
+ enable
+ enable
+ x86
+ true
+ True
+ 1.0.0-preview4
+ NI-Daq Communication Library
+ This library wraps the native ANSI C library into .NET 7
+ https://github.com/jrdnwrth/NetDAQmx
+ en
+ True
+
diff --git a/NetDAQmx/dll_wrapper.cs b/NetDAQmx/dll_wrapper.cs
deleted file mode 100644
index b1bc2bb..0000000
--- a/NetDAQmx/dll_wrapper.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace NetDAQmx;
-
-public class Dll_Wrapper
-{
- private const string DllPath = @"nicaiu.dll";
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxCreateTask(string taskName, out IntPtr taskHandle);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxCreateDOChan(IntPtr taskHandle, string lines, string nameToAssignToLines, int lineGrouping);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxWriteDigitalLines(IntPtr taskHandle, int numSampsPerChan, bool autoStart, double timeout, bool dataLayout, byte[] writeArray, out int sampsPerChanWritten, IntPtr reserved);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxReadDigitalLines(IntPtr taskHandle, int numSampsPerChan, double timeout, bool fillMode, byte[] readArray, UInt32 arraySizeInBytes, out int sampsPerChanRead, out int numBytesPerSamp, IntPtr reserved);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxClearTask(IntPtr taskHandle);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxResetDevice(string deviceName);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxGetDeviceAttribute(string deviceName, int attribute, IntPtr value);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxGetErrorString(int errorCode, StringBuilder errorString, uint bufferSize);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxGetExtendedErrorInfo(StringBuilder errorString, uint bufferSize);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxGetTaskName(IntPtr taskHandle, StringBuilder data, uint bufferSize);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxGetTaskChannels(IntPtr taskHandle, StringBuilder data, uint bufferSize);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxGetTaskNumChans(IntPtr taskHandle, out uint data);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxLoadTask(string taskName, out IntPtr taskHandle);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxStartTask(IntPtr taskHandle);
-
- [DllImport(DllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
- public static extern int DAQmxStopTask(IntPtr taskHandle);
-}
diff --git a/NetDAQmx/ni_daq.cs b/NetDAQmx/ni_daq.cs
deleted file mode 100644
index 2e8571a..0000000
--- a/NetDAQmx/ni_daq.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace NetDAQmx;
-
-///
-/// The `Daq` functions usually operate on a "Task" handle. This handle should be closed when finished.
-/// To ensure that it will be closed, we created this IDisposable object.
-///
-public class Daq_Task : IDisposable
-{
- public IntPtr handle;
- public Daq_Task()
- {
- var status = Dll_Wrapper.DAQmxCreateTask("", out handle);
- Daq.throw_error(status);
- }
-
- ///
- /// Fun Fact! Dispose is not called in debug mode. However, it does work when we 'Start Without Debugging'
- /// https://stackoverflow.com/questions/518352/does-dispose-still-get-called-when-exception-is-thrown-inside-of-a-using-stateme
- ///
- public void Dispose()
- {
- var status = Dll_Wrapper.DAQmxClearTask(handle);
- Daq.throw_error(status);
- }
-}
-
-///
-/// This would not be much of a library if the user had to call the raw DLL functions.
-/// This class provides more user-friendly functions for interacting with NI-DAQ.
-///
-public class Daq
-{
- public static void actuate_relay(string device_alias, bool close, int channel)
- {
- string identifier = device_alias + @"/port0/line" + channel;
-
- using (var task = new Daq_Task())
- {
- var status = Dll_Wrapper.DAQmxCreateDOChan(task.handle, identifier, "", 0);
- throw_error(status);
-
- byte[] data = new byte[] { close ? (byte)1 : (byte)0 };
- int written;
-
- status = Dll_Wrapper.DAQmxWriteDigitalLines(task.handle, 1, true, 10.0, false, data, out written, IntPtr.Zero);
- throw_error(status);
- }
- }
-
- public static bool is_relay_closed(string device_alias, int channel)
- {
- string identifier = device_alias + @"/port0/line" + channel;
-
- using (var task = new Daq_Task())
- {
- var status = Dll_Wrapper.DAQmxCreateDOChan(task.handle, identifier, "", 0);
- throw_error(status);
-
- byte[] data = new byte[8];
-
- int samples_per_channel_read;
- int bytes_per_channel;
-
- status = Dll_Wrapper.DAQmxReadDigitalLines(task.handle, 1, 10.0, false, data, (uint)data.Count(), out samples_per_channel_read, out bytes_per_channel, IntPtr.Zero);
- throw_error(status);
-
- return data.ToList().Any();
- }
- }
-
- ///
- /// Handle errors here using DAQmxGetErrorString (or try DAQmxGetExtendedErrorInfo).
- ///
- public static void throw_error(int code)
- {
- // No problems
- if (code == 0)
- return;
-
- // Give us a message for that error code.
- var error = new StringBuilder(2000);
- Dll_Wrapper.DAQmxGetErrorString(code, error, 2000);
- if (error.ToString().Trim().Length > 0)
- throw new Exception(error.ToString());
-
- // No message? Then just throw the error code.
- throw new Exception(code + "");
- }
-}
diff --git a/NetDAQmx_TestingPlatform/NetDAQmx_TestingPlatform.csproj b/NetDAQmx_TestingPlatform/NetDAQmx_TestingPlatform.csproj
index 33a945b..4a04feb 100644
--- a/NetDAQmx_TestingPlatform/NetDAQmx_TestingPlatform.csproj
+++ b/NetDAQmx_TestingPlatform/NetDAQmx_TestingPlatform.csproj
@@ -2,9 +2,10 @@
Exe
- net6.0
+ net7.0-windows
enable
enable
+ AnyCPU;x64;x86
diff --git a/NetDAQmx_TestingPlatform/Program.cs b/NetDAQmx_TestingPlatform/Program.cs
index 06311a4..dc5c528 100644
--- a/NetDAQmx_TestingPlatform/Program.cs
+++ b/NetDAQmx_TestingPlatform/Program.cs
@@ -1,5 +1,5 @@
using NetDAQmx;
-using System;
+using NetDAQmx.Helpers;
namespace NetDAQmx_TestingPlatform;
@@ -10,17 +10,24 @@ internal class Program
///
static void Main(string[] args)
{
- int relay = 1; // 0,1,2, or 3 for NI-9481. 0,1,2,3,4,5,6, or 7 for NI-9485.
- bool close = true; // Set this to false to open the relay.
- string device_name = "Dev1"; // Use NI-MAX to assign this name.
+ var connectedDevices = NIDAQ.GetSystemDevices();
+ if (connectedDevices.Length == 0)
+ {
+ Console.WriteLine("There are no NI Daq Connected to this PC.");
+ return;
+ }
- // Open or close the relay.
- Daq.actuate_relay(device_name, close, relay);
+ uint relay = 7; // 0,1,2, or 3 for NI-9481. 0,1,2,3,4,5,6, or 7 for NI-9485.
+ bool close = false; // Set this to false to open the relay.
+ NIDAQ daq = new(connectedDevices[0]); // Use NI-MAX to assign this name.
+ // Open or close the relay.
+ daq.WriteDOChannel(0, relay, close);
+
// Read whether it is open or closed.
- bool is_closed = Daq.is_relay_closed(device_name, relay);
+ bool is_closed = daq.IsLineOpen(0, relay);
// Print the results.
- Console.WriteLine(is_closed ? "Closed" : "Open" );
+ Console.WriteLine(is_closed ? "Closed" : "Open");
}
}
diff --git a/NetDaqmx.Tests/GlobalUsings.cs b/NetDaqmx.Tests/GlobalUsings.cs
new file mode 100644
index 0000000..8c927eb
--- /dev/null
+++ b/NetDaqmx.Tests/GlobalUsings.cs
@@ -0,0 +1 @@
+global using Xunit;
\ No newline at end of file
diff --git a/NetDaqmx.Tests/NetDaqMxTests.cs b/NetDaqmx.Tests/NetDaqMxTests.cs
new file mode 100644
index 0000000..4da0e61
--- /dev/null
+++ b/NetDaqmx.Tests/NetDaqMxTests.cs
@@ -0,0 +1,46 @@
+using NetDAQmx;
+
+namespace NetDaqmx.Tests;
+
+public class NetDaqMxTests
+{
+ private NIDAQ[] Daqs;
+ public NetDaqMxTests()
+ {
+ var connectedDevices = NIDAQ.GetSystemDevices();
+ Assert.NotEmpty(connectedDevices);
+
+ Daqs = new NIDAQ[connectedDevices.Length]; // Use NI-MAX to assign this name.
+ for (int i = 0; i < connectedDevices.Length; i++)
+ {
+ Daqs[i] = new(connectedDevices[i]);
+ }
+ }
+
+ [Fact]
+ public void WritePort0Test()
+ {
+ foreach (var daq in Daqs)
+ {
+ daq.WritePort(0, 255);
+ Assert.Equal(255, daq.ReadPort(0));
+
+ for (byte i = 0; i < byte.MaxValue; i++)
+ {
+ daq.WritePort(0, i);
+
+ Assert.Equal(i, daq.ReadPort(0));
+ }
+ }
+ }
+
+ [Fact]
+ public void AnalogInputTest()
+ {
+ foreach (var daq in Daqs)
+ {
+ double[] analogReads = new double[10];
+ var analogInputAverage = daq.GetAnalogInputSingleLine(0, 0, 10, analogReads);
+ }
+ }
+}
\ No newline at end of file
diff --git a/NetDaqmx.Tests/NetDaqmx.Tests.csproj b/NetDaqmx.Tests/NetDaqmx.Tests.csproj
new file mode 100644
index 0000000..f198498
--- /dev/null
+++ b/NetDaqmx.Tests/NetDaqmx.Tests.csproj
@@ -0,0 +1,30 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+ true
+ AnyCPU;x86
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+