Esempio n. 1
0
def AI_start_delay(device_name):
    if 'PFI0' not in DAQmxGetDevTerminals(device_name):
        return None
    task = Task()
    clock_terminal = '/' + device_name + '/PFI0'
    rate = DAQmxGetDevAIMaxSingleChanRate(device_name)
    Vmin, Vmax = DAQmxGetDevAIVoltageRngs(device_name)[0:2]
    num_samples = 1000
    chan = device_name + '/ai0'
    task.CreateAIVoltageChan(chan, "", c.DAQmx_Val_RSE, Vmin, Vmax,
                             c.DAQmx_Val_Volts, None)
    task.CfgSampClkTiming("", rate, c.DAQmx_Val_Rising, c.DAQmx_Val_ContSamps,
                          num_samples)
    task.CfgDigEdgeStartTrig(clock_terminal, c.DAQmx_Val_Rising)

    start_trig_delay = float64()
    delay_from_sample_clock = float64()
    sample_timebase_rate = float64()

    task.GetStartTrigDelay(start_trig_delay)
    task.GetDelayFromSampClkDelay(delay_from_sample_clock)
    task.GetSampClkTimebaseRate(sample_timebase_rate)

    task.ClearTask()

    total_delay_in_ticks = start_trig_delay.value + delay_from_sample_clock.value
    total_delay_in_seconds = total_delay_in_ticks / sample_timebase_rate.value
    return total_delay_in_seconds
Esempio n. 2
0
def AI_start_delay(device_name):
    """Empirically determines the analog inputs' start delay.

    Args:
        device_name (str): NI-MAX device name

    Returns:
        float: Analog input start delay in seconds. `None` if
        analog inputs not supported.
    """
    if 'PFI0' not in DAQmxGetDevTerminals(device_name):
        return None
    task = Task()
    clock_terminal = '/' + device_name + '/PFI0'
    rate = DAQmxGetDevAIMaxSingleChanRate(device_name)
    Vmin, Vmax = DAQmxGetDevAIVoltageRngs(device_name)[0:2]
    num_samples = 1000
    chan = device_name + '/ai0'
    supp_types = DAQmxGetPhysicalChanAITermCfgs(chan)
    if supp_types & c.DAQmx_Val_Bit_TermCfg_RSE:
        input_type = c.DAQmx_Val_RSE
    elif supp_types & c.DAQmx_Val_Bit_TermCfg_Diff:
        input_type = c.DAQmx_Val_Diff
    elif supp_types & c.DAQmx_Val_Bit_TermCfg_PseudoDIFF:
        input_type = c.DAQmx_Val_PseudoDiff
    task.CreateAIVoltageChan(
        chan, "", input_type, Vmin, Vmax, c.DAQmx_Val_Volts, None
    )
    task.CfgSampClkTiming(
        "", rate, c.DAQmx_Val_Rising, c.DAQmx_Val_ContSamps, num_samples
    )
    task.CfgDigEdgeStartTrig(clock_terminal, c.DAQmx_Val_Rising)

    start_trig_delay = float64()
    delay_from_sample_clock = float64()
    sample_timebase_rate = float64()

    try:
        task.GetStartTrigDelay(start_trig_delay)
    except PyDAQmx.DAQmxFunctions.AttributeNotSupportedInTaskContextError:
        # device does not have a Start Trigger Delay property
        # is likely a dynamic signal acquisition device with filter
        # delays instead. 
        start_trig_delay.value = 0
    try:
        task.GetDelayFromSampClkDelay(delay_from_sample_clock)
    except PyDAQmx.DAQmxFunctions.AttributeNotSupportedInTaskContextError:
        # seems simultaneous sampling devices do not have this property, 
        # so assume it is zero
        delay_from_sample_clock.value = 0
    task.GetSampClkTimebaseRate(sample_timebase_rate)

    task.ClearTask()

    total_delay_in_ticks = start_trig_delay.value + delay_from_sample_clock.value
    total_delay_in_seconds = total_delay_in_ticks / sample_timebase_rate.value
    return total_delay_in_seconds
Esempio n. 3
0
def trigger_analog_output(devport, edge_selection):
    '''
    Using PFI to Trigger an Analog Output Generation
    in    devport = Device/port e.g. Dev2/PFI0
    out   task = Task handle
    '''
    logger.info("testlog, Device: {}".format(devport))
    max_num_samples = 2
    task = Task()
    task.CreateAOVoltageChan(devport, '', -10.0, 10.0, DAQmx_Val_Volts, None)
    task.CfgSampClkTiming('', float64(100), DAQmx_Val_Rising,
                          DAQmx_Val_FiniteSamps, uInt64(max_num_samples))

    if edge_selection == 'R':
        task.CfgDigEdgeStartTrig("/Dev2/PFI1", DAQmx_Val_Rising)
        #logger.info("testlog, trigger analog output -function, Rising: {}")
    else:
        task.CfgDigEdgeStartTrig("/Dev2/PFI1", DAQmx_Val_Falling)
        #logger.info("testlog, trigger analog output -function, Falling: {}")
    return task
Esempio n. 4
0
def trigger_analog_input(devport, samples, rate, edge_selection):
    '''
    Using PFI to Trigger an Analog Input Acquisition
    in    devport = Device/port e.g. Dev2/PFI0
    out   task = Task handle
    '''
    logger.info("testlog, Device: {}".format(devport))
    max_num_samples = samples
    task = Task()
    task.CreateAIVoltageChan(devport, '', DAQmx_Val_RSE, -10.0, 10.0,
                             DAQmx_Val_Volts, None)
    task.CfgSampClkTiming('', float64(rate), DAQmx_Val_Rising,
                          DAQmx_Val_FiniteSamps, uInt64(max_num_samples))
    #logger.info("trigger analog input -function, 1: {}")
    if edge_selection == 'R':
        task.CfgDigEdgeStartTrig("/Dev2/PFI0", DAQmx_Val_Rising)
        logger.info("testlog, trigger analog input -function, Rising: {}")
    else:
        task.CfgDigEdgeStartTrig("/Dev2/PFI0", DAQmx_Val_Falling)
        logger.info("testlog, trigger analog input -function, Falling: {}")
    task.StartTask()
    return task
Esempio n. 5
0
def createCOPulseTask(chan,
                      freq,
                      delay,
                      duty,
                      numPulses=4,
                      edge=DAQmx_Val_Rising,
                      triggerSource="PFI0"):
    th = Task()
    th.CreateCOPulseChanFreq(chan, "", DAQmx_Val_Hz, DAQmx_Val_Low, delay,
                             freq, duty)
    th.CfgDigEdgeStartTrig(triggerSource, edge)
    th.CfgImplicitTiming(DAQmx_Val_FiniteSamps, numPulses)
    th.SetTrigAttribute(DAQmx_StartTrig_Retriggerable, True)
    return th
Esempio n. 6
0
def createCOPulseTask2(chan,
                       totTime,
                       delay,
                       pulseWidth,
                       numPulses=4,
                       edge=DAQmx_Val_Rising,
                       triggerSource="PFI0"):
    th = Task()
    #th.CreateCOPulseChanFreq ( chan, "", DAQmx_Val_Hz, DAQmx_Val_Low, delay, freq,
    th.CreateCOPulseChanTime(chan, "", DAQmx_Val_Seconds, DAQmx_Val_Low, delay,
                             totTime - pulseWidth, pulseWidth)
    th.CfgDigEdgeStartTrig(triggerSource, edge)
    th.CfgImplicitTiming(DAQmx_Val_FiniteSamps, numPulses)
    th.SetTrigAttribute(DAQmx_StartTrig_Retriggerable, True)
    return th
