Integrator Resources

The official home for NAI Support

Not sure where to start? Try Quick Start Guide or ask a question below!

Toggle Components with Visual Button
JavaScript Form Processing

REF BasicOps

REF BasicOps Sample Application (SSK 1.x)

Overview

The REF BasicOps sample application demonstrates how to configure and control AC reference signal generation using the NAI Software Support Kit (SSK 1.x). AC reference modules produce precision sinusoidal excitation signals that drive synchro, resolver, and LVDT position sensors. Without a stable, accurately controlled reference signal, these sensors cannot produce meaningful position data — the reference is the "carrier" that the sensor modulates, and the measurement system demodulates the return signal against it to extract angle or displacement. Getting the reference voltage, frequency, and power state right is a prerequisite for any synchro/resolver or LVDT measurement chain.

This sample covers the core REF operations you will need in your own application: setting output frequency and voltage, enabling and disabling channel output power, reading back measured voltage and current, monitoring overcurrent status, resetting fault conditions, and managing a hardware watchdog timer. Each menu command maps directly to one or more naibrd_REF_*() API calls that you can lift into your own code.

This sample supports the following REF module types defined in naibrd_ref.h: AC1, AC2, AC3, AC4, W1 through W7, LD6, and SDP. The specific voltage and frequency ranges available depend on which module variant is installed — consult your module’s manual for hardware-specific limits.

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a REF module installed (AC1-AC4, W1-W7, LD6, or SDP).

  • SSK 1.x installed on your development host.

  • The sample applications built. Refer to the SSK 1.x build instructions for your platform if you have not already compiled them.

How to Run

Launch the REF_BasicOps executable from your build output directory. On startup the application looks for a configuration file (default_RefBasicOps.txt). On the first run, this file will not exist — the application will present an interactive board menu where you configure a board connection, card index, and module slot. You can save this configuration so that subsequent runs skip the menu and connect automatically. Once connected, you select a channel and the application presents a command menu for exercising each REF operation.

Board Connection and Module Selection

Note
This startup sequence is common to all NAI sample applications. The board connection and module selection code shown here is not specific to REF. For details on board connection configuration, see the First Time Setup Guide.

The main() function follows a standard SSK 1.x startup flow:

  1. Call naiapp_RunBoardMenu() to load a saved configuration file (if one exists) or present the interactive board menu. The configuration file (default_RefBasicOps.txt) is not included with the SSK — it is created when the user saves their connection settings from the board menu. On the first run, the menu will always appear.

  2. Query the user for a card index with naiapp_query_CardIndex().

  3. Query for a module slot with naiapp_query_ModuleNumber().

  4. Retrieve the module ID with naibrd_GetModuleID() so downstream code can adapt to the specific REF variant installed.

#if defined (__VXWORKS__)
int32_t REF_RunBasicOpsProgramSample(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = FALSE;
   int32_t cardIndex;
   int32_t moduleCnt;
   int32_t module;
   uint32_t moduleID = 0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
   {
      while (stop != TRUE)
      {
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         if (stop != TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
            if (stop != TRUE)
            {
               moduleID = naibrd_GetModuleID(cardIndex, module);
               if ((moduleID != 0))
               {
                  REFBasicMenu_Run(cardIndex, module, moduleID);
               }
            }
         }

         printf("\nType Q to quit or Enter key to restart application:\n");
         stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR,
                  inputBuffer, &inputResponseCnt);
      }
   }

   printf("\nType the Enter key to exit the program: ");
   naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR,
            inputBuffer, &inputResponseCnt);
   naiapp_access_CloseAllOpenCards();

   return 0;
}
Important

Common connection errors you may encounter at this stage:

  • No board found — verify that the board is powered on and physically connected. Check that the configuration file lists the correct interface and address.

  • Connection timeout — confirm network settings (for Ethernet connections) or bus configuration (for PCI/PCIe). Firewalls and IP mismatches are frequent causes.

  • Invalid card or module index — indices are zero-based for cards and one-based for modules. Ensure the values you pass match your hardware setup.

  • Module not present at selected slot — the slot you selected does not contain a REF module. Use the board menu to verify which slots are populated.

Program Structure

Once connected to a board and module, the application initializes a parameter structure and enters the command loop. The menu system is a sample convenience — in your own code, call the naibrd_REF_*() API functions directly without the menu scaffolding.

Application Parameters

The sample packs the active card index, module number, module ID, channel count, and selected channel into an naiapp_AppParameters_t struct. Your application will need to track the same values: cardIndex identifies which board you are talking to, module identifies the slot, and channel identifies which REF output you are configuring.

naiapp_AppParameters_t  ref_basicops_params;
p_naiapp_AppParameters_t ref_basicOps_params = &ref_basicops_params;
ref_basicOps_params->cardIndex = cardIndex;
ref_basicOps_params->module = module;
ref_basicOps_params->modId = modid;
ref_basicOps_params->maxChannels = naibrd_REF_GetChannelCount(modid);
ref_basicOps_params->displayHex = FALSE;

The call to naibrd_REF_GetChannelCount() returns the number of reference output channels available on the installed module variant. This value determines the valid channel range for all subsequent API calls.

Command Loop and Menu

The command loop displays current measurements for all channels, shows the available commands, and waits for user input. The available commands are:

Command Description

FREQ

Set the output frequency for the selected channel

VOLT

Set the output voltage for the selected channel

CHAN

Set channel control (enable/disable)

POWR

Set output power on or off

REST

Reset channel fault conditions

WDT

Open the watchdog timer submenu

Displaying Channel Measurements

