The interface used for controlling task-based I/O.

Namespace:  Quanser.Hardware
Assembly:  Quanser.Hardware.Hil (in Quanser.Hardware.Hil.dll)

Syntax

Visual Basic (Declaration)
Public Interface Task
C#
public interface Task
Visual C++
public interface class Task
JavaScript
Quanser.Hardware.Task = function();
Quanser.Hardware.Task.createInterface('Quanser.Hardware.Task');

Remarks

Like buffered I/O, the task functions read or write multiple samples from or to the HIL hardware. However, the task functions perform their operations asynchronously as a separate "task". Tasks may be regarded as separate "threads" that run at a fixed sample rate in the background. The task may or may not be performed using DMA. The implementation depends on the underlying driver and data acquisition card. The user can create a task, start and stop the task, and read data from or write data to the task, or even do both at once. Tasks are created using one of the TaskCreate methods listed in the Hil remarks.

There are three kinds of tasks:

  • Reader tasks
  • Writer tasks
  • Reader-writer tasks

Each kind of task has its own set of functions, as described below. However, there are also functions common to all tasks. These common functions allow a task to be started, stopped and deleted. A task that has been stopped may be started again. A task that has been deleted can no longer be used.

The common task functions are:

Method NameDescription
Start(Hil..::.Clock, Double, Int32) Starts a task.
Flush()()() Waits until all samples have actually been written to the hardware.
Stop()()() Stops a task.
IsValid()()() Checks whether a task is valid.

Reader Tasks

As its name suggests, a reader task reads from the hardware. The channels to be read are selected when the task is created. Once the task has been started, it reads the data at the sampling rate specified when the task was started and stores the values read into the task buffer. The user can then read any number of samples from the task buffer using one of the Read methods. If the task has not yet stored the requested number of samples in the task buffer, then the Read operation will block until the requested number of samples has been read or the task overflow. If the task buffer would overflow, then the next Read operation will throw a HilException BufferOverflow exception.

This process is illustrated in the figure below. In this case, the application is reading four samples at a time using one of the Read methods. A "sample" constitutes a set of channels that are read in a single sampling instant. Each square in the figure represents a sample. The buffer passed to the Read function is initially empty (hence portrayed as white), but will be filled with the samples read from the task buffer before the Read method returns. The light orange squares represent samples that were read in the previous call to the Read function.

The task buffer is filled by the task interrupt service routine (ISR) at the sampling rate specified when the task was created. Each sampling instant, the task reads one sample from the channels selected when the task was created. The sample is stored at the next available location in the task buffer. The dark orange squares represent samples that have been stored in the task buffer by the task ISR since the last call to the Read function.

The task buffer operates like a circular buffer. However, new samples are not allowed to overwrite old samples in the buffer. Hence, if the Read method has not been called for a long time and the task buffer becomes full, then the next call to the Read function will fail with an overflow exception.

Reader task diagram

The methods associated with reader tasks are:

Method NameDescription
ReadAnalog(Int32, array<Double>[]()[]) Reads analog samples from the task buffer.
ReadEncoder(Int32, array<Int32>[]()[]) Reads encoder samples from the task buffer.
ReadDigital(Int32, array<SByte>[]()[]) Reads digital samples from the task buffer.
ReadOther(Int32, array<Double>[]()[]) Reads other samples from the task buffer.
Read(Int32, array<Double>[]()[], array<Int32>[]()[], array<SByte>[]()[], array<Double>[]()[]) Reads analog, encoder, digital and/or other samples from the task buffer.

Writer Tasks

As its name suggests, writer tasks write to the hardware. The channels to be written to are selected when the task is created. Once the task has been started, it reads data from the task buffer at the sampling rate specified when the task was started and writes the data to the hardware. The user can write any number of samples to the task buffer using one of the Write methods. If there is not enough room to store the given number of samples in the task buffer, then the Write operation blocks until space becomes available or the task is stopped. Note that for writer tasks, data must be written to the task buffer prior to starting the task so that the task will have data to write to the hardware as soon as it starts. If the task runs out of data in the task buffer then the next Write operation will throw a HilException BufferOverflow exception.

This process is illustrated in the figure below. In this case, the application is writing four samples at a time using one of the Write methods. A "sample" constitutes a set of channels that are written in a single sampling instant. Each square in the figure represents a sample. The buffer passed to the Write method contains the data to write to the task buffer (hence portrayed as yellow) before the Write method returns.

The task buffer is read by the task interrupt service routine (ISR) at the sampling rate specified when the task was created. Each sampling instant, the task reads the next available sample from the task buffer and writes it to the output channels selected when the task was created. The light orange squares represent samples that were written to the task buffer in a previous call to the Write method and have already been written to the hardware by the task. The dark orange squares represent samples that have been stored in the task buffer by previous calls to the Write method but which have not yet been written to the hardware by the task ISR.