Esempio n. 7
0
def AI_filter_delay(device_name):
    """Determine the filter delay for dynamic signal acquistion devices.

    Returns the delay in clock cycles. Absolute delay will vary with sample rate.
    
    Args:
        device_name (str): NI-MAX device name

    Returns:
        int: Number of analog input delays ticks between task start and acquisition start.
    """
    if 'PFI0' not in DAQmxGetDevTerminals(device_name):
        return None
    task = Task()
    clock_terminal = '/' + device_name + '/PFI0'
    rate = DAQmxGetDevAIMaxSingleChanRate(device_name)
    Vmin, Vmax = DAQmxGetDevAIVoltageRngs(device_name)[0:2]
    num_samples = 1000
    chan = device_name + '/ai0'
    task.CreateAIVoltageChan(
        chan, "", c.DAQmx_Val_PseudoDiff, Vmin, Vmax, c.DAQmx_Val_Volts, None
    )
    task.CfgSampClkTiming(
        "", rate, c.DAQmx_Val_Rising, c.DAQmx_Val_ContSamps, num_samples
    )
    task.CfgDigEdgeStartTrig(clock_terminal, c.DAQmx_Val_Rising)

    start_filter_delay = float64()
    sample_timebase_rate = float64()

    # get delay in number of clock samples
    task.SetAIFilterDelayUnits("", c.DAQmx_Val_SampleClkPeriods)

    task.GetAIFilterDelay("", start_filter_delay)
    task.GetSampClkTimebaseRate(sample_timebase_rate)

    task.ClearTask()

    return int(start_filter_delay.value)
Esempio n. 8
0
from PyDAQmx import Task
import PyDAQmx
import numpy as np
from ctypes import byref

pulse = Task()
pulse.CreateCOPulseChanTime("/Dev2/ctr0", "LED pulse",
                            PyDAQmx.DAQmx_Val_Seconds, PyDAQmx.DAQmx_Val_Low,
                            1.00, 10, 10)
pulse.StartTask()

voltage = Task()
voltage.CreateAOVoltageChan("/Dev2/ao1", "LED", 0, 5, PyDAQmx.DAQmx_Val_Volts,
                            None)
voltage.CfgImplicitTiming(PyDAQmx.DAQmx_Val_ContSamps, 1000)
voltage.CfgDigEdgeStartTrig("/Dev2/pfi0", PyDAQmx.DAQmx_Val_Rising)
voltage.WriteAnalogScalarF64(1, 0, 3, None)

# voltage.CfgSampClkTiming(None,1000,PyDAQmx.DAQmx_Val_Rising,PyDAQmx.DAQmx_Val_ContSamps,4000)
# voltage.CfgDigEdgeStartTrig("/Dev2/pfi0",PyDAQmx.DAQmx_Val_Rising)
# voltage.StartTask()
# voltage.WriteAnalogF64(1,0,voltage_out,None)
# taskHandle,4000,0,10.0,DAQmx_Val_GroupByChannel,data,&written,NULL)

# class LED(Task):
#     def __init__(self):
#         Task.__init__(self)
#         self.CreateAOVoltageChan("/Dev2/ao1","LED",0,5,PyDAQmx.DAQmx_Val_Volts,None)
#         self.CfgSampClkTiming(None,1000,PyDAQmx.DAQmx_Val_Rising,PyDAQmx.DAQmx_Val_ContSamps,1000)
#         self.CfgDigEdgeStartTrig("/Dev2/pfi0",PyDAQmx.DAQmx_Val_Rising)
#         self.AutoRegisterDoneEvent(0)
class digFreqGenerator(object):
    def __init__(self):
        self.counter = ''
        self.Task = Task()
        self.initialized = False
        self.initialDelay = 0
        self.dutyCycle = 0.50
        self.frequency = 1e6
        self._numberOfPulses = 0
        self.status = 0
        self._startTriggerSource = ''
        self.triggerType = TriggerType.Software
        self.timeout = -1

    def _getStartTriggerSource(self):
        if self.initialized:
            buffSize = uInt32(255)
            buff = ctypes.create_string_buffer(buffSize.value)
            self.status = self.Task.GetDigEdgeStartTrigSrc(buff, buffSize)
            self._startTriggerSource = buff.value
        return self._startTriggerSource 

    def _setStartTriggerSource(self, value):
        if self.initialized:
            self.status = self.Task.SetDigEdgeStartTrigSrc(value)
            #value = self._getStartTriggerSource()
        self._startTriggerSource = value

    startTriggerSource = property(_getStartTriggerSource,
            _setStartTriggerSource)

    def _getNumberOfPulses(self):
        if self.initialized:
            sampPerChan = uInt32()
            self.status = self.Task.GetSampQuantSampPerChan(sampPerChan)
            self._numberOfPulses = sampPerChan.value
        return self._numberOfPulses

    def _setNumberOfPulses(self, value):
        if self.initialized:
            self.status = self.Task.SetSampQuantSampPerChan(value)
            if value > 0:
                self.status = self.Task.SetSampQuantSampMode(
                        DAQmx_Val_FiniteSamps)
            else:
                self.status = self.Task.SetSampQuantSampMode(
                        DAQmx_Val_ContSamps)
        self._numberOfPulses = value
            

    numberOfPulses = property(_getNumberOfPulses, _setNumberOfPulses)
        

    def init(self, counter=None):
        if counter is not None:
            self.counter = counter
        self.status = self.Task.CreateCOPulseChanFreq(self.counter, '',
                DAQmx_Val_Hz, DAQmx_Val_Low,
                numpy.float64(self.initialDelay),
                numpy.float64(self.frequency),
                numpy.float64(self.dutyCycle))
        if self._numberOfPulses > 0:
            self.status = self.Task.CfgImplicitTiming(DAQmx_Val_FiniteSamps,
                    uInt64(self._numberOfPulses))
        else:
            self.status = self.Task.CfgImplicitTiming(DAQmx_Val_ContSamps,
                    uInt64(int(1e6)))
        if self.triggerType == TriggerType.Hardware:
            self.status = self.Task.CfgDigEdgeStartTrig(
                    self._startTriggerSource, DAQmx_Val_Rising)
            self.status = self.Task.SetStartTrigRetriggerable(bool32(True))
        self.initialized = True

    def _getOutputTerm(self):
        buffSize = uInt32(255)
        buff = ctypes.create_string_buffer(buffSize.value)
        self.status = self.Task.GetCOPulseTerm(self.counter, buff,
                buffSize)
        return buff.value

    def _setOutputTerm(self, term = 'PFI0'):
        self.status = self.Task.SetCOPulseTerm(self.counter, term)

    outputTerm = property(_getOutputTerm, _setOutputTerm)

    def start(self):
        self.status = self.Task.StartTask()

    def waitUntilDone(self):
        self.status = self.Task.WaitUntilTaskDone(self.timeout)

    def stop(self):
        retriggerable = bool32()
        self.status = self.Task.GetStartTrigRetriggerable(retriggerable)
        try:
            if retriggerable == 0:
                self.status = self.Task.StopTask()
        except DAQError as e:
            print(e.error)
            print(retriggerable.value)
            if e.error == 200010 and retriggerable.value == 1:
                print('caught')
                pass
            else:
                raise e

    def close(self):
        self.status = self.Task.ClearTask()
        self.Task = Task()
        self.initialized = False