Before each command prompt, the sample reads back the current state of every channel on the module. This gives you real-time feedback on the reference signal being generated. The display shows frequency, measured voltage, measured current, output enable state, and overcurrent status.

To read these values in your own application, use the following API calls:

/* Read the configured frequency */
naibrd_REF_GetValueEx(cardIndex, module, channel, NAI_REF_FREQUENCY, &frequencyOut);

/* Read the measured output voltage and current */
naibrd_REF_GetMeasuredValueEx(cardIndex, module, channel, NAI_REF_MEASURED_VOLTAGE, &voltageOut);
naibrd_REF_GetMeasuredValueEx(cardIndex, module, channel, NAI_REF_MEASURED_CURRENT, &currentOut);

/* Read whether the channel output is enabled */
naibrd_REF_GetChannelEnable(cardIndex, module, channel, &powerControlOut);

/* Check for an overcurrent condition on the module */
naibrd_REF_GetOverCurrentStatus(cardIndex, module, &overCurrent);

naibrd_REF_GetValueEx() retrieves a configured parameter (here, frequency), while naibrd_REF_GetMeasuredValueEx() retrieves the actual measured output. The distinction matters: the configured value is what you asked the module to produce; the measured value is what the hardware is actually delivering. A significant discrepancy between the two can indicate a wiring issue, an overcurrent condition, or a load problem.

naibrd_REF_GetOverCurrentStatus() is a module-level status (not per-channel). When it returns TRUE, at least one channel on the module has exceeded its current limit. You should check this status periodically and take corrective action — an overcurrent condition typically means the connected sensor load is too heavy or there is a short on the output.

Important

Common Errors

  • Measured voltage reads zero when output is configured — verify that the channel output power is enabled (naibrd_REF_GetChannelEnable() returns 1). Also check that no overcurrent fault is active.

  • NAI_ERROR_NOT_SUPPORTED — the module variant installed may not support the requested measurement type. Consult your module’s manual for supported features.

  • Measured values differ significantly from configured values — check the sensor load impedance against the module’s specifications. An overloaded output cannot maintain its configured voltage.

Setting Output Frequency

AC reference modules generate a sinusoidal excitation signal at a specific frequency. Synchro/resolver systems typically operate at 400 Hz or 47-1000 Hz depending on the application, while LVDT systems may use frequencies from 47 Hz up to 10 kHz. The frequency you configure must match the excitation frequency expected by the connected sensor.

To set the output frequency for a channel in your own application, call naibrd_REF_SetValueEx() with the NAI_REF_FREQUENCY parameter:

float64_t freq = 400.0; /* Frequency in Hz */
check_status(naibrd_REF_SetValueEx(cardIndex, module, channel, NAI_REF_FREQUENCY, freq));

The cardIndex, module, and channel parameters identify which output to configure. The freq value is specified in Hertz. Consult your module’s manual for the valid frequency range — it varies by module variant (for example, some modules support 47-10000 Hz while others have a narrower range).

Important

Common Errors

  • NAI_ERROR_INVALID_VALUE — the requested frequency is outside the supported range for the installed module. Check your module’s manual for valid frequency limits.

  • Output frequency does not change — verify that you are addressing the correct channel. Also ensure that the module firmware supports the naibrd_REF_SetValueEx() extended API; older firmware revisions may require the legacy API.

Setting Output Voltage

The output voltage determines the amplitude of the AC reference signal (typically specified as Vrms). Synchro systems commonly use 26 Vrms or 115 Vrms reference signals, while LVDT excitation voltages vary widely depending on the sensor. Setting the correct voltage is critical — too low and the sensor output will be weak and noisy; too high and you risk damaging the sensor or triggering an overcurrent fault.

To set the output voltage for a channel, call naibrd_REF_SetValueEx() with the NAI_REF_VOLTAGE parameter:

float64_t volt = 26.0; /* Voltage in Vrms */
check_status(naibrd_REF_SetValueEx(cardIndex, module, channel, NAI_REF_VOLTAGE, volt));

Consult your module’s manual for the valid voltage range and resolution. After setting the voltage, read it back with naibrd_REF_GetMeasuredValueEx() using NAI_REF_MEASURED_VOLTAGE to confirm the output has settled to the expected level.

Important

Common Errors

  • NAI_ERROR_INVALID_VALUE — the requested voltage is outside the module’s supported range.

  • Measured voltage does not reach the configured value — this usually indicates an overcurrent condition caused by excessive load. Check naibrd_REF_GetOverCurrentStatus() and verify the sensor load impedance.

  • Output voltage is unstable or noisy — ensure that the frequency is within the module’s rated range. Operating near the frequency limits can reduce voltage regulation accuracy.

Setting Channel Control

The channel control function enables or disables signal generation on a per-channel basis. When a channel is disabled, no AC signal is generated on that output regardless of the configured voltage and frequency settings. This is useful for selectively activating reference outputs when your system has multiple sensors but you only need to excite certain ones at a given time.

To enable or disable a channel in your own application, call naibrd_REF_SetChannelEnable():

uint32_t channelControl = 1; /* 1 = enable, 0 = disable */
check_status(naibrd_REF_SetChannelEnable(cardIndex, module, channel, channelControl));

The channelControl parameter accepts 1 to enable the channel output or 0 to disable it.

Important

Common Errors

  • Channel shows as enabled but no output is measured — check that the output power is also enabled (see the next section). Both channel control and output power must be active for signal generation.

  • NAI_ERROR_INVALID_CHANNEL — the channel number is out of range for the installed module. Use naibrd_REF_GetChannelCount() to determine the valid range.

Setting Output Power

