Counter Inputs

It is very simple to read a counter input with the help of the LIBAD4 library. Therefore the example opens the measurement system (ad_open), then sets the operating mode (ad_set_counter_mode) and after that reads the counter status (ad_discrete_in). At last it closes the measurement system again (ad_close). Evidently the measurement system would be opened just once at the start of the program and closed at the end in a real program. The operating mode of the counter needs to be set just once and not before every reading.

 

You will find the source code of the example in LIBAD4 SDK in the directory examples/counter (and in there in the according directories c, cs and vb for C/C++, C# and Visual Basic™.Net). Like all examples, this one does away with a proper error treatment due to simplicity of handling…

The example provides the routine do_counter() showing how to use the LIBAD4 functions ad_open(), ad_set_counter_mode(), ad_discrete_in() and ad_close(). The name of the measurement device (driver), running mode (mode), a flag for activating the reset line (enable_rst) and the numbers of the counting lines (chav) are passed to the routine. All arguments are retrieved from the command line in main(), are processed accordingly and then handed over to do_counter().

The first parameter on the command gets passed as driver and denotes the measurement system. For example "usb-oi16:@100" opens the USB-OI16 with the serial number 100. You will find detailed descriptions for the necessary names of the different measurement systems in the LIBAD4 manual in chapter 6, measurement systems.

This name will be passed on by do_counter() directly to ad_open(). The return value of ad_open() is a handle, that represents the opened measurement system and has to be returned to all functions of the LIBAD4. In case of an error-1 will be returned.

The parameter mode defines the operating mode and will be denoted in main() by the optional command line -counter (AD_CNT_COUNTER), -updown (AD_CNT_UPDOWN) or -quad (AD_CNT_QUAD_DECODER.This value defaults -1 and ensures that the operating mode is fixed.

main() fills the array chav[] by converting the remaining arguments of the command line to numbers. The function do_counter() denotes the operating mode of the counter in a loop across all channels. The variable par is to be assigned accordingly and to be passed on to ad_set_counter_mode. par.cha denotes the channel and par.mode the operating mode. The settings in par.mux_a as well as in par.mux_b regulate, which digital lines are connected to which counter inputs (for example fixed port A/1 and port A72). If -rst is stated on the command line,  the reset input of the counter is activated. The example connects the reset (par.mux_rst) firmly with port A/3.

Then the current counter reading is ascertained by calling ad_discrete_in. The argument (adh) specifies the measurement system (as passed by ad_open()), the second argument specifies the channel (consisting the channel type AD_CHA_TYPE_COUNTER and channel number chav[i]) and the third argument specifies the measurement range (for counter channels always 0). The last argument data] passed, records the current counter reading. On error the function returns a non-zero error code. This error code corresponds to the host computer's operating system (for example in Windows an error number is returned from <winerror.h>).

The measurement system will be closed at the end of the loop ad_close().

/* Libad Counter Example
 *
 * Example showing how to setup counter mode and read counter value
 * using bmcm's LIBAD4.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "libad.h"
/* Setup counter and read actual value.
 */
void
do_counter (const char *driver, int mode, int enable_rst, int chac, int chav[])
{
  int32_t adh;
  int i;
  /* Open DAQ system.
   */
  adh = ad_open (driver);
  if (adh == -1)
    {
      printf ("failed to open %s: err = %d\n", driver, errno);
      return;
    }
  /* Set counter mode and read actual value.
   */
  for (i = 0; i < chac; i++)
    {
      struct ad_counter_mode par;
      uint32_t data;
      int rc;
      if (mode != -1)
        {
          /* Setup counter mode, using Port A/1 and Port A/2 as
           * both counter inputs. The counter's reset input
           * gets connected to Port A/3 (if enabled).
           */
          memset (&par, 0, sizeof(par));
          par.cha = AD_CHA_TYPE_COUNTER | chav[i];
          par.mode = mode;
          par.mux_a = 0;
          par.mux_b = 1;
          if (enable_rst)
            {
              par.mux_rst = 2;
              par.flags |= AD_CNT_ENABLE_RST;
            }
          rc = ad_set_counter_mode (adh, &par);
          if (rc != 0)
            {
              printf ("error: failed to setup counter %d: err = %d\n", chav[i], rc);
              return;
            }
        }
      rc = ad_discrete_in (adh, AD_CHA_TYPE_COUNTER|1, 0, &data);
      if (rc == 0)
        printf ("counter %d: %d\n", chav[i], data);
      else
        printf ("error: failed to read counter %d: err = %d\n", chav[i], rc);
    }
  /* Close DAQ system again.
   */
  ad_close (adh);
}
/* Show usage.
 */
void
usage ()
{
  printf ("usage: counter <driver> [-counter|-updown|-quad] [-rst] <cha1> .. <chan>\n"
          "  <driver>     string to pass to ad_open()\n"
          "               - will prompt for name\n"
          "  -counter     configure counter mode\n"
          "  -updown      configure up/down counter mode\n"
          "  -quad        configure quad-decoder counter mode\n"
          "  -rst         enable counter's reset input\n"
          "  <cha1..n>    number of counter channel to (configure and) read\n");
}
/* Main entry point.
 */
int
main (int argc, char *argv[])
{
  if (argc > 1)
    {
      char *name, *p, tmp[80];
      int i, start, mode, enable_rst, chac, chav[16];
      /* First command line argument is the DAQ's name.
       * If "-" is passed, then let's read the name from
       * the console.
       */
      name = argv[1];
      if (strcmp (argv[1], "-") == 0)
        {
          printf ("data acquisition system to open: ");
          fgets (tmp, sizeof(tmp), stdin);
          p = strchr (tmp, '\n');
          if (p)
            *p = '';
          name = tmp;
        }
      /* Counter mode defaults to -1 (i.e. do not configure), but
       * may get overridden by command line.
       */
      start = 2;
      mode = -1;
      enable_rst = 0;
      while (argc > start)
        {
          if (strcmp (argv[start], "-counter") == 0)
            {
              mode = AD_CNT_COUNTER;
              start++;
            }
          else if (strcmp (argv[start], "-updown") == 0)
            {
              mode = AD_CNT_UPDOWN;
              start++;
            }
          else if (strcmp (argv[start], "-quad") == 0)
            {
              mode = AD_CNT_QUAD_DECODER;
              start++;
            }
          else if (strcmp (argv[start], "-rst") == 0)
            {
              enable_rst = 1;
              start++;
            }
          else
            break;
        }
      /* Convert remaining command line arguments
       * into numbers and add those to the channel array.
       */
      chac = 0;
      for (i = start; i < argc; i++)
        {
          chav[chac] = atoi (argv[i]);
          chac++;
          if (chac >= 16)
            break;
        }
      /* Configure counter and read actual values, printing results
       * to the console.
       */
      do_counter (name, mode, enable_rst, chac, chav);
      if (strcmp (argv[1], "-") == 0)
        {
          printf ("press return to continue...\n");
          fgets (tmp, sizeof(tmp), stdin);
        }
      return 0;
    }
  else
    {
      usage ();
      return 1;
    }
}
// Libad Counter Example
//
// Example showing how to setup counter mode and read counter value
// using bmcm's LIBAD4.
using System;
using LIBAD4;
static class Example
{
  // Setup counter and read actual value.
  static void
  do_counter (string driver, int mode, bool enable_rst, int[] chav)
  {
    // Open DAQ system.
    int adh = LIBAD.ad_open (driver);
    if (adh == -1)
      {
        Console.WriteLine ("failed to open {0}: err = {1}", driver, LIBAD.errno);
        return;
      }
    // Set counter mode and read actual value.
    for (int i = 0; i < chav.Length; i++)
      {
        uint data = 0;
        int rc;
        if (mode >= 0)
          {
            LIBAD.ad_counter_mode par;
            /* Setup counter mode, using Port A/1 and Port A/2 as
             * both counter inputs. The counter's reset input
             * gets connected to Port A/3 (if enabled).
             */
            par = new LIBAD.ad_counter_mode ();
            par.cha = LIBAD.AD_CHA_TYPE_COUNTER | chav[i];
            par.mode = (byte) (mode & 0xff);
            par.mux_a = 0;
            par.mux_b = 1;
            if (enable_rst)
              {
                par.mux_rst = 2;
                par.flags |= LIBAD.AD_CNT_ENABLE_RST;
              }
            rc = LIBAD.ad_set_counter_mode (adh, ref par);
            if (rc != 0)
              {
                Console.WriteLine ("error: failed to setup counter %d: err = %d\n", chav[i], rc);
                return;
              }
          }
        rc = LIBAD.ad_discrete_in (adh, LIBAD.AD_CHA_TYPE_COUNTER | chav[i], 0, ref data);
        if (rc == 0)
          Console.WriteLine ("counter {0,2}: {1}", chav[i], data);
        else
          Console.WriteLine ("error: failed to write cha {0}: err = {1}", chav[i], rc);
      }
    // Close DAQ system again.
    LIBAD.ad_close (adh);
  }
  // Show usage.
  static void
  usage ()
  {
    Console.WriteLine ("usage: counter <driver> [-counter|-updown|-quad] [-rst] <cha1> .. <chan>");
    Console.WriteLine ("  <driver>     string to pass to ad_open()");
    Console.WriteLine ("               - will prompt for name");
    Console.WriteLine ("  -counter     configure counter mode");
    Console.WriteLine ("  -updown      configure up/down counter mode");
    Console.WriteLine ("  -quad        configure quad-decoder counter mode");
    Console.WriteLine ("  -rst         enable counter's reset input");
    Console.WriteLine ("  <cha1..n>    number of counter channel to (configure and) read");
  }
  // Main entry point.
  static int
  Main (string[] argv)
  {
    if (argv.Length > 0)
      {
        // First command line argument is the DAQ's name.
        // If "-" is passed, then let's read the name from
        // the console.
        string name = argv[0];
        if (argv[0] == "-")
          {
            Console.Write ("data acquisition system to open: ");
            name = Console.ReadLine ();
          }
      // Direction defaults to input, but may get overridden by -o
      // on the command line.
      int start = 1;
      int mode = -1;
      bool enable_rst = false;
      while (argv.Length > start)
        {
          if (argv[start] == "-counter")
            {
              mode = LIBAD.AD_CNT_COUNTER;
              start++;
            }
          else if (argv[start] == "-updown")
            {
              mode = LIBAD.AD_CNT_UPDOWN;
              start++;
            }
          else if (argv[start] == "-quad")
            {
              mode = LIBAD.AD_CNT_QUAD_DECODER;
              start++;
            }
          else if (argv[start] == "-rst")
            {
              enable_rst = true;
              start++;
            }
          else
            break;
        }
        // Convert remaining command line arguments into
        // numbers and add those to the channel array.
        int[] chav = new int[argv.Length - start];
        for (int i = start; i < argv.Length; i++)
          {
            chav[i - start] = int.Parse (argv[i]);
          }
        // Configure counter and read actual values, printing results
        // to the console.
        do_counter (name, mode, enable_rst, chav);
        if (argv[0]== "-")
          {
            Console.WriteLine ("press return to continue...");
            Console.ReadLine ();
          }
        return 0;
      }
    else
      {
        usage ();
        return 1;
      }
  }
}
' Libad Counter Example
'
' Example showing how to setup counter mode and read counter value
' using bmcm's LIBAD4.
Imports System
Imports LIBAD4
Module Example
  ' Setup counter and read actual value.
  Sub do_counter (driver As String, mode As Integer, enable_rst As Boolean, ByVal chav As Integer())
    ' Open DAQ system.
    Dim adh As Integer
    adh = LIBAD.ad_open (driver)
    If adh = -1 Then
      Console.WriteLine ("failed to open {0}: err = {1}", driver, LIBAD.errno)
      Exit Sub
    End If
    ' Set counter mode and read actual value.
    For i = 0 To chav.Length-1
      Dim data As Uinteger
      Dim rc As Integer
      If mode >= 0 Then
        Dim par As LIBAD.ad_counter_mode
        ' Setup counter mode, using Port A/1 and Port A/2 as
        ' both counter inputs. The counter's reset input
        ' gets connected to Port A/3 (if enabled).
        par = new LIBAD.ad_counter_mode ()
        par.cha = LIBAD.AD_CHA_TYPE_COUNTER Or chav(i)
        par.mode = mode And &Hff
        par.mux_a = 0
        par.mux_b = 1
        If enable_rst Then
          par.mux_rst = 2
          par.flags = par.Flags Or LIBAD.AD_CNT_ENABLE_RST
        End If
        rc = LIBAD.ad_set_counter_mode (adh, par)
        If rc <> 0 Then
          Console.WriteLine ("error: failed to setup counter %d: err = %d\n", chav(i), rc)
          Exit Sub
        End If
      End If
      rc = LIBAD.ad_discrete_in (adh, LIBAD.AD_CHA_TYPE_COUNTER or chav(i), 0, data)
      If rc = 0 Then
        Console.WriteLine ("counter {0,2}: {1}", chav(i), data)
      Else
        Console.WriteLine ("error: failed to write cha {0}: err = {1}", chav(i), rc)
      End If
    Next
    ' Close DAQ system again.
    LIBAD.ad_close (adh)
  End Sub
  ' Show usage.
  Sub Usage
    Console.WriteLine ("usage: counter <driver> [-counter|-updown|-quad] [-rst] <cha1> .. <chan>")
    Console.WriteLine ("  <driver>     string to pass to ad_open()")
    Console.WriteLine ("               - will prompt for name")
    Console.WriteLine ("  -counter     configure counter mode")
    Console.WriteLine ("  -updown      configure up/down counter mode")
    Console.WriteLine ("  -quad        configure quad-decoder counter mode")
    Console.WriteLine ("  -rst         enable counter's reset input")
    Console.WriteLine ("  <cha1..n>    number of counter channel to (configure and) read")
  End Sub
  ' Main entry point.
  Sub Main (ByVal argv As String())
    If argv.Length > 0 Then
      ' First command line argument is the DAQ's name.
      ' If "-" is passed, then let's read the name from
      ' the console.
      Dim name As String
      name = argv(0)
      If argv(0) = "-" Then
        Console.Write ("data acquisition sytem to open: ")
        name = Console.ReadLine ()
      End If
      ' Direction defaults to input, but may get overridden by -o
      ' on the command line.
      Dim start As Integer
      Dim mode As Integer
      Dim enable_rst As Boolean
      start = 1
      mode = -1
      enable_rst = False
      Do While argv.Length > start
        If argv(start) = "-counter" Then
          mode = LIBAD.AD_CNT_COUNTER
          start = start + 1
        Else If argv(start) = "-updown" Then
          mode = LIBAD.AD_CNT_UPDOWN
          start = start + 1
        Else If argv(start) = "-quad" Then
          mode = LIBAD.AD_CNT_QUAD_DECODER
          start = start + 1
        Else If argv(start) = "-rst" Then
          enable_rst = True
          start = start + 1
        Else
          Exit Do
        End If
      Loop
      ' Convert remaining command line arguments into
      ' numbers and add those to the channel array.
      Dim chav(argv.Length-1 - start) As Integer
      For i = start To argv.Length-1
        chav(i - start) = Int32.Parse (argv(i))
      Next
      ' Configure counter and read actual values, printing results
      ' to the console.
      do_counter (name, mode, enable_rst, chav)
      If argv(0) = "-" Then
        Console.WriteLine ("press return to continue...")
        Console.ReadLine ()
      End If
      Environment.Exit (0)
    Else
      Usage
      Environment.Exit (1)
    End If
  End Sub
End Module