Esempio n. 10
0
class pCounter(object):
    ## This function is the constructor for the pCounter class.
    #
    #  It creates internal variables required to perform functions within
    #  the class. This function does not initialize any hardware.
    #  @param self The object pointer.
    def __init__(self, **kwargs):
        #super(pCounter, self).__init__()
        ## The string that identifies the DAQmx device and counter
        #  for the counter that is used to count edges.
        #
        #  Example: PXISlot5/ctr0
        self.edgeCounter = ''

        ## The string that identifies the DAQmx device and counter
        #  for the counter that is used to create the sample clock.
        #
        #  Example: /PXI1Slot5/ctr0
        self.clockCounter = ''

        ##  A boolean that enables the start trigger.
        #
        #  The default is false, which disables the start trigger.
        #  The measurement will immediately start when the start()
        #  method is called.
        #  A true value will make the measurement start when a digital
        #  trigger is received on the line specified by the triggerSource
        #  variable.
        self.enableStartTrigger = False

        ## A string that identifies the DAQmx digital line that will
        #  be used as an input to the edge counter.
        #
        #  Default: PFI0
        self.edgeCntrTerm = kwargs.get('edgeCntrTerm', 'PFI0')

        self._triggerClkSource = 'Ctr0InternalOutput'

        ## A string that identifies the DAQmx digital line that will
        #  be used as the start trigger.
        #
        #  Default: PFI1
        self.triggerSource = 'PFI1'

        ## A string that identifies the DAQmx digital line that will
        #  output the sample clock.
        #
        #  Default: PFI12
        self.clockSourceTerm = kwargs.get('clockSourceterm', 'PFI12')

        ## The task reference for the edge counter.
        self.edgeCntrTask = Task()

        ## The task reference for the sample clock counter.
        self.clockCntrTask = Task()

        ## @var samples
        #  This is the number of samples to take.  It is the size
        #  of the data array returned by the read() method.
        self._samples = kwargs.get('samples', None)

        ## @var sampleRate
        #  This is the sample rate to use when counting edges.
        self._sampleRate = kwargs.get('sampleRate', None)

        ## @var acqTime
        #  This is the time in milliseconds for a full acquisition
        #  period.
        self._acqTime = None

        ## @var binTime
        #  This is the time in millisenconds to take a single sample.
        self._binTime = None

        self._status = int32()

        ## This is the time to wait for a start trigger.
        #
        #  If the timeout passes, then an error is generated. Ignore
        #  this variable if the start trigger is disabled.
        self.timeout = kwargs.get('timeout', 1)
        self._samplesRead = None

    def _calcBinAndAcq(self):
        self._binTime = 1000. / self._sampleRate
        self._acqTime = (self._samples - 1.) * self._binTime

    def _calcSampsAndSampRate(self):
        self._sampleRate = 1000 / self._binTime
        self._samples = int((self._acqTime / self._binTime) + 1)

    def _getSamples(self):
        return self._samples

    def _setSamples(self, value):
        self._samples = value
        if self._sampleRate:
            self._calcBinAndAcq()

    samples = property(_getSamples, _setSamples)

    def _getSampleRate(self):
        return self._sampleRate

    def _setSampleRate(self, value):
        self._sampleRate = value
        if self._samples:
            self._calcBinAndAcq()

    sampleRate = property(_getSampleRate, _setSampleRate)

    def _getBinTime(self):
        return self._binTime

    def _setBinTime(self, value):
        self._binTime = value
        if self._acqTime:
            self._calcSampsAndSampRate()

    binTime = property(_getBinTime, _setBinTime)

    def _getAcqTime(self):
        return self._acqTime

    def _setAcqTime(self, value):
        self._acqTime = value
        if self._binTime:
            self._calcSampsAndSampRate()

    acqTime = property(_getAcqTime, _setAcqTime)

    ## This function initializes the pCounter class and opens a
    #  reference to the DAQmx device(s).
    #
    #  If specifiying a acqTime and binTime or samples and sampleRate,
    #  only one pair of parameters need to be provided.  When specifying
    #  acqTime and binTime, the samples and sampleRate are calculated.
    #  When specifying the samples and sampleRate, the acqTime and
    #  binTime are calculated.
    #
    #  @param self The object pointer.
    #  @param clockCounter The string that identifies the DAQmx
    #  device and counter for the counter that is used to create
    #  the sample clock.
    #  @param edgeCounter The string that identifies the DAQmx
    #  device and counter for the counter that is used to count edges.
    #  @param acqTime This is the time in milliseconds for a full
    #  acquisition period.
    #  @param binTime This is the time in millisenconds to take a
    #  single sample.
    #  @param samples The number of samples for the pCounter to take.
    #  @param sampleRate The frequency of the samples taken by the
    #  pCounter.
    def init(self,
             clockCounter=None,
             edgeCounter=None,
             acqTime=None,
             binTime=None,
             samples=None,
             sampleRate=None):
        if edgeCounter:
            self.edgeCounter = edgeCounter
        if clockCounter:
            self.clockCounter = clockCounter

        if samples and sampleRate:
            self._samples = samples
            self._sampleRate = sampleRate
            self._calcBinandAcq()

        if acqTime and binTime:
            self._acqTime = acqTime
            self._binTime = binTime
            self._calcSampsAndSampRate()

        # Setup the Edge Counter
        self._status = self.edgeCntrTask.CreateCICountEdgesChan(
            self.edgeCounter, '', DAQmx_Val_Rising, 0, DAQmx_Val_CountUp)
        self._status = self.edgeCntrTask.SetCICountEdgesTerm(
            self.edgeCounter, self.edgeCntrTerm)
        self._status = self.edgeCntrTask.CfgSampClkTiming(
            self._triggerClkSource, float64(self._sampleRate),
            DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, uInt64(self._samples + 1))

        # Setup the Clock Source Counter
        self._status = self.clockCntrTask.CreateCOPulseChanFreq(
            self.clockCounter, '', DAQmx_Val_Hz, DAQmx_Val_Low, 0,
            float64(self._sampleRate), float64(0.5))
        self._status = self.clockCntrTask.SetCOPulseTerm(
            self.clockCounter, self.clockSourceTerm)
        self._status = self.clockCntrTask.CfgImplicitTiming(
            DAQmx_Val_ContSamps, uInt64(self._samples + 1))
        if self.enableStartTrigger:
            self._status = self.clockCntrTask.CfgDigEdgeStartTrig(
                self.triggerSource, DAQmx_Val_Rising)

    ## This function initializes the pCounter class using the
    #  chassis config file and opens a reference to the DAQmx device(s).
    #
    #  @param self The object reference.
    #  @param filepath The path to the chassis config file.
    def initFromFile(self, filepath):
        from .chassisConfigParser import chassisConfigParser
        config = chassisConfigParser()
        edgeCounter, clockCounter = config.readCntrSection(filepath)
        self.init(clockCounter, edgeCounter)

    ## This function starts the measurement.
    #
    #  If the start trigger is enabled, then a the pCounter waits
    #  for that digital trigger.  Otherwise the measurement takes
    #  place immediately.
    #  @param self The object pointer.
    def start(self):
        self._status = self.edgeCntrTask.StartTask()
        self._status = self.clockCntrTask.StartTask()

    ## This function stops the measurement.
    #
    #  It needs to be called everytime the start() method is called.
    #  @param self The object pointer.
    def stop(self):
        self._status = self.edgeCntrTask.StopTask()
        self._status = self.clockCntrTask.StopTask()

    ## This function returns an array of the edge counts with an
    #  array size equal to the number of samples.
    #
    #  @param self The object pointer.
    def read(self):
        samplesRead = int32()
        data = np.zeros(self._samples + 1, dtype=np.uint32)

        self._status = self.edgeCntrTask.ReadCounterU32(
            int32(self._samples + 1), float64(self.timeout), data,
            uInt32(self._samples + 1), ctypes.byref(samplesRead), None)
        self._samplesRead = samplesRead.value

        dataDelta = []
        for i, item in enumerate(data):
            if i > 0:
                dataDelta.append(item - preValue)
            preValue = item

        length = len(dataDelta)
        dataSum = 0
        for item in dataDelta:
            dataSum += item
        mean = float(dataSum / length)

        sqSum = 0
        for item in dataDelta:
            sq = np.square(item - mean)
            sqSum += sq
        stdDev = sqrt(sqSum / length)

        return dataDelta, mean, stdDev

    ## This function performs the start(), read(), and stop() methods
    #  in one function call.
    #
    #  This is useful for when the results of the read() method can be
    #  retrieved immediately after a start()
    #  @param self The object pointer.
    def measure(self):
        # Start the Tasks
        self.start()

        # Read the data
        data, mean, stdDev = self.read()

        # Stop the Tasks
        self.stop()

        return data, mean, stdDev

    ## This function closes the refences to the DAQmx devices.
    #
    #  @param self The object pointer.
    def close(self):
        self._status = self.edgeCntrTask.ClearTask()
        self.edgeCntrTask = Task()

        self._status = self.clockCntrTask.ClearTask()
        self.clockCntrTask = Task()

    ## This function is the destructor for the pCounter class.
    #
    #  It deletes internal variables and closes the references to
    #  the DAQmx devices if they are not already closed.
    #  @param self The object pointer.
    def __del__(self):
        self.close()

        del self.edgeCounter
        del self.clockCounter
        del self.enableStartTrigger
        del self.edgeCntrTerm
        del self._triggerClkSource
        del self.triggerSource
        del self.clockSourceTerm
        del self.edgeCntrTask
        del self.clockCntrTask
        del self._samples
        del self._sampleRate
        del self._acqTime
        del self._binTime
        del self._status
        del self.timeout
        del self._samplesRead
