Closed GoogleCodeExporter closed 9 years ago
I wound up writing my own ctypes-based class for accessing the digital I/O
ports on
my NI-DAQ 6008. I based it on the examples given in
http://www.scipy.org/Cookbook/Data_Acquisition_with_NIDAQmx and the C code
provided
with the NIDAQmx 9.0.2 driver. As seen in the example python code at
scipy.org, it
uses nicaiu.dll to access the hardware. The code was tested and it seems to
work for
what I'm trying to do:
"""
This is an interpretation of the example program
C:\Documents and Settings\All Users\Documents\National
Instruments\NI-DAQ\Examples\DAQmx ANSI C\Digital\Generate Values\Write Dig
Chan\WriteDigChan.c
This routine allows you to access and set the digital output ports.
This module depends on:
numpy
Adapted by Martin Bures [ mbures { @ } zoll { . } com ]
Re-adapted by Matthew Last [ mlast { @ } trexenterprises { . } com]
"""
# import system libraries
import ctypes
import numpy as np
# load DLL
nidaq = ctypes.windll.nicaiu # load the DLL
##############################
# Setup some typedefs and constants
# to correspond with values in
# C:\Program Files\National Instruments\NI-DAQ\DAQmx ANSI C
Dev\include\NIDAQmx.h
# the typedefs
uint8 = ctypes.c_uint8
uInt32 = ctypes.c_ulong
uInt64 = ctypes.c_ulonglong
float64 = ctypes.c_double
TaskHandle = uInt32
# the constants
DAQmx_Val_ChanForAllLines = 1
DAQmx_Val_GroupByChannel = 0
class Ports( threading.Thread ):
"""
This class performs the necessary initialization of the DAQ hardware and
initializes the digital lines to low (digital 0)
"""
def __init__( self ):
self.port0 = [0,0,0,0,0,0,0,0]
self.port1 = [0,0,0,0]
self.taskHandle0 = TaskHandle( 0 )
self.taskHandle1 = TaskHandle( 0 )
# setup the DAQ hardware for port0 and port1
self.CHK(nidaq.DAQmxCreateTask("",
ctypes.byref( self.taskHandle0 )))
self.CHK(nidaq.DAQmxCreateTask("",
ctypes.byref( self.taskHandle1 )))
self.CHK(nidaq.DAQmxCreateDOChan( self.taskHandle0,
"Dev1/port0/line0:7",
"",
DAQmx_Val_ChanForAllLines))
self.CHK(nidaq.DAQmxCreateDOChan( self.taskHandle1,
"Dev1/port1/line0:3",
"",
DAQmx_Val_ChanForAllLines))
self.run(self.taskHandle0)
self.run(self.taskHandle1)
# Initialize digital ports
self.update( port0 = self.port0, port1 = self.port1)
def CHK( self, err ):
"""a simple error checking routine"""
if err < 0:
buf_size = 100
buf = ctypes.create_string_buffer('\000' * buf_size)
nidaq.DAQmxGetErrorString(err,ctypes.byref(buf),buf_size)
raise RuntimeError('nidaq call failed with error %d:
%s'%(err,repr(buf.value)))
if err > 0:
buf_size = 100
buf = ctypes.create_string_buffer('\000' * buf_size)
nidaq.DAQmxGetErrorString(err,ctypes.byref(buf),buf_size)
raise RuntimeError('nidaq generated warning %d: %s'%(err,repr(buf.value)))
def run( self, taskHandle ):
self.CHK(nidaq.DAQmxStartTask( taskHandle ))
def stop( self ):
nidaq.DAQmxStopTask( self.taskHandle0 )
nidaq.DAQmxClearTask( self.taskHandle0 )
def update(self, port0 = [0,0,0,0,0,0,0,0], port1 = [0,0,0,0]):
if len(port0) != 8:
raise ValueError('port0 argument must have 8 values')
if len(port1) != 4:
raise ValueError('port1 argument must have 4 values')
for i in range(len(port0)):
self.port0data[i] = port0[i]
for i in range(len(port1)):
self.port1data[i] = port1[i]
self.CHK(nidaq.DAQmxWriteDigitalLines( self.taskHandle0,
1, 1, float64(10.0),
DAQmx_Val_GroupByChannel,
self.port0data.ctypes.data,
None,
None))
self.CHK(nidaq.DAQmxWriteDigitalLines( self.taskHandle1,
1, 1, float64(10.0),
DAQmx_Val_GroupByChannel,
self.port1data.ctypes.data,
None,
None))
Original comment by mattl...@gmail.com
on 3 Dec 2009 at 1:04
I lie! It doesn't work. I removed some critical pieces during my code cleanup
just
before I posted. Here's the really truly tested and working code:
"""
This is an interpretation of the example program
C:\Documents and Settings\All Users\Documents\National
Instruments\NI-DAQ\Examples\DAQmx ANSI C\Digital\Generate Values\Write Dig
Chan\WriteDigChan.c
This routine allows you to access and set the digital output ports.
This module depends on:
numpy
Adapted by Martin Bures [ mbures { @ } zoll { . } com ]
Re-adapted by Matthew Last [ mlast { @ } trexenterprises { . } com]
"""
# import system libraries
import ctypes
import numpy as np
# load DLL
nidaq = ctypes.windll.nicaiu # load the DLL
##############################
# Setup some typedefs and constants
# to correspond with values in
# C:\Program Files\National Instruments\NI-DAQ\DAQmx ANSI C
Dev\include\NIDAQmx.h
# the typedefs
uint8 = ctypes.c_uint8
uInt32 = ctypes.c_ulong
uInt64 = ctypes.c_ulonglong
float64 = ctypes.c_double
TaskHandle = uInt32
# the constants
DAQmx_Val_ChanForAllLines = 1
DAQmx_Val_GroupByChannel = 0
class Ports( object ):
"""
This class performs the necessary initialization of the DAQ hardware and
initializes the digital lines to low (digital 0)
"""
def __init__( self ):
self.port0 = [0,0,0,0,0,0,0,0]
self.port1 = [0,0,0,0]
self.port0data = np.zeros((8,), np.uint8 )
self.port1data = np.zeros((4,), np.uint8 )
self.taskHandle0 = TaskHandle( 0 )
self.taskHandle1 = TaskHandle( 0 )
# setup the DAQ hardware for port0 and port1
self.CHK(nidaq.DAQmxCreateTask("",
ctypes.byref( self.taskHandle0 )))
self.CHK(nidaq.DAQmxCreateTask("",
ctypes.byref( self.taskHandle1 )))
self.CHK(nidaq.DAQmxCreateDOChan( self.taskHandle0,
"Dev1/port0/line0:7",
"",
DAQmx_Val_ChanForAllLines))
self.CHK(nidaq.DAQmxCreateDOChan( self.taskHandle1,
"Dev1/port1/line0:3",
"",
DAQmx_Val_ChanForAllLines))
self.run(self.taskHandle0)
self.run(self.taskHandle1)
# Initialize digital ports
self.update( port0 = self.port0, port1 = self.port1)
def CHK( self, err ):
"""a simple error checking routine"""
if err < 0:
buf_size = 100
buf = ctypes.create_string_buffer('\000' * buf_size)
nidaq.DAQmxGetErrorString(err,ctypes.byref(buf),buf_size)
raise RuntimeError('nidaq call failed with error %d:
%s'%(err,repr(buf.value)))
if err > 0:
buf_size = 100
buf = ctypes.create_string_buffer('\000' * buf_size)
nidaq.DAQmxGetErrorString(err,ctypes.byref(buf),buf_size)
raise RuntimeError('nidaq generated warning %d: %s'%(err,repr(buf.value)))
def run( self, taskHandle ):
self.CHK(nidaq.DAQmxStartTask( taskHandle ))
def stop( self ):
nidaq.DAQmxStopTask( self.taskHandle0 )
nidaq.DAQmxClearTask( self.taskHandle0 )
def update(self, port0 = [0,0,0,0,0,0,0,0], port1 = [0,0,0,0]):
if len(port0) != 8:
raise ValueError('port0 argument must have 8 values')
if len(port1) != 4:
raise ValueError('port1 argument must have 4 values')
for i in range(len(port0)):
self.port0data[i] = port0[i]
for i in range(len(port1)):
self.port1data[i] = port1[i]
self.CHK(nidaq.DAQmxWriteDigitalLines( self.taskHandle0,
1, 1, float64(10.0),
DAQmx_Val_GroupByChannel,
self.port0data.ctypes.data,
None,
None))
self.CHK(nidaq.DAQmxWriteDigitalLines( self.taskHandle1,
1, 1, float64(10.0),
DAQmx_Val_GroupByChannel,
self.port1data.ctypes.data,
None,
None))
Original comment by mattl...@gmail.com
on 3 Dec 2009 at 1:19
[deleted comment]
I'm also trying to get this to work on windows as well as linux. Here's a first
patch
for windows work: test for platform and load windows dll if on win32.
Should probably specify NIDAQmx.h in setup.cfg, but here just change it to
where it
is on my system.
105,113c105
< if sys.platform == 'win32':
< try:
< libnidaqmx = ctypes.windll.nicaiu # load the DLL
< except WindowsError as err:
< print "Trying to load the national instruments DAQmx dll library on
windows
but can't find the nicaiu.dll. Is it on the PATH? Is NI-DAQmx installed?"
< raise
< else:
< # default: assume we are on linux
< lib = ctypes.util.find_library('nidaqmx')
---
> lib = ctypes.util.find_library('nidaqmx')
115,116c107,108
< if lib is None:
< raise ImportError('Failed to find NI-DAQmx library. Make sure that
libnidaqmx is installed and its location is listed in PATH|LD_LIBRARY_PATH|..')
---
> if lib is None:
> raise ImportError('Failed to find NI-DAQmx library. Make sure that
libnidaqmx
is installed and its location is listed in PATH|LD_LIBRARY_PATH|..')
118c110
< libnidaqmx = ctypes.cdll.LoadLibrary(lib)
---
> libnidaqmx = ctypes.cdll.LoadLibrary(lib)
151,152c143
< #include_nidaqmx_h = '/usr/local/include/NIDAQmx.h'
< include_nidaqmx_h = r'c:/Programs/NationaInstruments/NI-DAQ/DAQmx ANSI C
Dev/include/NIDAQmx.h'
---
> include_nidaqmx_h = '/usr/local/include/NIDAQmx.h'
Original comment by chris.le...@gmail.com
on 23 Dec 2009 at 8:25
Attachments:
Sorry for long delay in responding (I must create issues ml..).
I have commited a patch that adds Windows support to pylibnidaqmx.
The patch is derived from comment #4 but is not tested (users may need
to update include_nidaqmx_h string).
Please report any issues.
Original comment by pearu.peterson
on 8 Jan 2010 at 8:43
Thank you Pearu.
I've now done some tests with r27 with windows xp and NI-DAQmx 8.8 and 9.0. I
believe
the only change that needs to be done is to point to where my include file is
kept.
I also need to becareful that I don't try to start a task if auto_start=True is
specified during a write() as this raises an error.
The on demand DigitalOutTask task works
The buffered write with internal clock timing works with the AnalogOutTask
and I can trigger the AnalogOutTask using an analog trigger.
The test acquisition script doesn't work on my system, but I haven't looked yet
into
why.
Original comment by chris.le...@gmail.com
on 11 Feb 2010 at 1:19
On above comment I meant to say that it applied to revision 26 not r27
Original comment by chris.le...@gmail.com
on 11 Feb 2010 at 1:21
It seems that your include file
c:/Programs/NationaInstruments/NI-DAQ/DAQmx ANSI C
Dev/include/NIDAQmx.h
is in a non-standard place and, in general, its location cannot be
determined automatically. The path
C:\Program Files\National Instruments\NI-DAQ\DAQmx ANSI C Dev\include\NIDAQmx.h
seems more reasonable as a standard path.
Anyway, now the trunk has all NI-DAQ defines for 9.0.x version in a .py and the
include file is not used anymore.
I am closing this issue as fixed. If you find other problems, please report
them as
separate issues.
Original comment by pearu.peterson
on 12 Feb 2010 at 7:39
I agree about the include file. Perhaps I can come up a with a patch to allow
the
setting of the include file location in setup.cfg.
Original comment by chris.le...@gmail.com
on 12 Feb 2010 at 6:46
Original issue reported on code.google.com by
mattl...@gmail.com
on 2 Dec 2009 at 12:11