The task buffer operates like a circular buffer. However, the same samples are never written to the hardware twice. Hence, if all the samples in the task buffer are written to the hardware before the next call to the Write method so that the task buffer becomes empty, then the next call to the Write method will fail with a buffer underflow exception.

Writer task diagram

The methods associated with writer tasks are:

Method NameDescription
WriteAnalog(Int32, array<Double>[]()[]) Writes analog samples to the task buffer.
WritePwm(Int32, array<Double>[]()[]) Writes PWM samples to the task buffer.
WriteDigital(Int32, array<SByte>[]()[]) Writes digital samples to the task buffer.
WriteOther(Int32, array<Double>[]()[]) Writes other samples to the task buffer.
Write(Int32, array<Double>[]()[], array<Double>[]()[], array<SByte>[]()[], array<Double>[]()[]) Writes analog, PWM, digital and/or other samples to the task buffer.

Reader-Writer Tasks

A "reader-writer" task is a combination of the reader task and the writer task. When a reader-writer task is created, two task buffers are created: one for the read operation and one for the write operation. Each sampling instant, the task reads one sample from the hardware and stores that data in the task read buffer. Then the task reads data from the task write buffer and writes that data to the hardware. Hence, the read and write operations are synchronized. Reader-writer tasks are particularly useful for system identification and other instances where read and write operations need to be synchronized. See the analog_loopback example for demonstration of the synchronization of read and write operations.

This process is illustrated in the figure below. In this case, the application is reading and writing four samples at a time using one of the ReadWrite methods. A "sample" constitutes a set of channels that are read in a single sampling instant. Each square in the figure represents a sample. The input buffer passed to the ReadWrite method is initially empty (hence portrayed as white), but will be filled with the samples read from the task read buffer before the ReadWrite method returns. The light orange squares represent samples that were read in previous calls to the ReadWrite method. Notice that the ReadWrite method will block because the task ISR still needs to write two more samples to the task read buffer before all four samples requested can be read.

The output buffer passed to the ReadWrite method contains the data to write to the task write buffer (hence portrayed as yellow) before the ReadWrite method returns. In this case, these samples are shown as already in the task write buffer because the ReadWrite method has enough space in the task write buffer to do this transfer without blocking. The ReadWrite method always does as much as it can before blocking.

The task read buffer is filled by the task interrupt service routine (ISR) at the sampling rate specified when the task was created. Each sampling instant, the task reads one sample from the channels selected when the task was created. The sample is stored at the next available location in the task read buffer. The dark orange squares represent samples that have been stored in the task read buffer by the task ISR since the last call to the ReadWrite method.

The task read buffer operates like a circular buffer. However, new samples are not allowed to overwrite old samples in the buffer. Hence, if the ReadWrite method has not been called for a long time and the task read buffer becomes full, then the next call to the ReadWrite method will throw a HilException BufferOverflow exception.

After the task ISR reads a sample from the selected input channels and stores the data in the task read buffer, the task ISR reads the next available sample from the task write buffer and writes it to the output channels selected when the task was created. The light purple squares represent samples that were written to the task write buffer in a previous call to the ReadWrite method and have already been written to the hardware by the task. The dark purple squares represent samples that have been stored in the task buffer by the previous call to the ReadWrite method but which have not yet been written to the hardware by the task ISR.

The reason the ReadWrite function is not writing to the same sample number in the task write buffer as it is reading from the task read buffer is because the task write buffer was filled with four samples before the task was started by a call to the Write method. These four samples are indicated in green. The Write method does not block waiting for the data to be written to the hardware - it only blocks if there's not enough space the task write buffer. The task ISR, on the other hand, always reads from the same sample number in the task write buffer as it is writing to in the task read buffer.

Reader-writer diagram

The methods associated with reader-writer tasks are:

Method NameDescription
ReadAnalogWriteAnalog(Int32, array<Double>[]()[], array<Double>[]()[]) Reads analog samples from the task read buffer and writes analog samples to the task write buffer.
ReadEncoderWritePwm(Int32, array<Int32>[]()[], array<Double>[]()[]) Reads encoder samples from the task read buffer and writes PWM samples to the task write buffer.
ReadDigitalWriteDigital(Int32, array<SByte>[]()[], array<SByte>[]()[]) Reads digital samples from the task read buffer and writes digital samples to the task write buffer.
ReadOtherWriteOther(Int32, array<Double>[]()[], array<Double>[]()[]) Reads other samples from the task read buffer and writes other samples to the task write buffer.
ReadWrite(Int32, array<Double>[]()[], array<Int32>[]()[], array<SByte>[]()[], array<Double>[]()[], array<Double>[]()[], array<Double>[]()[], array<SByte>[]()[], array<Double>[]()[]) Reads analog, encoder, digital and/or other samples from the task read buffer and writes analog, PWM, digital and/or other samples to the task write buffer.

See Also