Esempio n. 11
0
class TriggerOutputDig(object):
    t = None
    wvfms = None
    Nsamps = None
    sampleRate = None
    pulseLength = None

    def __init__(self, port="Dev12/port0", startTrigChan="PFI0"):
        self.th = Task()  #Task.__init__(self)
        self.th.CreateDOChan(port, "", DAQmx_Val_ChanForAllLines)
        #self.setTiming(sampleRate, pulseLength)
        self.th.CfgDigEdgeStartTrig(startTrigChan, DAQmx_Val_Rising)
        self.th.SetStartTrigRetriggerable(True)
        #DAQmxLoadTask("WvfmOutputTask", byref(self.taskHandle))

    def start(self):
        self.th.StartTask()

    def stop(self):
        try:
            self.th.StopTask()
        except DAQError as e:
            if e.error == 200010:
                self.th.StopTask()
            else:
                raise (e)

    def setTiming(self, sampleRate, waveformLength):
        Nsamps = int(waveformLength * sampleRate)
        #self.th.CfgSampClkTiming("",sampleRate,DAQmx_Val_Rising,DAQmx_Val_ContSamps, 5*Nsamps);
        self.th.CfgSampClkTiming("", sampleRate, DAQmx_Val_Rising,
                                 DAQmx_Val_FiniteSamps, Nsamps)
        self.sampleRate = sampleRate
        self.Nsamps = Nsamps

    def reset(self):
        try:
            self.stop()
            sleep(0.2)
        except DAQError:
            pass
        finally:
            self.start()

    def setWaveforms(self, t, *wvfms):
        Npts = t.size
        sampleRate = 1. / (t[1] - t[0])
        totalLength = Npts / sampleRate
        self.setTiming(sampleRate, totalLength)

        wvfmPort = np.zeros(t.size, dtype='u4')
        for k, wv in enumerate(wvfms):
            wv[:] = np.where(wv, 1, 0)
            wv = wv.astype('u4')
            wvfmPort += (k + 1) * wv

        written = int32()
        self.th.WriteDigitalU32(1 * wvfmPort.size, 1, 10,
                                DAQmx_Val_GroupByChannel,
                                np.hstack(1 * [wvfmPort]).astype('u4'),
                                byref(written), None)
        self.t = t
        self.wvfms = wvfms
        return self.t, wvfmPort