The output power command provides a direct on/off control for the channel’s output stage. This is functionally similar to channel control but provides an explicit binary toggle. In the sample, the user enters 0 for off or 1 for on:

/* Turn output power ON */
check_status(naibrd_REF_SetChannelEnable(cardIndex, module, channel, 1));

/* Turn output power OFF */
check_status(naibrd_REF_SetChannelEnable(cardIndex, module, channel, 0));

When you turn off output power, the module stops driving the reference signal on that channel. The configured voltage and frequency settings are preserved — when you re-enable power, the channel resumes generating the previously configured signal without needing to reconfigure it.

Important

Common Errors

  • Output does not turn on after enabling power — check for an active overcurrent fault. An uncleared overcurrent condition may prevent the output from re-enabling. Use the channel reset command to clear fault latches.

  • Module shuts off all outputs unexpectedly — if the watchdog timer is enabled and not being strobed, the module will disable all outputs as a safety measure. See the Watchdog Operations section below.

Resetting Channel Faults

When an overcurrent or voltage fault occurs, the module latches the fault condition. The channel reset command clears these latches so the channel can resume normal operation. The sample resets both the overcurrent and voltage fault latches:

check_status(naibrd_REF_SetReset(cardIndex, module, channel, NAI_REF_RESET_OVERCURRENT));
check_status(naibrd_REF_SetReset(cardIndex, module, channel, NAI_REF_RESET_VOLTAGE));

Call naibrd_REF_SetReset() with NAI_REF_RESET_OVERCURRENT to clear the overcurrent fault latch, and with NAI_REF_RESET_VOLTAGE to clear the voltage fault latch. You should resolve the underlying cause of the fault (for example, removing a short circuit or reducing the load) before resetting — otherwise the fault will immediately re-trigger.

Important

Common Errors

  • Fault immediately re-latches after reset — the underlying condition has not been resolved. Check sensor wiring, load impedance, and voltage/frequency settings before attempting another reset.

  • NAI_ERROR_NOT_SUPPORTED — the installed module variant may not support the specified reset type. Consult your module’s manual.

Watchdog Operations

The watchdog timer is a hardware safety mechanism that monitors whether your application is still actively communicating with the REF module. When enabled, the watchdog expects periodic "strobe" signals from your software. If the strobe stops (because your application has crashed, hung, or lost communication), the watchdog triggers a fault and the module disables all outputs. This prevents an uncontrolled reference signal from continuing to drive sensors when the supervising software is no longer functioning.

The watchdog is essential in safety-critical applications where an unattended reference output could cause downstream measurement systems to report stale or incorrect position data. By shutting down the reference when software supervision is lost, the watchdog ensures a fail-safe state.

The watchdog submenu (WDT from the main menu) provides the following commands:

Command Description

TIME QUIET

Set the watchdog quiet time (initial grace period)

WINDOW

Set the watchdog window time (strobe deadline)

STROBE

Start a background thread that continuously strobes the watchdog

KILL

Stop the watchdog strobing thread

BACK

Return to the main menu

Watchdog Timing: Quiet Time and Window Time

The watchdog uses a two-phase timing model:

  • Quiet time — an initial grace period after the watchdog is armed. During this interval, the watchdog ignores the absence of strobes, giving your application time to finish initialization before the watchdog becomes active. Set this with naibrd_REF_SetWatchdogQuietTime().

  • Window time — once the quiet time expires, the watchdog expects a strobe within each window interval. If no strobe arrives before the window expires, the watchdog triggers a fault. Set this with naibrd_REF_SetWatchdogWindow().

To configure these timers in your own application:

/* Set quiet time -- value is in microseconds, so multiply ms by 1000 */
uint32_t quietTimeMs = 1000; /* 1000 ms */
check_status(naibrd_REF_SetWatchdogQuietTime(cardIndex, module, quietTimeMs * 1000));

/* Set window time -- value is in microseconds, so multiply ms by 1000 */
uint32_t windowTimeMs = 500; /* 500 ms */
check_status(naibrd_REF_SetWatchdogWindow(cardIndex, module, windowTimeMs * 1000));

Both API calls accept the time value in microseconds. The sample converts from milliseconds by multiplying by 1000. For reliable operation with the sample’s strobe thread, set both quiet time and window time to at least 500 ms. Shorter intervals may not leave enough margin for thread scheduling latency.

Reading Watchdog Status

The watchdog display function reads back the current quiet time, window time, and watchdog fault status:

uint32_t quietTime = 0u, windowTime = 0u;
uint32_t wdStatLatched = 0u, wdStatRT = 0u;

check_status(naibrd_REF_GetWatchdogQuietTime(cardIndex, module, &quietTime));
check_status(naibrd_REF_GetWatchdogWindow(cardIndex, module, &windowTime));

check_status(naibrd_REF_GetChannelStatus(cardIndex, module, chan,
         NAI_REF_STATUS_WATCHDOG_TIMER_FAULT, NAI_REF_STATUS_REALTIME, &wdStatRT));
check_status(naibrd_REF_GetChannelStatus(cardIndex, module, chan,
         NAI_REF_STATUS_WATCHDOG_TIMER_FAULT, NAI_REF_STATUS_LATCHED, &wdStatLatched));

The status is reported as both real-time and latched values. The real-time status indicates whether the watchdog fault is currently active. The latched status indicates whether a watchdog fault has occurred since the last reset — even if the fault has since cleared, the latch remains set until you explicitly reset it.

Strobing the Watchdog

Once the watchdog is configured, your application must periodically call naibrd_REF_WatchdogStrobe() to prevent the watchdog from triggering. The sample spawns a background thread that strobes at an interval of quietTime + (windowTime / 2), which places each strobe roughly in the middle of the window period:

check_status(naibrd_REF_GetWatchdogQuietTime(cardIndex, module, &quietTime));
check_status(naibrd_REF_GetWatchdogWindow(cardIndex, module, &windowTime));
quietTime = quietTime / 1000;   /* Convert from microseconds to milliseconds */
windowTime = windowTime / 1000;
delayTime = quietTime + (windowTime / 2);

check_status(naibrd_REF_WatchdogStrobe(cardIndex, module));
do
{
   nai_msDelay(delayTime);
   check_status(naibrd_REF_WatchdogStrobe(cardIndex, module));
} while (!terminateThread);

In your own application, you do not need to use a separate thread — you can call naibrd_REF_WatchdogStrobe() from your main loop or any periodic task, as long as the interval between strobes does not exceed the window time.

Warning
When the strobe thread or application exits without disabling the watchdog, the module will shut off all outputs and will need to be power cycled to become operational again. Always kill the strobe thread cleanly before exiting.

Stopping the Strobe Thread

The KILL command sets the terminateThread flag, which causes the strobe loop to exit on its next iteration. In your own application, ensure that you stop the watchdog strobe gracefully before shutting down:

naiapp_kill_WDStrobe_Thread();
Important

Common Errors

  • Module disables all outputs unexpectedly — the watchdog timer has expired because strobes stopped arriving. This can happen if the strobe thread was killed, the application crashed, or the strobe interval is too long relative to the window time.

  • Watchdog fault persists after restarting strobes — the latched fault status must be cleared. Reset the channel faults and reconfigure the watchdog timers.

  • Strobe thread fails to create — on Windows, CreateThread() returns NULL on failure. On Linux, pthread_create() returns a non-zero error code. Check system resource limits and ensure no prior thread handle is leaked.

  • Module requires power cycle after watchdog fault — this is expected behavior. Once the watchdog has triggered and outputs are shut down, a power cycle is required to restore the module to an operational state.

Troubleshooting Reference

The following table summarizes errors covered in the preceding sections. Consult your module’s manual for hardware-specific diagnostics.

Error / Symptom Possible Causes Suggested Resolution

No board found

Board not powered, not connected, or configuration file has wrong interface/address

Verify power, cabling, and connection settings in the configuration file

Connection timeout

Network misconfiguration, firewall blocking, IP mismatch, or incorrect bus settings

Confirm Ethernet IP settings or PCI/PCIe bus configuration; check firewall rules

Invalid card or module index

Wrong index values (cards are zero-based, modules are one-based)

Verify hardware setup and adjust index values accordingly

Module not present at selected slot

The selected slot does not contain a REF module

Use the board menu to identify populated slots

Measured voltage reads zero

Channel output power not enabled, or overcurrent fault active

Enable channel power; check and clear overcurrent faults

Measured voltage does not match configured voltage

Sensor load too heavy, wiring issue, or overcurrent condition

Check load impedance against module specs; inspect wiring; clear faults

NAI_ERROR_INVALID_VALUE

Frequency or voltage outside the module’s supported range

Consult your module’s manual for valid parameter ranges

NAI_ERROR_INVALID_CHANNEL

Channel number exceeds the module’s channel count

Call naibrd_REF_GetChannelCount() to determine the valid range

NAI_ERROR_NOT_SUPPORTED

The installed module variant does not support the requested feature

Consult your module’s manual for feature availability

Fault re-latches immediately after reset

Underlying fault condition (short, overload) still present

Resolve the hardware issue before resetting the fault latch

Module shuts off all outputs unexpectedly

Watchdog timer expired due to missed strobes

Ensure your application strobes the watchdog within the configured window time

Module requires power cycle after watchdog fault

Expected behavior — watchdog shutdown is not recoverable without power cycle

Power cycle the module and reconfigure the watchdog with appropriate timing

Watchdog strobe thread fails to start

System resource limits, leaked thread handle, or OS-specific threading error

Check system resources; ensure previous thread was properly terminated

Full Source

Full Source — REF_BasicOps.c (SSK 1.x)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#if defined (LINUX)
#include <pthread.h>
#endif

/* Common Sample Program include files */
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"

/* naibrd include files */
#include "REF_Common.h"
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_ref.h"
#include "advanced/nai_ether_adv.h"

static const int8_t *CONFIG_FILE = (const int8_t *)"default_RefBasicOps.txt";

/* Function prototypes */
static bool_t REFBasicMenu_Run(int32_t cardIndex, int32_t module, uint32_t modid);
static bool_t REFBasicMenu_DisplayMeasurements(int32_t cardIndex, int32_t module, int32_t modid);

static nai_status_t REFBasicMenu_SetFrequency(int32_t paramCount, int32_t* p_params);
static nai_status_t REFBasicMenu_SetVoltage(int32_t paramCount, int32_t* p_params);
static nai_status_t REFBasicMenu_SetChannelControl(int32_t paramCount, int32_t* p_params);
static nai_status_t REFBasicMenu_SetOutputPower(int32_t paramCount, int32_t* p_params);
static nai_status_t REFBasicMenu_SetChannelReset(int32_t paramCount, int32_t* p_params);

static nai_status_t Handle_REF_WatchdogShowMenu(int32_t paramCount, int32_t* p_params);
static nai_status_t Handle_REF_WatchDogQuietTime(int32_t paramCount, int32_t* p_params);
static nai_status_t Handle_REF_WatchDogWindowTime(int32_t paramCount, int32_t* p_params);
static bool_t Handle_REF_DisplayWatchdog(int32_t cardIndex, int32_t module, int32_t chan);
static nai_status_t Handle_REF_StrobeWatchdog(int32_t paramCount, int32_t* p_params);
static nai_status_t Handle_REF_kill_WDStrobe_Thread(int32_t paramCount, int32_t* p_params);
static void naiapp_kill_WDStrobe_Thread();

