Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

.NET DAQmx: Task runs first time, but throws "already running" when called again.

    public List<byte> ReadData(int bytesToRead)
    {
      int digitalSampleCount = CalculateNumberOfSamplesNeededFromByteCount(bytesToRead) + 1;
      List<DigitalState> clockStates = GenerateClock(digitalSampleCount);
      DigitalWaveform clockWaveform = CopyStatesIntoWaveform(clockStates);

      using (NationalInstruments.DAQmx.Task writeClockTask= new NationalInstruments.DAQmx.Task("Clock Writer"))
      {
        writeClockTask.DOChannels.CreateChannel(clockLine, "Clock Line", ChannelLineGrouping.OneChannelForEachLine);
        writeClockTask.Timing.ConfigureSampleClock("", 20000,
          SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples, digitalSampleCount);
        DigitalSingleChannelWriter clockWriter = new DigitalSingleChannelWriter(writeClockTask.Stream);

        using (NationalInstruments.DAQmx.Task readDataTask = new NationalInstruments.DAQmx.Task("Data Reader"))
        {
          readDataTask.DIChannels.CreateChannel(dataLine, "Data Line", ChannelLineGrouping.OneChannelForEachLine);
          readDataTask.Timing.ConfigureSampleClock("/PXI1Slot6/PFI5", 20000,
            SampleClockActiveEdge.Falling, SampleQuantityMode.FiniteSamples, 16);
          var dataReader = new DigitalSingleChannelReader(readDataTask.Stream);
          var result = dataReader.BeginReadWaveform(16, new AsyncCallback(ReadTaskCallback), readDataTask);
          readDataTask.Start(); // ***** This line throws exception the second time ReadData(int) is called ****
          
          clockWriter.BeginWriteWaveform(true, clockWaveform, new AsyncCallback(WriteClockCallback), writeClockTask);
          writeClockTask.WaitUntilDone();
          readDataTask.WaitUntilDone();

          DigitalWaveform readData = dataReader.EndReadWaveform(result);
          Console.WriteLine("Number of samples read: {0}", readData.Signals[0].States.Count);
          for (int i = 0; i < readData.Signals[0].States.Count; i++)
          {
            Console.WriteLine("State at {0}: {1}", i, readData.Signals[0].States[i].ToString());
          }
        }
      }

      return new List<byte>();
    }

I have the above method, which creates 2 tasks.  One to write a clock signal out, one to read data back in.  Everything works great the first time the function is called.

 

HOWEVER, the "readDataTask.Start()" throws a DaqException, claiming "Specified operation cannot be performed while the task is running".  Maybe I don't have a firm grasp on C# and "using", but shouldn't "readDataTask" get cleaned up when the using block falls out of scope?  And shouldn't new-ing up a new task actually create a new task?  

0 Kudos
Message 1 of 4
(3,756 Views)

Looks like there's something under the covers that isn't being cleaned up when it should be.  If I run the method twice, with 4 seconds between each call, the exception gets thrown.  But if the method is run 60 seconds apart, no exception....

0 Kudos
Message 2 of 4
(3,754 Views)

A little more digging:  It appears that there are 3 Worker threads that get spun up by the above function, and one has to wait for those 3 Worker threads to exit before that function can run again.

 

In addition, the problem only arises when using an external sample clock on the read data task.  Use the default clock and everything works good.  This is code that exhibits the problem.  The key difference between this code and the above code is the "readDataTask" uses different clock sources.  The below code uses the default clock.  The above code uses "/PXI1Slot6/PFI5" for the sample clock (I have a signal generator hooked up to PFI5 to drive the clock).

 

    public void ReadSomething()
    {
      DigitalWaveform clock = new DigitalWaveform(20, 1);
      for(int i=0; i<20; i++)
      {
        if (i % 2 == 0)
          clock.Signals[0].States[i] = DigitalState.ForceDown;
        else
          clock.Signals[0].States[i] = DigitalState.ForceUp;
      }

      using (NationalInstruments.DAQmx.Task writeDataTask = new NationalInstruments.DAQmx.Task())
      {
        writeDataTask.DOChannels.CreateChannel(clockLine, "", ChannelLineGrouping.OneChannelForEachLine);
        writeDataTask.Timing.ConfigureSampleClock("", 10000, 
          SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples, 20);
        var clockWriter = new DigitalSingleChannelWriter(writeDataTask.Stream);

        using (NationalInstruments.DAQmx.Task readDataTask = new NationalInstruments.DAQmx.Task())
        {
          readDataTask.DIChannels.CreateChannel(dataLine, "Data Line", ChannelLineGrouping.OneChannelForEachLine);
          readDataTask.Timing.ConfigureSampleClock("", 10000, /******  USES DEFAULT CLOCK!!!! ******/
            SampleClockActiveEdge.Falling, SampleQuantityMode.FiniteSamples, 5);
          var dataReader = new DigitalSingleChannelReader(readDataTask.Stream);

          var result = dataReader.BeginReadWaveform(5, new AsyncCallback(ReadTaskCallback), readDataTask);
          readDataTask.Start();

          clockWriter.BeginWriteWaveform(true, clock, new AsyncCallback(WriteClockCallback), writeDataTask);
          readDataTask.WaitUntilDone();
          writeDataTask.WaitUntilDone();
          var d = dataReader.EndReadWaveform(result);
        }
      }
    }
0 Kudos
Message 3 of 4
(3,748 Views)

Figured it out.....

 

One has to start the task BEFORE starting the read.

 

This will cause problems.

    public void ReadSomething()
    {
      /*Snip setup code*/
        using (NationalInstruments.DAQmx.Task readDataTask = new NationalInstruments.DAQmx.Task())
        {
          /*Snip setup code*/
          var result = dataReader.BeginReadWaveform(5, new AsyncCallback(ReadTaskCallback), readDataTask);
          readDataTask.Start();
        }
      }
    }

This works flawlesssly

    public void ReadSomething()
    {
      /*Snip setup code*/
        using (NationalInstruments.DAQmx.Task readDataTask = new NationalInstruments.DAQmx.Task())
        {
          /*Snip setup code*/
          readDataTask.Start();
          var result = dataReader.BeginReadWaveform(5, new AsyncCallback(ReadTaskCallback), readDataTask);
        }
      }
    }

Note that "readDataTask.Start()" is called BEFORE "BeginReadWaveform" in the working code.....

 

Is this covered in the documentation somewhere?  

Message 4 of 4
(3,742 Views)