Esempio n. 12
0
class AnalogOutput(object):

    ## This function is a constructor for the AnalogOutput class.
    #
    # It creates the internal variables required to perform functions within the
    # class. This function does not initialize any hardware.
    def __init__(self):

        ## The DAQmx task reference.
        self.taskRef = Task()

        ## This is a boolean that is true when the DAQmx task has been initialized.
        self.initialized = False

        ## This is the status of the DAQmx task.
        #
        #  A value greater than 0 means that an error has occurred. When the status
        #  is greater than 0 an error should be reported by the class.
        self.status = int32()

        ## @var sampleRate
        #  This is the sample rate of the analog output.
        self._sampleRate = 100e3

        ## @var numChannels
        #  This is the number of channels configured in the task.
        self._numChannels = 0

        ## @var samplesPerChannel
        #  This is the number of samples per channel that will be
        #  generated in Finite mode.
        self._samplesPerChannel = 100

        ## @var clkSource
        #  This is the sample clock source terminal.  It can be set to an
        #  internal clock or external clock such as a PFI line i.e. "/PXI1Slot3/PFI15."
        self._clkSource = ''

        ## @var startTriggerSource
        #  This is the start trigger source terminal.  The software
        #  ignores this value when the triggerType is set to "Software". Otherwise when
        #  the triggerType is "Hardware," this terminal is used to start analog
        #  generation.  Example Value: "/PXI1Slot3/PFI0"
        self._startTriggerSource = ''

        ## @var pauseTriggerSource
        #  The source terminal of the pause trigger.  This can be
        #  any PFI or backplane trigger such as 'PFI5' and 'PXI_TRIG5'
        self._pauseTriggerSource = ''

        ## This is the start trigger terminal of the NI-Sync card.
        #
        #  Setting this value will make sure that the start trigger will be
        #  propogated through the PXI backplane. If there is no sync card needed
        #  leave the value default.
        self.startTriggerSyncCard = ''

        ## This is the mode of operation for the analog outputs.
        #
        #  There are currently three modes available.  Static mode is where one
        #  static voltage is set with no need for a sample clock.  Finite mode is
        #  where a finite number of voltages will be set at a sample clock rate.
        #  Continuous mode is where a sequence of voltages are generated at a sample
        #  rate and then repeated until the stop() method is called.
        self.mode = dutil.Mode.Finite

        ## The trigger type for the analog outputs.
        #
        #  There are currently two trigger types - "Software" and
        #  "Hardware."  The "Software" mode means that analog output channels are not
        #  syncronized. While "Hardware" means that analog output channels are
        #  syncronized to a start trigger.  The startTriggerSouce attribute must be
        #  configured appropriately.
        self.triggerType = dutil.TriggerType.Software

        ## The number of times to iterate over a Finite number of samples.
        #
        #  This value is only useful in the "Finite" mode.  It is the number of
        #  times that a sequence of voltages will be looped.  The default is allways 1.
        self.loops = 1

        ## The estimated time to generate the samples for a Finite generation.
        #
        #  Once the input buffer of the analog input is configured, the
        #  amount of time it takes to generate the voltages in the buffer can be
        #  estimated.  This is a function of the sample rate and the number of samples
        #  per channel. (This attribute is for internal use only.  This attribute may
        #  not return an accurate value.)
        self.estAcqTime = 0

        ## The analog output buffer.
        #
        #  This is the data that is stored in the buffer of the Analog Output card.
        self.buff = None

        self._timeoutPad = 0.01

    def _getDone(self):
        done = bool32()
        if self.initialized:
            self.status = self.taskRef.GetTaskComplete(ctypes.byref(done))
        else:
            done.value = 1
        return bool(done.value)

    ## @var done
    #  Returns the task done status.
    #
    #  This mode works differently depending on the mode. <br />
    #  <ul>
    #  <li><B>Static and Continuous</B>: done is false after a start
    #  method and true</li>
    #  only after a stop method.
    #  <li><B>Finite</B>: done is false until all samples are
    #  generated.</li></ul>
    done = property(_getDone)

    def _getPauseTriggerSource(self):
        if self.initialized:
            buffSize = uInt32(255)
            buff = ctypes.create_string_buffer(buffSize.value)
            self.status = self.taskRef.GetDigLvlPauseTrigSrc(buff, buffSize)
            self._pauseTriggerSource = buff.value
        return self._pauseTriggerSource

    def _setPauseTriggerSource(self, value):
        if self.initialized:
            if value == '':
                self.status = self.taskRef.SetPauseTrigType(DAQmx_Val_None)
                self.status = self.taskRef.ResetDigLvlPauseTrigSrc()
            else:
                self.status = self.taskRef.SetDigLvlPauseTrigWhen(
                    DAQmx_Val_High)
                self.status = self.taskRef.SetPauseTrigType(DAQmx_Val_DigLvl)
                self.status = self.taskRef.SetDigLvlPauseTrigSrc(value)
        self._pauseTriggerSource = value

    pauseTriggerSource = property(_getPauseTriggerSource,
                                  _setPauseTriggerSource)

    ## Initializes the analog outputs based on the object's configuration.
    #  @param self The object pointer.
    #  @param physicalChannel A string representing the device and analog
    #  output channels. Example Value: "PXI1Slot3/ao0:7"
    def init(self, physicalChannel):
        self.__createTask(physicalChannel)
        self.initialized = True

        #Finite Mode
        if self.mode == dutil.Mode.Finite:
            self.status = self.taskRef.SetWriteRegenMode(DAQmx_Val_AllowRegen)
            self.__configTiming(DAQmx_Val_FiniteSamps)

        #Continuous Mode
        elif self.mode == dutil.Mode.Continuous:
            self.status = self.taskRef.SetWriteRegenMode(DAQmx_Val_AllowRegen)
            self.__configTiming(DAQmx_Val_ContSamps)

        #Static Mode
        elif self.mode == dutil.Mode.Static:
            self.setSampleRate(self._sampleRate)
            self.setSamplesPerChannel(1)

        self.pauseTriggerSource = self._pauseTriggerSource
        #print self.samplesPerChannel
        #print self._sampleRate
        #print self.clkSource
        #print self.startTriggerSource

    ## This function returns the samples per channel configured in the DAQmx Task.
    #  @param self The object pointer.
    def getSamplesPerChannel(self):
        if self.initialized:
            samplesPerChannel = uInt64()
            self.status = self.taskRef.GetSampQuantSampPerChan(
                ctypes.byref(samplesPerChannel))
            self._samplesPerChannel = samplesPerChannel.value
        return self._samplesPerChannel

    ## This function sets the samples per channel in the DAQmx Task.
    #  @param self The object pointer.
    #  @param value The value to set the samples per channel.
    def setSamplesPerChannel(self, value):
        if self.initialized:
            self.status = self.taskRef.SetSampQuantSampPerChan(uInt64(value))
        self._samplesPerChannel = value

    ## This funciton deletes the samplesPerChannel variable inside the AnalogOutput
    #  object.
    #
    #  It is an internal function that is called in the class destructor. It should
    #  not be called.
    def _delSamplesPerChannel(self):
        """
        This funciton deletes the samplesPerChannel variable inside the AnalogOutput
        object.  It is an internal function that is called in the class destructor.
        It should not be called.
        """
        del self._samplesPerChannel

    samplesPerChannel = property(getSamplesPerChannel, setSamplesPerChannel,
                                 _delSamplesPerChannel)

    ## This function returns the sample clock source configured in the DAQmx Task.
    #  @param self The object pointer.
    def getClkSource(self):
        if self.initialized:
            buffSize = uInt32(255)
            buff = ctypes.create_string_buffer(buffSize.value)
            self.status = self.taskRef.GetSampClkSrc(buff, buffSize)
            self._clkSource = buff.value
        return self._clkSource

    ## This function sets the sample clock source in the DAQmx Task.
    #  @param self The object pointer.
    #  @param value The string value for the clock source terminal.
    def setClkSource(self, value):
        if self.initialized:
            self.status = self.taskRef.SetSampClkSrc(value)
            value = self.getClkSource()
        self._clkSource = value

    ## This function deletes the clkSource variable within the AnalogOutput object.
    #
    #   It is an internal function that is called in the class destructor.  It should
    #   not be called.
    def _delClkSource(self):
        del self._clkSource

    clkSource = property(getClkSource, setClkSource, _delClkSource)

    ## This function return the start trigger source configured in the DAQmx Task.
    #  @param self The object pointer.
    def getStartTriggerSource(self):
        if self.initialized:
            buffSize = uInt32(255)
            buff = ctypes.create_string_buffer(buffSize.value)
            self.status = self.taskRef.GetDigEdgeStartTrigSrc(buff, buffSize)
            self._startTriggerSource = buff.value
        return self._startTriggerSource

    ## This function sets the start trigger source in the DAQmx Task.
    #  @param self The object pointer.
    #  @param value The string vaue of the start trigger source.
    #  Example value: "\PXI1Slot3\PFI0"
    def setStartTriggerSource(self, value):
        if self.initialized:
            self.status = self.taskRef.SetDigEdgeStartTrigSrc(value)
            value = self.getStartTriggerSource()
        self._startTriggerSource = value

    ## This function deletes the startTriggerSource variable within the AnalogOutput object.
    #
    #   It is an internal function that is called in the class destructor.  It should
    #   not be called.
    def _delStartTriggerSource(self):
        del self._startTriggerSource

    startTriggerSource = property(getStartTriggerSource, setStartTriggerSource,
                                  _delStartTriggerSource)

    ## This function returns the number of channels configured in the DAQmx Task.
    #  @param self The object pointer.
    def getNumChannels(self):
        if self.initialized:
            numChannels = uInt32()
            self.status = self.taskRef.GetTaskNumChans(
                ctypes.byref(numChannels))
            self._numChannels = numChannels.value
        return self._numChannels

    numChannels = property(getNumChannels)

    ## This function returns the sample rate configured in the DAQmx Task.
    #  @param self The object pointer.
    def getSampleRate(self):
        if self.initialized:
            sampleRate = float64()
            self.status = self.taskRef.GetSampClkRate(ctypes.byref(sampleRate))
            self._sampleRate = sampleRate.value
        return self._sampleRate

    ## This funciton sets the sample rate in the DAQmx Task.
    #  @param self The object pointer.
    #  @param value The value of the sample rate.
    def setSampleRate(self, value):
        if self.initialized:
            self.status = self.taskRef.SetSampClkRate(float64(value))
        self._sampleRate = value

    ## This function deletes the sample rate variable inside the AnalogOutput object.
    #  @param self The object pointer.
    def _delSampleRate(self):
        del self._sampleRate

    sampleRate = property(getSampleRate, setSampleRate, _delSampleRate)

    ## This function returns a 1D numpy array of samples with random voltages.
    #  The returned value is intended to be used to write samples to the buffer with
    #  the writeToBuffer() method.
    #  @param self The object pointer.
    #  @param numChannels The number of channels to generate. If this parameter is
    #  not provided, Then the function will generate the number of channels configured
    #  in the analog output task.
    def createTestBuffer(self, numChannels=0):
        numChannels = numChannels if numChannels > 0 else self.getNumChannels()
        return numpy.float64(
            numpy.random.rand(self._samplesPerChannel * numChannels))

    ## This function returns a 1D numpy array of sine waves.  The returned
    #  value is intended to be used to write samples to the buffer with the
    #  writeToBuffer() method.
    #  @param self The object pointer.
    def createSineTestBuffer(self):
        from .createSineWave import createSineWave

        numChannels = self.getNumChannels()
        for i in range(numChannels):
            data = createSineWave(10, 100e3, self._sampleRate,
                                  self._samplesPerChannel,
                                  ((2 * numpy.pi) / numChannels) * i)
            if i == 0:
                sineData = data['amplitude']
            else:
                sineData = numpy.append(sineData, data['amplitude'])

        return sineData

    ## This function writes the specified values into the buffer.
    #  @param self The object pointer.
    #  @param data This is a 1D 64-bit floating point numpy array that contians data
    #  for each channel.  Channels are non-interleaved (channel1 n-samples then
    #  channel2 n-samples).
    def writeToBuffer(self, data):
        autostart = self.mode == dutil.Mode.Static
        self.buff = data

        samplesWritten = int32()
        self.status = self.taskRef.WriteAnalogF64(self._samplesPerChannel,
                                                  autostart, 10,
                                                  DAQmx_Val_GroupByChannel,
                                                  data,
                                                  ctypes.byref(samplesWritten),
                                                  None)
        return samplesWritten.value

    ## This function starts the analog output generation.
    #  @param self The object pointer.
    def start(self):
        self.status = self.taskRef.StartTask()

    ## This functions waits for the analog output generation to complete.
    #  @param self The object pointer.
    def waitUntilDone(self):
        sampPerChan = uInt64()
        self.status = self.taskRef.GetSampQuantSampPerChan(
            ctypes.byref(sampPerChan))
        self.estAcqTime = (self.loops * sampPerChan.value) / self._sampleRate
        #print 'SamplesPerChannel: ' + str(sampPerChan.value)
        #print 'Estimated Acquisition Time: ' + str(self.estAcqTime)
        #if (self.estAcqTime >= 0.01 and self.mode != dutil.Mode.Static):
        if self.mode != dutil.Mode.Static:
            self.status = self.taskRef.WaitUntilTaskDone(
                float64(self.estAcqTime + self._timeoutPad))

    ## This function stops the analog output generation.
    #  @param self The object pointer.
    def stop(self):
        self.status = self.taskRef.StopTask()

    def __createTask(self, physicalChannel):
        """
        This is a private method that creates the Task object for use inside the
        AnalogOutput class."""
        self.status = self.taskRef.CreateAOVoltageChan(physicalChannel, "",
                                                       -10, 10,
                                                       DAQmx_Val_Volts, None)

    def __configTiming(self, sampleMode):
        """
        This is a private method that configures the timing for the Analog Output
        class.
        """
        totalSamples = self._samplesPerChannel * self.loops
        onDemand = bool32()
        self.status = self.taskRef.GetOnDemandSimultaneousAOEnable(
            ctypes.byref(onDemand))
        #print 'On Demand: ' + str(onDemand.value)
        #print 'Trigger Type: ' + str(self.triggerType)
        #print 'Software Trigger Type: ' + str(dutil.TriggerType.Software)
        if self.triggerType == dutil.TriggerType.Software:
            #print 'Software Timing'
            self.status = self.taskRef.CfgSampClkTiming(
                'OnboardClock', float64(self._sampleRate), DAQmx_Val_Rising,
                sampleMode, uInt64(totalSamples))

        elif self.triggerType == dutil.TriggerType.Hardware:
            #print 'Hardware Timing'
            self.status = self.taskRef.CfgSampClkTiming(
                self._clkSource, float64(self._sampleRate), DAQmx_Val_Falling,
                sampleMode, uInt64(totalSamples))
            self.status = self.taskRef.CfgDigEdgeStartTrig(
                self._startTriggerSource, DAQmx_Val_Rising)
            if self.startTriggerSyncCard != '':
                DAQmxConnectTerms(self.startTriggerSyncCard,
                                  self._startTriggerSource,
                                  DAQmx_Val_DoNotInvertPolarity)

    ## This function will close connection to the analog output device and channels.
    #  @param self The object pointer.
    def close(self):
        self.initialized = False
        if self.startTriggerSyncCard != '':
            DAQmxDisconnectTerms(self._startTriggerSource,
                                 self.startTriggerSyncCard)

        self.status = self.taskRef.ClearTask()
        self.taskRef = Task()

    ## This is the destructor for the AnalogOutput Class.
    #  @param self The object pointer.
    def __del__(self):
        if self.initialized:
            self.close()

        del self.taskRef
        del self.initialized
        del self.status
        del self.sampleRate
        del self._numChannels
        del self.samplesPerChannel
        del self.clkSource
        del self.startTriggerSource
        del self.startTriggerSyncCard
        del self.mode
        del self.triggerType
        del self.loops
        del self.estAcqTime