static const int8_t *SAMPLE_WD_PGM_NAME = (const int8_t*)"REF Watchdog Operations";
static bool_t terminateThread;

#if defined (WIN32)
DWORD WINAPI WD_Strobe_ThreadEntryPoint(LPVOID param);
#elif defined (LINUX)
void* WD_Strobe_ThreadEntryPoint(void* arg);
#elif defined (__VXWORKS__)
static int WD_Strobe_ThreadEntryPoint(int32_t nParam);
#else
#error Unsupported OS
#endif
/* TX Thread */
#if defined (WIN32)
static HANDLE thread = NULL;
#elif defined (LINUX)
static pthread_t thread;
#elif defined (__VXWORKS__)
static int thread;
#else
#error Unsupported OS
#endif

enum ref_basicOpsMenu_commands
{
   REF_BASICMENU_SET_FREQUENCY,
   REF_BASICMENU_SET_VOLTAGE,
   REF_BASICMENU_SET_CHANNEL_CONTROL,
   REF_BASICMENU_SET_OUTPUT_POWER,
   REF_BASICMENU_SET_CHANNEL_RESET,
   REF_BASICOP_CMD_WATCHDOG_MENU,
   REF_BASICMENU_CMD_COUNT
};

enum ref_watchdog_commands
{
   REF_WD_CMD_QUIETTIME,
   REF_WD_CMD_WINDOWTIME,
   REF_WD_CMD_STROBE,
   REF_WD_CMD_KILL,
   REF_WD_CMD_BACK,
   REF_WD_CMD_COUNT
};

naiapp_cmdtbl_params_t REF_BasicOpMenuCmds[] =
{
   { "FREQ",        "Set Frequency",                      REF_BASICMENU_SET_FREQUENCY,                REFBasicMenu_SetFrequency        },
   { "VOLT",       "Set Voltage",                         REF_BASICMENU_SET_VOLTAGE,                  REFBasicMenu_SetVoltage          },
   { "CHAN",       "Set Channel Control",                 REF_BASICMENU_SET_CHANNEL_CONTROL,          REFBasicMenu_SetChannelControl   },
   { "POWR",       "Set Output Power",                    REF_BASICMENU_SET_OUTPUT_POWER,             REFBasicMenu_SetOutputPower      },
   {"WDT",         "Show Watchdog Menu Options",               REF_BASICOP_CMD_WATCHDOG_MENU,               Handle_REF_WatchdogShowMenu},
   { "REST",       "ResetChannel",                        REF_BASICMENU_SET_CHANNEL_RESET,            REFBasicMenu_SetChannelReset     }
};

naiapp_cmdtbl_params_t REF_WatchdogOpMenuCmds[REF_WD_CMD_COUNT] =
{
   {"BACK",           "Back to Main Menu",                             REF_WD_CMD_BACK,          NULL},
   {"TIME QUIET",     "Set Watchdog Quiet Time",                       REF_WD_CMD_QUIETTIME,     Handle_REF_WatchDogQuietTime},
   {"WINDOW",         "Set Watchdog Window Time",                      REF_WD_CMD_WINDOWTIME,    Handle_REF_WatchDogWindowTime},
   {"STROBE",         "Start thread to continuously strobe watchdog",  REF_WD_CMD_STROBE,        Handle_REF_StrobeWatchdog},
   {"KILL",           "Kill Watchdog strobing thread",                 REF_WD_CMD_KILL,          Handle_REF_kill_WDStrobe_Thread}
};

#if defined (__VXWORKS__)
int32_t REF_RunBasicOpsProgramSample(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = FALSE;
   int32_t cardIndex;
   int32_t moduleCnt;
   int32_t module;
   uint32_t moduleID = 0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
   {
      while (stop != TRUE)
      {
         /* Query the user for the card index */
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         if (stop != TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));

            /* Query the user for the module number */
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
            if (stop != TRUE)
            {
               moduleID = naibrd_GetModuleID(cardIndex, module);
               if ((moduleID != 0))
               {
                  REFBasicMenu_Run(cardIndex, module, moduleID);
               }
            }
         }

         printf("\nType Q to quit or Enter key to restart application:\n");
         stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      }
   }

   printf("\nType the Enter key to exit the program: ");
   naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   naiapp_access_CloseAllOpenCards();

   return 0;
}

static bool_t REFBasicMenu_Run(int32_t cardIndex, int32_t module, uint32_t modid)
{
   bool_t bQuit = FALSE, bCmdFound;
   int32_t cmd;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   naiapp_AppParameters_t  ref_basicops_params;
   p_naiapp_AppParameters_t ref_basicOps_params = &ref_basicops_params;
   ref_basicOps_params->cardIndex = cardIndex;
   ref_basicOps_params->module = module;
   ref_basicOps_params->modId = modid;
   ref_basicOps_params->maxChannels = naibrd_REF_GetChannelCount(modid);
   ref_basicOps_params->displayHex = FALSE;
   bQuit = naiapp_query_ChannelNumber(ref_basicOps_params->maxChannels, 1, &ref_basicOps_params->channel);

   naiapp_utils_LoadParamMenuCommands(REF_BASICMENU_CMD_COUNT, REF_BasicOpMenuCmds);
   do
   {
      REFBasicMenu_DisplayMeasurements(cardIndex, module, modid);
      naiapp_display_ParamMenuCommands((int8_t*)"MENU_TITLE");
      printf("\n Type command or %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (!bQuit && inputResponseCnt > 0)
      {
         bCmdFound = naiapp_utils_GetParamMenuCmdNum(inputResponseCnt, inputBuffer, &cmd);
         if (bCmdFound)
         {
            switch (cmd)
            {
               case REF_BASICMENU_SET_FREQUENCY:
               case REF_BASICMENU_SET_VOLTAGE:
               case REF_BASICMENU_SET_CHANNEL_CONTROL:
               case REF_BASICMENU_SET_OUTPUT_POWER:
               case REF_BASICMENU_SET_CHANNEL_RESET:
               case REF_BASICOP_CMD_WATCHDOG_MENU:
                  REF_BasicOpMenuCmds[cmd].func(APP_PARAM_COUNT, (int32_t*)ref_basicOps_params);
                  break;
               default:
                  continue;
                  break;
            }
         }
         else printf("Invalid command entered\n");

      }
   } while (!bQuit);

   return TRUE;
}
static bool_t REFBasicMenu_DisplayMeasurements(int32_t cardIndex, int32_t module, int32_t modid)
{
   int32_t channel, MAX_CHANNEL = naibrd_REF_GetChannelCount((uint32_t)modid);
   float64_t frequencyOut = 0, voltageOut = 0, currentOut = 0;
   uint32_t powerControlOut = 0;
   bool_t overCurrent = FALSE;

   printf("\n\n ================================================== \n");
   printf("%7s%11s%9s%9s%8s%13s\n", "Chan", "Frequency", "Voltage", "Current", "Output", "OverCurrent");

   for (channel = 1; channel <= MAX_CHANNEL; channel++)
   {
      naibrd_REF_GetValueEx(cardIndex, module, channel, NAI_REF_FREQUENCY, &frequencyOut);
      naibrd_REF_GetMeasuredValueEx(cardIndex, module, channel, NAI_REF_MEASURED_VOLTAGE, &voltageOut);
      naibrd_REF_GetMeasuredValueEx(cardIndex, module, channel, NAI_REF_MEASURED_CURRENT, &currentOut);
      naibrd_REF_GetChannelEnable(cardIndex, module, channel, &powerControlOut);
      naibrd_REF_GetOverCurrentStatus(cardIndex, module, &overCurrent);

      printf("%4d%13.3f%10.3f%8.3f", channel, frequencyOut, voltageOut, currentOut);
      if (powerControlOut == TRUE)
         printf("%5s", "ON");
      else
         printf("%6s", "OFF");
      if (overCurrent == TRUE)
         printf("%10s\n", "TRUE");
      else
         printf("%11s\n", "FALSE");
   }

   return TRUE;
}

static nai_status_t REFBasicMenu_SetFrequency(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   float64_t freq = 0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   p_naiapp_AppParameters_t p_ad_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = p_ad_params->cardIndex;
   int32_t module = p_ad_params->module;
   int32_t channel = p_ad_params->channel;

#if defined (WIN32)
   UNREFERENCED_PARAMETER(paramCount);
#endif

   printf("Enter a frequency: ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      freq = atoi((const char *)inputBuffer);
      check_status(naibrd_REF_SetValueEx(cardIndex, module, channel, NAI_REF_FREQUENCY, freq));
   }

   return NAI_SUCCESS;
}
static nai_status_t REFBasicMenu_SetVoltage(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   float64_t volt = 0;
   p_naiapp_AppParameters_t p_ad_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = p_ad_params->cardIndex;
   int32_t module = p_ad_params->module;
   int32_t channel = p_ad_params->channel;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

#if defined (WIN32)
   UNREFERENCED_PARAMETER(paramCount);
#endif

   printf("Enter a voltage: ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      volt = atoi((const char *)inputBuffer);
      check_status(naibrd_REF_SetValueEx(cardIndex, module, channel, NAI_REF_VOLTAGE, volt));
   }
   return NAI_SUCCESS;
}
static nai_status_t REFBasicMenu_SetChannelControl(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   uint32_t channelControl = 0;
   p_naiapp_AppParameters_t p_ref_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = p_ref_params->cardIndex;
   int32_t module = p_ref_params->module;
   int32_t channel = p_ref_params->channel;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

#if defined (WIN32)
   UNREFERENCED_PARAMETER(paramCount);
#endif

   printf("Enter Channel Control: ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      channelControl = atoi((const char *)inputBuffer);
      check_status(naibrd_REF_SetChannelEnable(cardIndex, module, channel, channelControl));
   }
   return NAI_SUCCESS;
}
static nai_status_t REFBasicMenu_SetOutputPower(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   p_naiapp_AppParameters_t p_ad_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = p_ad_params->cardIndex;
   int32_t module = p_ad_params->module;
   int32_t channel = p_ad_params->channel;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

#if defined (WIN32)
   UNREFERENCED_PARAMETER(paramCount);
#endif

   printf("Enter a Output Power (0 Off 1 On): ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputBuffer[0] == '0')
         check_status(naibrd_REF_SetChannelEnable(cardIndex, module, channel, 0));
      else if (inputBuffer[0] == '1')
         check_status(naibrd_REF_SetChannelEnable(cardIndex, module, channel, 1));
   }
   return NAI_SUCCESS;
}
static nai_status_t REFBasicMenu_SetChannelReset(int32_t paramCount, int32_t* p_params)
{
   p_naiapp_AppParameters_t p_ad_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = p_ad_params->cardIndex;
   int32_t module = p_ad_params->module;
   int32_t channel = p_ad_params->channel;
#if defined (WIN32)
   UNREFERENCED_PARAMETER(paramCount);
#endif

   check_status(naibrd_REF_SetReset(cardIndex, module, channel, NAI_REF_RESET_OVERCURRENT));
   check_status(naibrd_REF_SetReset(cardIndex, module, channel, NAI_REF_RESET_VOLTAGE));
   return NAI_SUCCESS;
}
static nai_status_t Handle_REF_WatchdogShowMenu(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t bContinue = TRUE;
   bool_t bCmdFound = FALSE;
   int32_t cmd = 0;
   int32_t numMenuCmds = 0;
   p_naiapp_AppParameters_t p_ref_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = p_ref_params->cardIndex;
   int32_t module = p_ref_params->module;
   int32_t chan = p_ref_params->channel;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   numMenuCmds = REF_WD_CMD_COUNT;
   naiapp_utils_LoadParamMenuCommands(numMenuCmds, REF_WatchdogOpMenuCmds);
   while (bContinue)
   {
      Handle_REF_DisplayWatchdog(cardIndex, module, chan);
      naiapp_display_ParamMenuCommands((int8_t*)SAMPLE_WD_PGM_NAME);
      printf("\nType REF Watchdog command or %c to quit : main > watchdog >", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (!bQuit)
      {
         if (inputResponseCnt > 0)
         {
            if ((inputBuffer[0] == 'B') || (inputBuffer[0] == 'b'))
            {
               bContinue = FALSE;
            }
            else
            {
               bCmdFound = naiapp_utils_GetParamMenuCmdNum(inputResponseCnt, inputBuffer, &cmd);
               if (bCmdFound)
               {
                  REF_WatchdogOpMenuCmds[cmd].func(paramCount, p_params);
               }
               else
               {
                  printf("\nInvalid command entered\n");
               }
            }
         }
      }
      else
         bContinue = FALSE;
   }
   numMenuCmds = REF_BASICMENU_CMD_COUNT;
   naiapp_utils_LoadParamMenuCommands(numMenuCmds, REF_BasicOpMenuCmds);

   return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
static nai_status_t Handle_REF_WatchDogQuietTime(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   uint32_t quietTime = 0u;
   p_naiapp_AppParameters_t p_ref_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = p_ref_params->cardIndex;
   int32_t module = p_ref_params->module;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

#if defined (WIN32)
   UNREFERENCED_PARAMETER(paramCount);
#endif

   printf("\r\n*** To use this sample strobe it is recommended to set a quiet time > 500 ms **");
   printf("\r\nEnter the desired Watchdog Quiet Time (ms): ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt > 0)
      {
         if (inputBuffer[0] == '-')
         {
            printf("\nInvalid value entered\n");
         }
         else
         {
            quietTime = atoi((const char *)inputBuffer);
            if (quietTime == 0u)
            {
               if (inputBuffer[0] == '0')
               {
                  check_status(naibrd_REF_SetWatchdogQuietTime(cardIndex, module, quietTime * 1000));
               }
               else
               {
                  printf("\nInvalid value entered\n");
               }
            }
            else
            {
               check_status(naibrd_REF_SetWatchdogQuietTime(cardIndex, module, quietTime * 1000));
            }
         }
      }
   }

   return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
static nai_status_t Handle_REF_WatchDogWindowTime(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   uint32_t windowTime = 0u;
   p_naiapp_AppParameters_t p_ref_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = p_ref_params->cardIndex;
   int32_t module = p_ref_params->module;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

#if defined (WIN32)
   UNREFERENCED_PARAMETER(paramCount);
#endif

   printf("\r\n*** To use this sample strobe it is recommended to set a window time > 500 ms **");
   printf("\r\nEnter the desired Watchdog Window Time (ms): ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt > 0)
      {
         if (inputBuffer[0] == '-')
         {
            printf("\nInvalid value entered\n");
         }
         else
         {
            windowTime = atoi((const char *)inputBuffer);
            if (windowTime == 0u)
            {
               if (inputBuffer[0] == '0')
               {
                  check_status(naibrd_REF_SetWatchdogWindow(cardIndex, module, windowTime * 1000));
               }
               else
               {
                  printf("\nInvalid value entered\n");
               }
            }
            else
            {
               check_status(naibrd_REF_SetWatchdogWindow(cardIndex, module, windowTime * 1000));
            }
         }
      }
   }

   return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
static bool_t Handle_REF_DisplayWatchdog(int32_t cardIndex, int32_t module, int32_t chan)
{
   uint32_t wdStatLatched = 0u;
   uint32_t wdStatRT = 0u;
   uint32_t windowTime = 0u;
   uint32_t quietTime = 0u;

   printf("\n\nREF Watchdog Data:\n");
   check_status(naibrd_REF_GetWatchdogQuietTime(cardIndex, module, &quietTime));
   quietTime = quietTime / 1000;
   printf("Quiet Time: %d mS\n", quietTime);
   check_status(naibrd_REF_GetWatchdogWindow(cardIndex, module, &windowTime));
   windowTime = windowTime / 1000;
   printf("Window Time: %d mS\n", windowTime);

   check_status(naibrd_REF_GetChannelStatus(cardIndex, module, chan, NAI_REF_STATUS_WATCHDOG_TIMER_FAULT, NAI_REF_STATUS_LATCHED, &wdStatLatched));
   check_status(naibrd_REF_GetChannelStatus(cardIndex, module, chan, NAI_REF_STATUS_WATCHDOG_TIMER_FAULT, NAI_REF_STATUS_REALTIME, &wdStatRT));
   printf("WatchDog Status (R/L):  (%d/%d)\n", wdStatRT, wdStatLatched);

   printf("\n");

   return TRUE;
}

static nai_status_t Handle_REF_StrobeWatchdog(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   int32_t* arg = (int32_t*)malloc(sizeof(int32_t) * 3);
   p_naiapp_AppParameters_t p_ref_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = p_ref_params->cardIndex;
   int32_t module = p_ref_params->module;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

#if defined (WIN32)
   UNREFERENCED_PARAMETER(paramCount);
#endif

   printf("\r\n**NOTE: When this thread/application exits, the module will shut off all outputs and will need to be power cycled in order to be operational **");
   printf("\r\nEnter Y if you want to continue and N to go back: ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt > 0)
      {
         if ((inputBuffer[0] == 'Y') || (inputBuffer[0] == 'y'))
         {
            printf("\r\nStrobing Watchdog every (QuietTime) + (Window)/2...");
            printf("\r\nStarting thread...");
            /* Spawn thread here */

            arg[0] = cardIndex;
            arg[1] = module;

#if defined (__VXWORKS__)
            if (thread == 0)
#elif defined (LINUX)
            if (thread == (pthread_t)NULL)
#else
            if (thread == (int32_t*)NULL)
#endif
            {
#if defined (WIN32)
               LPDWORD threadID = 0;
               thread = CreateThread(NULL, 0, WD_Strobe_ThreadEntryPoint, arg, 0, threadID);
#elif defined (LINUX)
               pthread_create(&thread, NULL, WD_Strobe_ThreadEntryPoint, arg);
#elif defined (__VXWORKS__)
               thread = taskSpawn("WD_Strobe_Thread", 100, 0, 10000, (FUNCPTR)WD_Strobe_ThreadEntryPoint, (int32_t)arg, 0, 0, 0, 0, 0, 0, 0, 0, 0);
#else
#error Unsupported OS
#endif
               if (thread != 0) {
               }
               else
               {
                  free(arg);
                  printf("\nFailed to Create Thread");
               }
            }
            else
            {
#if defined (WIN32)
               LPDWORD threadID = 0;
#endif
               /* kill previous thread and create new one. Report this to them. */
               naiapp_kill_WDStrobe_Thread();
#if defined (WIN32)
               thread = CreateThread(NULL, 0, WD_Strobe_ThreadEntryPoint, arg, 0, threadID);
#elif defined (LINUX)
               pthread_create(&thread, NULL, WD_Strobe_ThreadEntryPoint, arg);
#elif defined (__VXWORKS__)
               thread = taskSpawn("WD_Strobe_Thread", 100, 0, 10000, (FUNCPTR)WD_Strobe_ThreadEntryPoint, (int32_t)arg, 0, 0, 0, 0, 0, 0, 0, 0, 0);
#else
#error Unsupported OS
#endif

#if defined (__VXWORKS__)
               if (thread != 0) {
               }
#elif defined (LINUX)
               if (thread != (pthread_t)NULL) {
               }
#else
               if (thread != (int32_t*)NULL) {
               }
#endif
               else
               {
                  free(arg);
                  printf("\nFailed to Create Thread");
               }
            }
         }
         else
         {
            printf("\r\nReturning to Menu...");
         }
      }
   }

   return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
            }
static void naiapp_kill_WDStrobe_Thread()
{
#if defined (__VXWORKS__)
   if (thread != 0)
   {
      terminateThread = TRUE;
      thread = 0;
   }
#elif defined (LINUX)
   if (thread != ((pthread_t)NULL))
   {
      terminateThread = TRUE;
      thread = ((pthread_t)NULL);
   }
#elif defined (LINUX)
   if (thread != ((pthread_t)NULL))
   {
      terminateThread = TRUE;
      thread = ((pthread_t)NULL);
   }
#else
   if (thread != ((int32_t*)NULL))
   {
      terminateThread = TRUE;
      thread = ((int32_t*)NULL);
   }
#endif
}

#if defined (WIN32)
DWORD WINAPI WD_Strobe_ThreadEntryPoint(LPVOID param)
#elif defined (LINUX)
void* WD_Strobe_ThreadEntryPoint(void* param)
#elif defined (__VXWORKS__)
static int WD_Strobe_ThreadEntryPoint(int32_t param)
#else
#error Unsupported OS
#endif
{
   uint32_t windowTime = 0u;
   uint32_t quietTime = 0u;
   int32_t delayTime = 0;
   int32_t* modInfo = (int32_t*)param;
   int32_t cardIndex = modInfo[0];
   int32_t module = modInfo[1];
   terminateThread = FALSE;
   free(modInfo);

   check_status(naibrd_REF_GetWatchdogQuietTime(cardIndex, module, &quietTime));
   check_status(naibrd_REF_GetWatchdogWindow(cardIndex, module, &windowTime));
   quietTime = quietTime / 1000;
   windowTime = windowTime / 1000;
   delayTime = quietTime + (windowTime / 2);
   check_status(naibrd_REF_WatchdogStrobe(cardIndex, module));
   do
   {
      nai_msDelay(delayTime);
      check_status(naibrd_REF_WatchdogStrobe(cardIndex, module));
   } while (!terminateThread);
   return NAI_SUCCESS;
}
static nai_status_t Handle_REF_kill_WDStrobe_Thread(int32_t paramCount, int32_t* p_params)
{
#if defined (WIN32)
   UNREFERENCED_PARAMETER(paramCount);
   UNREFERENCED_PARAMETER(p_params);
#endif

   naiapp_kill_WDStrobe_Thread();
   return NAI_SUCCESS;
}

Help Bot

X