y_freq = 200.0
written = ni.int32()

waveform, t = gen_waveform(x_freq, y_freq, num_AO_samples, AO_sample_rate,
                           amplitude)

AO_task = Task()
AO_task.CreateAOVoltageChan("/Dev1/ao0:1", "", -10.0, 10.0, ni.DAQmx_Val_Volts,
                            None)
#AO_task.StartTask()

# Specify Sample Clock Timing
AO_task.CfgSampClkTiming("OnboardClock", AO_sample_rate, ni.DAQmx_Val_Rising,
                         ni.DAQmx_Val_ContSamps, num_AO_samples)
#Trigger on the counter. PFI12 is the output of counter 0
AO_task.CfgDigEdgeStartTrig("/Dev1/PFI12", ni.DAQmx_Val_Rising)

# ## Analog input
# ---------------------------------------------------------------------------------------------------------------------------------------------

# In[36]:

# Define analog input task
AI_task = Task()
AI_task.CreateAIVoltageChan("/Dev1/ai1", "", ni.DAQmx_Val_RSE, -10.0, 10.0,
                            ni.DAQmx_Val_Volts, None)

# In[37]:

# set analog input parameters
num_images = 1
Esempio n. 14
0
class DigitalOutput(object):
    #-- Sample Rate Property
    ## This function returns the sample rate configured in the DAQmx Task.
    #  @param self The object reference.
    def getSampleRate(self):
        if self.initialized:
            sampleRate = float64()
            self.status = self.taskRef.GetSampClkRate(ctypes.byref(sampleRate))
            self._sampleRate = sampleRate.value
        return self._sampleRate

    ## This function sets the sample rate in the DAQmx Task.
    #  @param self The object reference.
    #  @param value The value to set the sample rate.
    def setSampleRate(self, value):
        if self.initialized:
            self.status = self.taskRef.SetSampClkRate(float64(value))
        self._sampleRate = value

    ## This function deletes the sample rate variable inside the
    #  DigitalOutput object.
    #  @param self The object reference.
    def _delSampleRate(self):
        del self._sampleRate

    sampleRate = property(getSampleRate,
                          setSampleRate,
                          _delSampleRate,
                          doc="""The sample rate of the digital output.""")

    #-- Samples Per Channel Property

    ## This function returns the samples per channel configured in the
    #  DAQmx Task.
    #  @param self The object reference.
    def getSamplesPerChannel(self):
        if self.initialized:
            samplesPerChannel = uInt64()
            self.status = self.taskRef.GetSampQuantSampPerChan(
                ctypes.byref(samplesPerChannel))
            self._samplesPerChannel = samplesPerChannel.value
        return self._samplesPerChannel

    ## This function sets the samples per channel in the DAQmx Task.
    #  @param self The object reference.
    #  @param value The value to set the samples per channel.
    def setSamplesPerChannel(self, value):
        if self.initialized:
            self.status = self.taskRef.SetSampQuantSampPerChan(uInt64(value))
        self._samplesPerChannel = value

    ## This function deletes the samplesPerChannel variable from the
    #  DigitalOutput object.
    #  @param self The object reference.
    def _delSamplesPerChannel(self):
        del self._samplesPerChannel

    samplesPerChannel = property(
        getSamplesPerChannel, setSamplesPerChannel, _delSamplesPerChannel,
        """The samples per channel of the digital output.""")

    #-- Clock Source Property

    ## This function returns the sample clock source configured in the
    #  DAQmx Task.
    #  @param self The object reference.
    def getClkSource(self):
        if self.initialized:
            buffSize = uInt32(255)
            buff = ctypes.create_string_buffer(buffSize.value)
            self.status = self.taskRef.GetSampClkSrc(buff, buffSize)
            self._clkSource = buff.value
        return self._clkSource

    ## This function sets the sample clock source in the DAQmx Task.
    #  @param self The object reference.
    #  @param value The value to set the clock source.
    def setClkSource(self, value):
        if self.initialized:
            self.status = self.taskRef.SetSampClkSrc(value)
            value = self.getClkSource()
        self._clkSource = value

    ## This function deletes the clkSource variable within the
    #  DigitalOutput
    #  object.
    #  @param self The object reference.
    def _delClkSource(self):
        del self._clkSource

    clkSource = property(
        getClkSource, setClkSource, _delClkSource,
        """The clock source for the digital outputsample clock.""")

    #-- Start Trigger Property
    ## This function returns the start trigger source configured in the
    #  DAQmx Task.
    #  @param self The object reference.
    def _getStartTriggerSource(self):
        if self.initialized:
            buffSize = uInt32(255)
            buff = ctypes.create_string_buffer(buffSize.value)
            self.status = self.taskRef.GetDigEdgeStartTrigSrc(buff, buffSize)
            self._startTriggerSource = buff.value
        return self._startTriggerSource

    ## This function sets the start trigger source in the DAQmx Task.
    #  @param self The object reference.
    #  @param value The value to set the start trigger.
    def _setStartTriggerSource(self, value):
        if self.initialized:
            self.status = self.taskRef.SetDigEdgeStartTrigSrc(value)
            value = self.getStartTriggerSource()
        self._startTriggerSource = value

    startTriggerSource = property(_getStartTriggerSource,
                                  _setStartTriggerSource)

    #-- Done Property
    def _getDone(self):
        done = bool32()
        if self.initialized:
            self.status = self.taskRef.GetTaskComplete(ctypes.byref(done))
        else:
            done.value = 1
        return bool(done.value)

    ## @var done
    #  Returns the task done status.
    #
    #  This mode works differently depending on the mode. <br />
    #  <ul>
    #  <li><B>Static and Continuous</B>: done is false after a start
    #  method and true</li>
    #  only after a stop method.
    #  <li><B>Finite</B>: done is false until all samples are
    #  generated.</li></ul>
    done = property(_getDone)

    #-- Pause Trigger Source
    def _getPauseTriggerSource(self):
        if self.initialized:
            buffSize = uInt32(255)
            buff = ctypes.create_string_buffer(buffSize.value)
            self.status = self.taskRef.GetDigLvlPauseTrigSrc(buff, buffSize)
            self._pauseTriggerSource = buff.value
        return self._pauseTriggerSource

    def _setPauseTriggerSource(self, value):
        if self.initialized:
            if value == '':
                self.status = self.taskRef.SetPauseTrigType(DAQmx_Val_None)
                self.status = self.taskRef.ResetDigLvlPauseTrigSrc()
            else:
                self.status = self.taskRef.SetDigLvlPauseTrigWhen(
                    DAQmx_Val_High)
                self.status = self.taskRef.SetPauseTrigType(DAQmx_Val_DigLvl)
                self.status = self.taskRef.SetDigLvlPauseTrigSrc(value)
        self._pauseTriggerSource = value

    pauseTriggerSource = property(_getPauseTriggerSource,
                                  _setPauseTriggerSource)

    #-------------------- Functions --------------------

    ## This function is a constructor for the DigitalOutput class.
    #
    #  It creates the internal variables required to perform functions
    #  within the class. This function does not initialize any hardware.
    #  @param self This object reference
    def __init__(self):
        ## The DAQmx task reference.
        self.taskRef = Task()

        ## This is the status of the DAQmx task.
        #
        #  A value greater than 0 means that an error has occurred. When
        #  the status is greater than 0 an error should be reported by
        #  the class.
        self.status = int32()

        ## This is a boolean that is true when the DAQmx task has been
        #  initialized.
        self.initialized = False

        ## @var sampleRate
        #  This is the sample rate of the digital output.
        self._sampleRate = 100e3

        ## @var samplesPerChannel
        #  This is the number of samples per channel that will be generated
        #  in Finite mode.
        self._samplesPerChannel = 100

        ## @var clkSource
        #  This is the sample clock source terminal.  It can be set to an
        #  internal clock or external clock such as a PFI line i.e.
        #  "/PXI1Slot3/PFI15."
        self._clkSource = ''

        ## @var startTriggerSource
        #  This is the start trigger source terminal.  It can be set to
        #  a PFI line such as "/PXISlot3/PFI0"
        self._startTriggerSource = ''

        ## @var pauseTriggerSource
        #  The source terminal of the pause trigger.  This can be
        #  any PFI or backplane trigger such as 'PFI5' and 'PXI_TRIG5'
        self._pauseTriggerSource = ''

        ## This is the mode of operation for the digital outputs.
        #
        #  There are currently three modes available.  Static mode is
        #  where one static digital sample is set with no need for a
        #  sample clock.  Finite mode is where a finite number of digital
        #  samples will be set at a sample clock rate. Continuous mode is
        #  where a sequence of voltages are generated at a sample rate and
        #  then repeated until the stop() method is called.
        self.mode = dutil.Mode.Finite

        self.triggerType = dutil.TriggerType.Software

        ## The number of time to iterate over a Finite number of samples.
        #
        #  This value is only useful in the "Finite" mode.  It is the
        #  number of times that a sequence of digital samples will be
        #  looped.  The default is allways 1.
        self.loops = 1

        ##  The time in seconds to wait for a trigger or for a digital
        #   state change.
        self.timeout = 1

        self.timeoutPad = 10

        self._pCh = ''

    ## Initialize the digital outputs based on the object's configuration.
    #  @param self The object reference.
    #  @param physicalChannel A string representing the device and digital
    #  output channels. Example value: "PXI1Slot3/ao0:7"
    def init(self, physicalChannel):
        self._pCh = physicalChannel
        self.__createTask(physicalChannel)
        self.initialized = True

        #Finite Mode
        if self.mode == dutil.Mode.Finite:
            self.status = self.taskRef.SetWriteRegenMode(DAQmx_Val_AllowRegen)
            self.__configTiming(DAQmx_Val_FiniteSamps)

        #Continuous Mode
        if self.mode == dutil.Mode.Continuous:
            self.status = self.taskRef.SetWriteRegenMode(DAQmx_Val_AllowRegen)
            self.__configTiming(DAQmx_Val_ContSamps)

        #Static Mode
        if self.mode == dutil.Mode.Static:
            pass

    ## This function returns a random 1D numpy array of samples for
    #  writing the buffer of digital output channels.
    #  @param self The objet reference.
    def createTestBuffer(self):
        import numpy
        data = numpy.random.rand(self._samplesPerChannel)
        data = numpy.ubyte(data * 255)
        return data

    ## This function returns the number of digital lines configured in
    #  the DAQmx Task.
    #  @param self The object reference.
    def getNumLines(self):
        numLines = uInt32()
        #bufferSize = 255
        #channel = ctypes.create_string_buffer(bufferSize)
        #self.taskRef.GetTaskChannels(channel, bufferSize)
        #print channel.value
        self.taskRef.GetDONumLines('', ctypes.byref(numLines))
        return numLines.value

    ## This function returns the number of digital channels configured in
    #  the DAQmx Task.
    #  @param self The object reference.
    def getNumChannels(self):
        numChannels = uInt32()
        self.taskRef.GetTaskNumChans(ctypes.byref(numChannels))
        return numChannels.value

    ## This function writes the specified values into the buffer.
    #  @param self The object reference.
    #  @param data This is a 1D 8-bit unsigned integer array that
    #  contians samples for each digital channel. Channels are
    #  non-interleaved (channel1 n-samples then channel2 n-samples).
    def writeToBuffer(self, data):
        autostart = self.mode == dutil.Mode.Static
        samplesWritten = int32()
        self.buff = data
        self.status = self.taskRef.WriteDigitalU8(self._samplesPerChannel,
                                                  autostart, 10,
                                                  DAQmx_Val_GroupByChannel,
                                                  data,
                                                  ctypes.byref(samplesWritten),
                                                  None)
        #print 'Samples Written: ' + str(samplesWritten.value)
        return samplesWritten.value

    ## This function writes a static value to the digital line(s)
    #  configured in the init() method.
    #  @param self The object reference.
    #  @param data The static value to send to the digital line(s).
    def writeStatic(self, data):
        if isinstance(data, bool) and data == True:
            digLineNum = int(self._pCh[len(self._pCh) - 1])
            data = 2**digLineNum
        autostart = True
        self.status = self.taskRef.WriteDigitalScalarU32(
            autostart, float64(self.timeout), uInt32(data), None)

    ## This function starts the digital output generation.
    #  @param self The object reference.
    def start(self):
        self.status = self.taskRef.StartTask()

    ## This functions waits for the digital output generation to complete.
    #  @param self The object reference.
    def waitUntilDone(self):
        sampPerChan = uInt64()
        self.status = self.taskRef.GetSampQuantSampPerChan(
            ctypes.byref(sampPerChan))
        #print 'DO Samples Per Channel: ' + str(sampPerChan.value)
        estAcqTime = (self.loops * sampPerChan.value) / self._sampleRate

        #print "Estimated Acquisition Time: " + str(estAcqTime)

        if self.mode != dutil.Mode.Static:
            self.status = self.taskRef.WaitUntilTaskDone(
                float64(estAcqTime + self.timeoutPad))

    ## This function stops the digital output generation.
    #  @param self The object reference.
    def stop(self):
        self.status = self.taskRef.StopTask()

    ## This is a private method that creates the Task object for use
    #  inside the DigitalOutput class.
    def __createTask(self, physicalChannel):
        self.status = self.taskRef.CreateDOChan(physicalChannel, '',
                                                DAQmx_Val_ChanForAllLines)

    ## This is a private method that configures the timing for the
    #  DigitalOutput class.
    #  @param self The object reference.
    def __configTiming(self, sampleMode):
        totalSamples = self._samplesPerChannel * self.loops
        if self.triggerType == dutil.TriggerType.Software:
            self.status = self.taskRef.CfgSampClkTiming(
                self._clkSource, float64(self._sampleRate), DAQmx_Val_Falling,
                sampleMode, uInt64(totalSamples))
        elif self.triggerType == dutil.TriggerType.Hardware:
            self.status = self.taskRef.CfgSampClkTiming(
                self._clkSource, float64(self._sampleRate), DAQmx_Val_Falling,
                sampleMode, uInt64(totalSamples))
            self.status = self.taskRef.CfgDigEdgeStartTrig(
                self._startTriggerSource, DAQmx_Val_Falling)

    ## This function will close connection to the digital ouput device and
    #  channels.
    #  @param self The object reference.
    def close(self):
        self.initialized = False
        self.status = self.taskRef.ClearTask()
        self.taskRef = Task()

    ## This is the destructor for the DigitalOutput Class.
    #  @param self The object reference.
    def __del__(self):
        if self.initialized:
            self.close()

        del self.taskRef
        del self.status
        del self.initialized
        del self.sampleRate
        del self.samplesPerChannel
        del self.clkSource
        del self.mode
        del self.loops
        del self.timeout
        del self.timeoutPad
        del self._pCh