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

PWM BasicOps

PWM BasicOps Sample Application (SSK 1.x)

Overview

The PWM BasicOps sample application demonstrates how to configure and control PWM (Pulse Width Modulation) motor drive channels using the NAI Software Support Kit (SSK 1.x). PWM modules generate variable-width electrical pulses to control motor current, motor voltage, and drive behavior. This sample covers the full range of PWM drive operations: commanding current and voltage output, enabling and resetting drives, reading DAC and ADC channels, monitoring real-time measurements and status, configuring module-level drive mode and command source, tuning per-channel control loop gains and current limits, setting up communication and safety watchdogs, managing battlefield and thermal override protections, and configuring serial interface parameters.

This sample supports the PW1 and PW2 module types (identified in the SSK as NAI_MODULE_ID_PW1 and NAI_MODULE_ID_PW2). The two module variants have different measurement capabilities — PW1 provides single-phase current and voltage measurements with temperature monitoring, while PW2 provides three-phase current and voltage measurements with power supply current and voltage readback. The sample detects the installed module type at runtime and adapts its display accordingly.

It serves as a practical API reference — each menu command maps directly to one or more naibrd_PWM_*() API calls that you can lift into your own code.

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a PWM module installed (PW1 or PW2).

  • 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 PWM_BasicOps executable from your build output directory. On startup the application looks for a configuration file (default_PWM_BasicOps.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, a main command menu lets you exercise each PWM operation through organized submenus.

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 PWM. 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_PWM_BasicOps.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 PWM variant installed.

#ifdef __VXWORKS__
int32_t PWM_BasicOps_Sample(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = FALSE;
   int32_t cardIndex;
   int32_t moduleCnt;
   int32_t module;
   uint32_t moduleID = 0;

   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))
               {
                  PWM_BasicOps_run(cardIndex, module, moduleID);
               }
            }
         }

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

   printf("\nType the Enter key to exit the program: ");
   naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   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 PWM module. Use the board menu to verify which slots are populated.

Program Structure

Entry Point

On standard platforms the entry point is main(). On VxWorks the entry point is PWM_BasicOps_Sample() — the SSK 1.x build system selects the correct variant via a preprocessor guard:

#ifdef __VXWORKS__
int32_t PWM_BasicOps_Sample(void)
#else
int32_t main(void)
#endif

The startup flow is the same in both cases:

  1. Attempt to load the saved configuration file via naiapp_RunBoardMenu(CONFIG_FILE). If the file does not yet exist, the interactive board menu is presented instead.

  2. Enter a loop that queries for card index and module slot.

  3. Call PWM_BasicOps_run() to enter the interactive command loop for the selected module.

  4. On exit, close all open board connections with naiapp_access_CloseAllOpenCards().

Application Parameters

The PWM_BasicOps_run() function populates an naiapp_AppParameters_t struct that is passed to every command handler. Your application will need to track these same values to identify which board, module, and channel you are targeting:

pwm_basicOps_params->cardIndex = cardIndex;
pwm_basicOps_params->module = module;
pwm_basicOps_params->channel = DEFAULT_CHANNEL;
pwm_basicOps_params->maxChannels = naibrd_PWM_GetChannelCount(modId);
pwm_basicOps_params->modId = modId;
pwm_basicOps_params->displayHex = FALSE;
  • cardIndex — identifies which board in a multi-board system.

  • module — the slot number where the PWM module is installed.

  • channel — the currently selected channel (defaults to 1).

  • maxChannels — total channel count for the detected module, retrieved by calling naibrd_PWM_GetChannelCount() with the module ID.

  • modId — the module identifier returned by naibrd_GetModuleID(). API functions use this to apply module-specific behavior (for example, PW1 vs. PW2 measurement differences).

  • displayHex — toggles between hexadecimal and decimal display of register values.

Command Loop and Menu System

PWM_BasicOps_run() drives the interactive command loop. On each iteration it displays the main menu and dispatches the user’s selection to the matching handler function. The main menu provides access to ten functional submenus:

Command Description

PCtl

PWM channel control — set current/voltage commands, enable/reset drives

DCtl

DAC control — view DAC output values

ACtl

ADC control — view ADC inputs, configure source and enable state

Meas

PWM measurements — read real-time current, voltage, and temperature

Stat

Status — view module status and board ready state

MCfg

Module configuration — set drive mode and command source

CCfg

Channel configuration — set current limit, input scale, and control loop gains

WD

Watchdog — configure VME/PCIe/Ethernet watchdog timeout and enable

GCtl

General control — battlefield override, thermal override, soft reset

SCtl

Serial control — serial interface configuration, watchdog, test bits, CRC/frame counters

The menu-driven structure is a convenience of the sample application. In your own application, you would call the same underlying naibrd_PWM_*() API functions directly — for example, calling naibrd_PWM_SetCurrent() instead of navigating to the "PCtl" menu command and selecting "C".

Each submenu handler follows a read-modify-verify pattern: it displays the current state of the relevant registers, presents a submenu of configurable parameters, accepts the user’s input, writes the new value via the API, and then redisplays the updated state. This loop continues until the user types 'Q' to return to the main menu.

PWM Channel Control

This section covers the core drive operations: commanding output current and voltage, enabling the drive, and resetting it. These are the fundamental operations for controlling a PWM motor drive — you set the desired output level, enable the drive to begin switching, and reset it if a fault occurs.

Set Current Command

To command a specific output current on a PWM channel in your own application, call naibrd_PWM_SetCurrent(). The API expects the current value in milliamps, so if your application works in amps you must multiply by 1000 before calling the API.

float32_t current;   /* Current in amps from user input */

/* Note: the current API uses units of milliamps */
naibrd_PWM_SetCurrent(cardIndex, module, channel, current * 1000.0f);
  • cardIndex — identifies the board.

  • module — the slot containing the PWM module.

  • channel — the drive channel to command.

  • current * 1000.0f — the desired output current in milliamps. The sample prompts for amps and converts internally.

To read the current command value back, call naibrd_PWM_GetCurrent(). The returned value is also in milliamps. To read the raw register value, use naibrd_PWM_GetChannelRaw() with NAI_PWM_CHAN_RAW_CURRENT_CMD.

Set Voltage Command

To command a specific output voltage on a PWM channel, call naibrd_PWM_SetVoltage(). The voltage is specified directly in volts.

float32_t voltage;   /* Voltage in volts from user input */

naibrd_PWM_SetVoltage(cardIndex, module, channel, voltage);
  • voltage — the desired output voltage in volts.

To read the voltage command back, call naibrd_PWM_GetVoltage(). To read the raw register value, use naibrd_PWM_GetChannelRaw() with NAI_PWM_CHAN_RAW_VOLTAGE_CMD.

Note
Whether the module responds to the current command or the voltage command depends on the drive mode setting. See Set Drive Mode for details on switching between current-drive and voltage-drive modes.

Enable Drive

To enable or disable the PWM drive output on a channel, call naibrd_PWM_SetDriveEnable(). When the drive is enabled, the module begins PWM switching on the output. When disabled, the output is inactive.

/* Enable the drive on the specified channel */
naibrd_PWM_SetDriveEnable(cardIndex, module, channel, TRUE);

/* Disable the drive */
naibrd_PWM_SetDriveEnable(cardIndex, module, channel, FALSE);
  • TRUE — enables PWM output on the channel.

  • FALSE — disables PWM output on the channel.

To query the current enable state, call naibrd_PWM_GetDriveEnable().

Reset Drive

To reset a PWM drive channel (for example, after a fault condition), call naibrd_PWM_ResetDrive(). This clears any latched fault state and returns the channel to its initial condition.

naibrd_PWM_ResetDrive(cardIndex, module, channel);

After a reset, you will need to reconfigure the channel and re-enable the drive before output resumes.

Important

Common Errors

  • NAI_ERROR_NOT_SUPPORTED — the module at the specified slot does not support PWM operations. Verify that a PW1 or PW2 module is installed.

  • Drive does not respond to current/voltage commands — check that the drive is enabled with naibrd_PWM_SetDriveEnable() and that the drive mode (current vs. voltage) matches the command type you are issuing.

  • Unexpected current units — the API uses milliamps internally. If you pass amps without multiplying by 1000, the output will be three orders of magnitude too small.

DAC Control

The DAC control submenu displays the output values of the module’s digital-to-analog converter channels. This is a read-only view — the DAC outputs are set internally by the module’s control loop based on your current and voltage commands.

To read a DAC output value in your own application, call naibrd_PWM_GetDACOutput():

float32_t dacOutput = 0;
uint32_t hexValue = 0;

naibrd_PWM_GetDACOutput(cardIndex, module, dac, &dacOutput);
naibrd_PWM_GetDAChannelRaw(cardIndex, module, dac, NAI_PWM_CHAN_RAW_DA_OUTPUT, &hexValue);
  • dac — the DAC channel number (1-based).

  • dacOutput — receives the floating-point output value.

  • hexValue — receives the raw register value for diagnostic purposes.

The sample iterates over all DAC channels (up to MAX_PWM_DAC_CHANNELS) and prints each output alongside its raw hex value. In your own application, you can use these readbacks to verify that the control loop is producing the expected drive signals.

Important

Common Errors

  • DAC output reads as zero — the drive may not be enabled, or the current/voltage command may be set to zero. Verify drive enable state and command values.

  • NAI_ERROR_INVALID_CHANNEL — the DAC channel number is out of range. Consult your module’s manual for the number of available DAC channels.

ADC Control

The ADC control submenu displays the analog-to-digital converter input channels and allows you to configure the ADC source and enable state. The ADC channels provide feedback measurements that the control loop uses internally, and that your application can read for monitoring purposes.

Read ADC Input

To read an ADC channel’s voltage in your own application, call naibrd_PWM_GetADCInput():

float32_t voltage = 0;

naibrd_PWM_GetADCInput(cardIndex, module, adc, &voltage);
  • adc — the ADC channel number (1-based).

  • voltage — receives the measured voltage.

Set ADC Source (PW2 Only)

To select the input source for an ADC channel, call naibrd_PWM_SetADCSource(). This function is available on the PW2 module. The source determines where the ADC receives its input data:

/* Route ADC input from the serial interface */
naibrd_PWM_SetADCSource(cardIndex, module, channel, NAI_PWM_ADC_SOURCE_SERIAL);

/* Route ADC input from Ethernet */
naibrd_PWM_SetADCSource(cardIndex, module, channel, NAI_PWM_ADC_SOURCE_ETHERNET);

/* Route ADC input from PWM channel 1 */
naibrd_PWM_SetADCSource(cardIndex, module, channel, NAI_PWM_ADC_SOURCE_PWM_CH1);

/* Route ADC input from PWM channel 2 */
naibrd_PWM_SetADCSource(cardIndex, module, channel, NAI_PWM_ADC_SOURCE_PWM_CH2);
  • NAI_PWM_ADC_SOURCE_SERIAL — ADC input comes from the serial interface.

  • NAI_PWM_ADC_SOURCE_ETHERNET — ADC input comes from the Ethernet interface.

  • NAI_PWM_ADC_SOURCE_PWM_CH1 — ADC input is routed from PWM channel 1.

  • NAI_PWM_ADC_SOURCE_PWM_CH2 — ADC input is routed from PWM channel 2.

To query the current source setting, call naibrd_PWM_GetADCSource().

Enable/Disable ADC (PW2 Only)

To enable or disable an ADC channel, call naibrd_PWM_SetADCEnable():

/* Enable ADC input on the specified channel */
naibrd_PWM_SetADCEnable(cardIndex, module, channel, TRUE);

To query the current enable state, call naibrd_PWM_GetADCEnable().

Note
On the PW1 module, the ADC submenu displays read-only measurement data. The source selection and enable/disable commands are available only on the PW2 module.
Important

Common Errors

  • ADC source/enable commands not available — these commands are PW2-specific. On PW1 modules, the ADC submenu is read-only.

  • ADC reads zero — verify that the ADC channel is enabled and that the selected source is providing data.

PWM Measurements

The measurements submenu displays real-time current, voltage, temperature, and power supply readings from the module. The measurement set differs significantly between PW1 and PW2 modules.

PW1 Measurements

On PW1 modules, the sample reads single-phase measurements per channel plus power supply data:

float32_t current_mA = 0.0f;
float32_t voltage = 0.0f;
int32_t temperature = 0;

/* Per-channel measurements */
naibrd_PWM_GetMeasuredCurrent(cardIndex, module, channel, &current_mA);
naibrd_PWM_GetMeasuredVoltage(cardIndex, module, channel, &voltage);
naibrd_PWM_GetMeasuredTemperature(cardIndex, module, channel, &temperature);

/* Power supply measurements (module-level) */
naibrd_PWM_GetMeasuredPSVoltage(cardIndex, module, &voltage);
naibrd_PWM_GetMeasuredPSTemperature(cardIndex, module, &temperature);
  • current_mA — measured output current in milliamps. Divide by 1000 to convert to amps.

  • voltage — measured output voltage in volts.

  • temperature — measured temperature in degrees Celsius.

  • Power supply voltage and temperature are module-level readings (not per-channel).

PW2 Measurements

On PW2 modules, the sample reads three-phase current and voltage measurements per channel, plus per-channel power supply current and voltage:

float32_t current1_mA, current2_mA, current3_mA;
float32_t voltage1, voltage2, voltage3;

/* Three-phase current (per channel, per phase 1-3) */
naibrd_PWM_GetDriveMeasureCurrent(cardIndex, module, channel, 1, &current1_mA);
naibrd_PWM_GetDriveMeasureCurrent(cardIndex, module, channel, 2, &current2_mA);
naibrd_PWM_GetDriveMeasureCurrent(cardIndex, module, channel, 3, &current3_mA);

/* Three-phase voltage (per channel, per phase 1-3) */
naibrd_PWM_GetDriveMeasureVoltage(cardIndex, module, channel, 1, &voltage1);
naibrd_PWM_GetDriveMeasureVoltage(cardIndex, module, channel, 2, &voltage2);
naibrd_PWM_GetDriveMeasureVoltage(cardIndex, module, channel, 3, &voltage3);

/* Per-channel power supply measurements */
naibrd_PWM_GetPSCurrentMeasure(cardIndex, module, channel, &current1_mA);
naibrd_PWM_GetPSVoltageMeasure(cardIndex, module, channel, &voltage1);

The third parameter to the phase-specific functions (1, 2, or 3) selects the phase. This is useful for three-phase motor drive applications where you need to monitor each winding independently.

Note
If you call PW1-specific measurement functions on a PW2 module (or vice versa), the sample prints "Feature is not supported by this module." Your application should check modId to determine which measurement API calls to use.
Important

Common Errors

  • "Feature is not supported by this module" — you are calling measurement functions that do not apply to the installed module type. Check modId against NAI_MODULE_ID_PW1 or NAI_MODULE_ID_PW2 to select the correct API set.

  • Measurements read zero — verify that the drive is enabled and that a load is connected. With no load, current measurements will naturally be zero.

  • Temperature reads unexpectedly high — this may indicate a thermal fault. Check the general controls for over-temperature override status.

Status

The status submenu displays the module’s status register and board ready state. To check module status and board readiness in your own application:

uint32_t hexValue = 0;

/* Read the status register */
naibrd_PWM_GetStatus(cardIndex, module, &hexValue);

/* Check board ready state */
if (naibrd_PWM_IsBoardReady(cardIndex, module) == NAI_SUCCESS)
{
   /* Board is ready for operation */
}

/* Read the raw board ready register */
naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_BOARD_READY, &hexValue);
  • naibrd_PWM_GetStatus() — retrieves the module status register as a raw hex value. Consult your module’s manual for the bit definitions.

  • naibrd_PWM_IsBoardReady() — returns NAI_SUCCESS when the module has completed initialization and is ready to accept commands. Returns an error status if the module is not yet ready.

  • naibrd_PWM_GetRaw() with NAI_PWM_RAW_BOARD_READY — reads the raw board ready register value for diagnostic purposes.

Always verify that the board is ready before issuing drive commands. If the board is not ready, commands may be ignored or produce unexpected results.

Important

Common Errors

  • Board shows "NOT READY" — the module may still be initializing. Wait and poll again. If the board remains not ready, check power supply connections and consult the module manual for required startup conditions.

  • Status register shows non-zero fault bits — consult your module’s manual for the status register bit map. Common fault bits include over-current, over-temperature, and communication faults.

Module Configuration

The module configuration submenu controls two module-level settings: the drive mode (current vs. voltage) and the command source (serial vs. other). These settings affect all channels on the module.

Set Drive Mode

To select whether the module operates in current-drive mode or voltage-drive mode, call naibrd_PWM_SetDriveMode():

/* Set module to current-drive mode */
naibrd_PWM_SetDriveMode(cardIndex, module, NAI_PWM_CURRENT_DRIVE);

/* Set module to voltage-drive mode */
naibrd_PWM_SetDriveMode(cardIndex, module, NAI_PWM_VOLTAGE_DRIVE);
  • NAI_PWM_CURRENT_DRIVE — the module regulates output current. Use naibrd_PWM_SetCurrent() to command the output.

  • NAI_PWM_VOLTAGE_DRIVE — the module regulates output voltage. Use naibrd_PWM_SetVoltage() to command the output.

The drive mode determines which command register the module’s control loop uses as its setpoint. In current-drive mode, the current command register is active and the voltage command is ignored. In voltage-drive mode, the opposite is true. Make sure you set the drive mode before issuing current or voltage commands.

To read the current drive mode, call naibrd_PWM_GetDriveMode().

Set Command Source

To select where the module receives its current/voltage commands, call naibrd_PWM_SetSource():

/* Commands come from the serial interface */
naibrd_PWM_SetSource(cardIndex, module, NAI_PWM_SOURCE_SERIAL);

/* Commands come from VME, PCIe, or Ethernet */
naibrd_PWM_SetSource(cardIndex, module, NAI_PWM_SOURCE_OTHER);
  • NAI_PWM_SOURCE_SERIAL — the module accepts current/voltage commands from its dedicated serial interface.

  • NAI_PWM_SOURCE_OTHER — the module accepts commands from the host bus (VME, PCIe, or Ethernet). This is the typical setting when controlling the module from your application via the SSK API.

To read the current source setting, call naibrd_PWM_GetSource().

Important

Common Errors

  • Commands have no effect on the output — the command source may be set to Serial while you are issuing commands over Ethernet/PCIe. Set the source to NAI_PWM_SOURCE_OTHER when controlling the module from your host application.

  • Drive mode mismatch — if the module is in voltage-drive mode and you set a current command, the output will not change. Match the command type to the drive mode.

Channel Configuration

The channel configuration submenu controls per-channel parameters that tune the drive’s behavior: current limit, input scale, and the three control loop gains (global, integral, and proportional).

Set Current Limit

To set the maximum allowable output current on a channel, call naibrd_PWM_SetCurrentLimit(). The API expects the value in milliamps:

float32_t currentLimit;   /* Limit in amps from user input */

/* Note: the current API uses units of milliamps */
naibrd_PWM_SetCurrentLimit(cardIndex, module, channel, currentLimit * 1000.0f);

The current limit acts as a safety clamp — if the control loop attempts to drive current beyond this limit, the module caps the output at the limit value. Set this to protect your load and wiring from excessive current.

To read the current limit back, call naibrd_PWM_GetCurrentLimit(). The returned value is in milliamps.

Set Input Scale (Kc)

To set the input scale factor for a channel, call naibrd_PWM_SetInputScale():

int32_t cfgValue;

naibrd_PWM_SetInputScale(cardIndex, module, channel, cfgValue);

The input scale factor (Kc) scales the command input before it enters the control loop. Consult your module’s manual for the valid range and effect of this parameter on drive behavior.

To read the current input scale, call naibrd_PWM_GetInputScale().

Set Global Gain (Kg)

To set the global gain for a channel’s control loop, call naibrd_PWM_SetGlobalGain():

int32_t cfgValue;

naibrd_PWM_SetGlobalGain(cardIndex, module, channel, cfgValue);

The global gain (Kg) is an overall scaling factor applied to the control loop output. It multiplies the combined output of the proportional and integral terms. Increasing Kg increases the overall loop responsiveness; decreasing it reduces output amplitude.

To read the current global gain, call naibrd_PWM_GetGlobalGain().

Set Integral Gain (Ki)

To set the integral gain for a channel’s control loop, call naibrd_PWM_SetIntegralGain():

int32_t cfgValue;

naibrd_PWM_SetIntegralGain(cardIndex, module, channel, cfgValue);

The integral gain (Ki) controls the integrator in the control loop. The integrator accumulates the error between the commanded and measured output over time, driving steady-state error toward zero. Higher Ki values reduce steady-state error faster but can cause overshoot and oscillation if set too aggressively.

To read the current integral gain, call naibrd_PWM_GetIntegralGain().

Set Proportional Gain (Kp)

To set the proportional gain for a channel’s control loop, call naibrd_PWM_SetProportionalGain():

int32_t cfgValue;

naibrd_PWM_SetProportionalGain(cardIndex, module, channel, cfgValue);

The proportional gain (Kp) controls the immediate response to the error between the commanded and measured output. Higher Kp values produce faster response but can cause ringing and instability. Lower values produce smoother but slower response.

To read the current proportional gain, call naibrd_PWM_GetProportionalGain().

Note
Tuning Kg, Ki, and Kp correctly is essential for stable drive operation. Start with conservative values (low gains) and increase gradually while monitoring the measurements submenu for oscillation. Consult your module’s manual for recommended starting values and tuning procedures.
Important

Common Errors

  • Drive oscillates or overshoots — one or more control loop gains are set too high. Reduce Kp and Ki, then increase gradually while monitoring measured current/voltage.

  • Drive responds slowly or does not reach commanded value — gains are too low, or the integral gain Ki is zero. Increase Ki to eliminate steady-state error.

  • Unexpected current units in current limit — the API uses milliamps. If you pass amps without multiplying by 1000, the limit will be set far too low and the drive may not produce meaningful output.

Watchdog Configuration

The watchdog submenu configures the VME/PCIe/Ethernet communication watchdog timer. The watchdog monitors communication between your host application and the PWM module. If the watchdog expires (no communication within the timeout period), the module can take protective action such as disabling drive outputs.

Set Watchdog Timeout

To set the watchdog timeout in your own application, call naibrd_PWM_SetWatchdogTimeout():

float32_t cfgValue;   /* Timeout in milliseconds */

naibrd_PWM_SetWatchdogTimeout(cardIndex, module, cfgValue);
  • cfgValue — the watchdog timeout in milliseconds. If no communication is received within this period, the watchdog triggers.

To read the current timeout, call naibrd_PWM_GetWatchdogTimeout(). To read the raw register value, use naibrd_PWM_GetRaw() with NAI_PWM_RAW_WATCHDOG_TIMEOUT.

Enable/Disable Watchdog

To enable or disable the watchdog timer, call naibrd_PWM_SetWatchdogEnable():

/* Enable the watchdog */
naibrd_PWM_SetWatchdogEnable(cardIndex, module, TRUE);

/* Disable the watchdog */
naibrd_PWM_SetWatchdogEnable(cardIndex, module, FALSE);

When the watchdog is enabled, your application must periodically communicate with the module to prevent the watchdog from expiring. Any API call to the module resets the watchdog timer. During development and bench testing, you may want to leave the watchdog disabled to avoid unexpected drive shutdowns.

To read the current enable state, call naibrd_PWM_GetWatchdogEnable().

Important

Common Errors

  • Drive unexpectedly disables during operation — the watchdog may have expired. Either increase the timeout, ensure your application communicates frequently enough, or disable the watchdog during development.

  • Watchdog does not trigger — verify that the watchdog is enabled. It is disabled by default.

General Controls

The general controls submenu provides access to safety overrides and soft reset functionality.

Battlefield Override Enable

To enable or disable the battlefield override in your own application, call naibrd_PWM_SetBattlefieldOverrideEnable():

/* Enable battlefield override */
naibrd_PWM_SetBattlefieldOverrideEnable(cardIndex, module, TRUE);

/* Disable battlefield override */
naibrd_PWM_SetBattlefieldOverrideEnable(cardIndex, module, FALSE);

When battlefield override is enabled, the module continues to operate even when certain fault conditions are present that would normally shut down the drive. This is intended for mission-critical applications where continued operation under degraded conditions is preferable to a complete shutdown.

To read the current state, call naibrd_PWM_GetBattlefieldOverrideEnable().

Power Supply Over-Temperature Override Enable

To enable or disable the power supply over-temperature override, call naibrd_PWM_SetPSOverTempOverrideEnable():

/* Enable PS over-temperature override */
naibrd_PWM_SetPSOverTempOverrideEnable(cardIndex, module, TRUE);

/* Disable PS over-temperature override */
naibrd_PWM_SetPSOverTempOverrideEnable(cardIndex, module, FALSE);

When this override is enabled, the module continues to operate even if a power supply over-temperature condition is detected. Under normal circumstances, an over-temperature event shuts down the drive to protect the hardware. Enable this override only when continued operation is critical and the thermal risk is understood.

To read the current state, call naibrd_PWM_GetPSOverTempOverrideEnable().

Soft Reset

To perform a software reset of the PWM module, call naibrd_PWM_SoftReset():

naibrd_PWM_SoftReset(cardIndex, module);

A soft reset returns the module to its power-on state. All configuration settings (drive mode, gains, current limits, watchdog, etc.) are reset to their default values, and all drives are disabled. After a reset, you must reconfigure the module and re-enable drives before operation can resume.

The sample prompts for confirmation (Y/N) before executing the reset to prevent accidental resets.

Important

Common Errors

  • Configuration lost after reset — a soft reset clears all settings. Your application must re-apply its configuration after calling naibrd_PWM_SoftReset().

  • Override enables do not persist across power cycles — these are volatile settings. Your application must re-enable overrides on each startup if required.

Serial Control

The serial control submenu configures the module’s dedicated serial communication interface. This interface provides a secondary command path for current/voltage commands and ADC data, independent of the VME/PCIe/Ethernet host bus.

Set Rx Clock Edge

To select which clock edge the serial receiver samples data on, call naibrd_PWM_SetSerialRxClockEdge():

/* Sample on the rising edge */
naibrd_PWM_SetSerialRxClockEdge(cardIndex, module, NAI_PWM_CLOCK_EDGE_RISING);

/* Sample on the falling edge */
naibrd_PWM_SetSerialRxClockEdge(cardIndex, module, NAI_PWM_CLOCK_EDGE_FALLING);

The clock edge setting must match the transmitting device’s configuration. If the edges are mismatched, the serial interface will receive corrupted data.

To read the current setting, call naibrd_PWM_GetSerialRxClockEdge().

Set Serial Watchdog Timeout

To set the serial interface watchdog timeout, call naibrd_PWM_SetSerialWatchdogTimeout():

float32_t cfgValue;   /* Timeout in milliseconds */

naibrd_PWM_SetSerialWatchdogTimeout(cardIndex, module, cfgValue);

This watchdog is separate from the VME/PCIe/Ethernet watchdog configured in the Watchdog submenu. It monitors the serial interface specifically.

To read the current timeout, call naibrd_PWM_GetSerialWatchdogTimeout().

Enable/Disable Serial Watchdog

To enable or disable the serial watchdog, call naibrd_PWM_SetSerialWatchdogEnable():

naibrd_PWM_SetSerialWatchdogEnable(cardIndex, module, TRUE);

To read the current enable state, call naibrd_PWM_GetSerialWatchdogEnable().

Set Serial Test Bits

To write a test pattern to the serial interface, call naibrd_PWM_SetSerialTestBits():

uint32_t hexValue;   /* Test pattern in hex */

naibrd_PWM_SetSerialTestBits(cardIndex, module, hexValue);

Serial test bits allow you to inject known data patterns for loopback testing and communication verification. To read the current test bits value, call naibrd_PWM_GetSerialTestBits().

Enable/Disable Serial Transmit

To enable or disable the serial transmitter, call naibrd_PWM_SetSerialTransmitEnable():

naibrd_PWM_SetSerialTransmitEnable(cardIndex, module, TRUE);

The transmitter must be enabled for the module to send data over the serial interface. To read the current state, call naibrd_PWM_GetSerialTransmitEnable().

CRC Error Count and Data Frame Count

The serial interface tracks CRC errors and data frame counts for diagnostic purposes:

int32_t count;

/* Read CRC error count */
naibrd_PWM_GetCRCErrorCount(cardIndex, module, &count);

/* Read data frame count */
naibrd_PWM_GetDataFrameCount(cardIndex, module, &count);

/* Read data frame status register */
uint32_t hexValue;
naibrd_PWM_GetDataFrameStatus(cardIndex, module, &hexValue);

You can disable these counters individually:

/* Disable CRC error counting */
naibrd_PWM_SetCRCErrorCountDisable(cardIndex, module, TRUE);

/* Disable data frame counting */
naibrd_PWM_SetDataFrameCountDisable(cardIndex, module, TRUE);

Note the inverted logic: passing TRUE disables the counter, and passing FALSE enables it. The sample displays counters as "Enabled" when the disable flag is FALSE, and "Disabled" when the disable flag is TRUE.

To query the current disable state, call naibrd_PWM_GetCRCErrorCountDisable() and naibrd_PWM_GetDataFrameCountDisable().

Important

Common Errors

  • CRC error count increases rapidly — the clock edge setting may be mismatched with the transmitting device, or there may be signal integrity issues on the serial bus. Verify clock edge configuration and check cabling.

  • Serial watchdog triggers unexpectedly — the timeout may be set too short for the serial data rate. Increase the timeout or disable the watchdog during initial integration.

  • Counter disable logic appears inverted — this is by design. SetCRCErrorCountDisable(TRUE) stops counting. SetCRCErrorCountDisable(FALSE) resumes counting.

Troubleshooting Reference

Note
This section summarizes errors covered in the preceding sections and serves as a quick-reference. Consult your module’s manual for hardware-specific diagnostics and detailed status register bit maps.
Error / Symptom Possible Causes Suggested Resolution

No board found

Board not powered on; incorrect interface or address in configuration file.

Verify power, check configuration file settings, confirm physical connection.

Connection timeout

Network misconfiguration; firewall blocking traffic; incorrect bus configuration.

Check IP settings, verify firewall rules, confirm PCI/PCIe bus configuration.

Invalid card or module index

Incorrect zero-based card index or one-based module index.

Verify indices match your hardware setup.

Module not present at selected slot

The selected slot does not contain a PWM module.

Use board menu to verify slot population.

Board shows "NOT READY"

Module still initializing; power supply issue.

Wait and re-poll; check power supply connections.

Drive does not respond to commands

Drive not enabled; drive mode does not match command type; command source set to Serial while commanding over Ethernet/PCIe.

Enable drive; match drive mode to command type; set source to NAI_PWM_SOURCE_OTHER.

Unexpected current units

API uses milliamps; passing amps without conversion.

Multiply amps by 1000 before calling naibrd_PWM_SetCurrent() or naibrd_PWM_SetCurrentLimit().

Drive oscillates or overshoots

Control loop gains (Kg, Ki, Kp) set too high.

Reduce gains and increase gradually while monitoring measurements.

Drive responds slowly

Control loop gains too low; integral gain Ki is zero.

Increase gains; ensure Ki is non-zero.

Feature not supported by this module

Calling PW1-specific functions on PW2 or vice versa.

Check modId and call the correct API variant for the installed module type.

Drive unexpectedly disables

Communication watchdog expired.

Increase timeout, communicate more frequently, or disable watchdog during development.

CRC error count increasing

Serial clock edge mismatch; signal integrity issue.

Verify Rx clock edge setting; check serial cabling.

Configuration lost

Soft reset was performed.

Re-apply all configuration after calling naibrd_PWM_SoftReset().

Full Source

Full Source — PWM_BasicOps.c (SSK 1.x)
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>

/* 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 "nai.h"
#include "naibrd.h"
#include "functions/naibrd_pwm.h"
#include "advanced/nai_ether_adv.h"
#include "boards/naibrd_gen5.h"

//#include "nai_sys_cfg.h"
//#include "nai_utils.h"

static const int8_t *SAMPLE_PGM_NAME = (const int8_t *)"PWM_BasicOps";
static const int8_t *CONFIG_FILE = (const int8_t *)"default_PWM_BasicOps.txt";

/* Global buffer and count for user input */
int8_t  g_op[80];
int32_t g_responseCnt;

#define DEFAULT_CHANNEL 1

typedef enum nai_pwm_devices
{
   DEVICE_NONE,
   DEVICE_64PW2,
   DEVICE_68PW1
}nai_pwm_devices_t;

/* Global variable for pwm device selected */
static nai_pwm_devices_t g_selectedDevice;

/*******************************/
/* Private Function Prototypes */
/*******************************/
static bool_t PWM_BasicOps_run(int32_t cardIndex, int32_t module, uint32_t modId);

/* PWM Channel Control Function Prototypes */
static nai_status_t handlePWMChannelControls(int32_t paramCount, int32_t* p_params);
static nai_status_t getPWMChannelControls(int32_t paramCount, int32_t* p_params);
static bool_t setPWMChannelControls(int32_t paramCount, int32_t* p_params);
static nai_status_t setCurrentCommand(int32_t paramCount, int32_t* p_params);
static nai_status_t setVoltageCommand(int32_t paramCount, int32_t* p_params);
static nai_status_t setDriveEnable(int32_t paramCount, int32_t* p_params);
static nai_status_t resetDrive(int32_t paramCount, int32_t* p_params);

/* DAC Control Function Prototypes */
static nai_status_t handleDACControls(int32_t paramCount, int32_t* p_params);
static nai_status_t getDACControls(int32_t paramCount, int32_t* p_params);

/* ADC Control Function Prototypes */
static nai_status_t handleADCControls(int32_t paramCount, int32_t* p_params);
static nai_status_t getADCControls(int32_t paramCount, int32_t* p_params);
static bool_t setADCControls(int32_t paramCount, int32_t* p_params);
static nai_status_t setADCEnable(int32_t paramCount, int32_t* p_params);
static nai_status_t setADCSource(int32_t paramCount, int32_t* p_params);

/* PWM Measurements Function Prototypes */
static nai_status_t handlePWMMeasurements(int32_t paramCount, int32_t* p_params);
static nai_status_t getPWMMeasurements(int32_t paramCount, int32_t* p_params);

/* PWM Status Function Prototypes */
static nai_status_t handlePWMStatus(int32_t paramCount, int32_t* p_params);
static nai_status_t getPWMStatus(int32_t paramCount, int32_t* p_params);

/* PWM Module Configuration Function Prototypes */
static nai_status_t handlePWMModuleCfg(int32_t paramCount, int32_t* p_params);
static nai_status_t getPWMModuleCfg(int32_t paramCount, int32_t* p_params);
static bool_t setPWMModuleCfg(int32_t paramCount, int32_t* p_params);
static nai_status_t setDriveMode(int32_t paramCount, int32_t* p_params);
static nai_status_t setSourceSelect(int32_t paramCount, int32_t* p_params);

/* Channel Configuration Function Prototypes */
static nai_status_t handlePWMChannelCfg(int32_t paramCount, int32_t* p_params);
static nai_status_t getPWMChannelCfg(int32_t paramCount, int32_t* p_params);
static bool_t setPWMChannelCfg(int32_t paramCount, int32_t* p_params);
static nai_status_t setCurrentLimit(int32_t paramCount, int32_t* p_params);
static nai_status_t setInputScale(int32_t paramCount, int32_t* p_params);
static nai_status_t setGlobalGain(int32_t paramCount, int32_t* p_params);
static nai_status_t setIntegralGain(int32_t paramCount, int32_t* p_params);
static nai_status_t setProportionalGain(int32_t paramCount, int32_t* p_params);

/* PWM VME/PCIe/Ethernet Watchdog Function Prototypes */
static nai_status_t handlePWMWatchdogCfg(int32_t paramCount, int32_t* p_params);
static nai_status_t getPWMWatchdogCfg(int32_t paramCount, int32_t* p_params);
static bool_t setPWMWatchdogCfg(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMWatchdogTimeout(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMWatchdogEnable(int32_t paramCount, int32_t* p_params);

/* PWM General Control Function Prototypes */
static nai_status_t handlePWMGeneralControls(int32_t paramCount, int32_t* p_params);
static nai_status_t getPWMGeneralControls(int32_t paramCount, int32_t* p_params);
static bool_t setPWMGeneralControls(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMSoftReset(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMBattlefieldOverrideEnable(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMPSOvertempOverrideEnable(int32_t paramCount, int32_t* p_params);

/* Serial Control Function Prototypes */
static nai_status_t handlePWMSerialControls(int32_t paramCount, int32_t* p_params);
static nai_status_t getPWMSerialControls(int32_t paramCount, int32_t* p_params);
static bool_t setPWMSerialControls(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMSerialRxClockEdge(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMSerialWatchdogTimeout(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMSerialWatchdogEnable(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMSerialTestBits(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMSerialTransmitEnable(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMCRCErrorCountDisable(int32_t paramCount, int32_t* p_params);
static nai_status_t setPWMDataFrameCountDisable(int32_t paramCount, int32_t* p_params);

/* Private Query Prototypes */
static int32_t queryPWMChannel(int8_t* p_queryText, int32_t maxChannel, int32_t defaultValue);
static bool_t queryFloat32Value(int8_t* p_queryText, float32_t* p_outFloat32);
static bool_t queryInt32Value(int8_t* p_queryText, int32_t* p_outInt32);
static bool_t queryYesNoValue(int8_t* p_queryText, bool_t* p_outresponseYes);
static bool_t queryHex32Value(int8_t* p_queryText, uint32_t* p_outHex32);

/*****************************/
/****** Command Tables *******/
/*****************************/
enum pwm_main_commands
{
   PWM_CMD_PWM_CONTROL,
   PWM_CMD_DAC_CONTROL,
   PWM_CMD_ADC_CONTROL,
   PWM_CMD_MEASUREMENT,
   PWM_CMD_STATUS,
   PWM_CMD_MODULE_CFG,
   PWM_CMD_CHANNEL_CFG,
   PWM_CMD_WATCHDOG,
   PWM_CMD_GENERAL_CONTROL,
   PWM_CMD_SERIAL,
   PWM_CMD_MAIN_COUNT
};

/* Main Menu */
naiapp_cmdtbl_params_t PWM_MenuCmds[] = {
   {"PCtl",       "    PWM Control",            PWM_CMD_PWM_CONTROL,           handlePWMChannelControls},
   {"DCtl",       "    DAC Control",            PWM_CMD_DAC_CONTROL,           handleDACControls},
   {"ACtl",       "    ADC Control",            PWM_CMD_ADC_CONTROL,           handleADCControls},
   {"Meas",       "    PWM Measurements",       PWM_CMD_MEASUREMENT,           handlePWMMeasurements},
   {"Stat",       "    Status",                 PWM_CMD_STATUS,                handlePWMStatus},
   {"MCfg",       "    Module Cfg",             PWM_CMD_MODULE_CFG,            handlePWMModuleCfg},
   {"CCfg",       "    Channel Cfg",            PWM_CMD_CHANNEL_CFG,           handlePWMChannelCfg},
   {"WD",         "    Watchdog",               PWM_CMD_WATCHDOG,              handlePWMWatchdogCfg},
   {"GCtl",       "    General Control",        PWM_CMD_GENERAL_CONTROL,       handlePWMGeneralControls},
   {"SCtl",       "    Serial Control",         PWM_CMD_SERIAL,                handlePWMSerialControls},
};

/* PWM Channel Control Menus */
enum pwm_channel_control_commands
{
   PWM_CMD_CHAN_CURRENT,
   PWM_CMD_CHAN_VOLTAGE,
   PWM_CMD_CHAN_DRIVE_ENABLE,
   PWM_CMD_CHAN_DRIVE_RESET,
   PWM_CMD_CHAN_CONTROL_COUNT
};

naiapp_cmdtbl_params_t PWM_ChannelControlMenuCmds[] = {
   {"C",     "    Current Command",    PWM_CMD_CHAN_CURRENT,         setCurrentCommand},
   {"V",     "    Voltage Command",    PWM_CMD_CHAN_VOLTAGE,         setVoltageCommand},
   {"D",     "    Drive Enable",       PWM_CMD_CHAN_DRIVE_ENABLE,    setDriveEnable},
   {"R",     "    Reset Drive",        PWM_CMD_CHAN_DRIVE_RESET,     resetDrive},
};

/* PWM ADC Control Menus */
enum pwm_adc_control_commands
{
   PWM_CMD_ADC_SOURCE,
   PWM_CMD_ADC_ENABLE,
   PWM_CMD_ADC_CONTROL_COUNT
};

naiapp_cmdtbl_params_t PWM_ADCControlMenuCmds[] = {
   {"S",     "    ADC Source",    PWM_CMD_ADC_SOURCE,         setADCSource},
   {"E",     "    ADC Enable",    PWM_CMD_ADC_ENABLE,         setADCEnable},
};

/* Module Configuration Menus */
enum pwm_module_cfg_commands
{
   PWM_CMD_MODULE_CFG_DRIVE,
   PWM_CMD_MODULE_CFG_SOURCE,
   PWM_CMD_MODULE_CFG_COUNT
};

naiapp_cmdtbl_params_t PWM_ModuleCfgMenuCmds[] = {
   {"D",     "    Drive Mode",      PWM_CMD_MODULE_CFG_DRIVE,       setDriveMode},
   {"S",     "    Source",          PWM_CMD_MODULE_CFG_SOURCE,      setSourceSelect},
};

/* Channel Configuration Menus */
enum pwm_channel_cfg_commands
{
   PWM_CMD_CHAN_CFG_CURRENT_LIMIT,
   PWM_CMD_CHAN_CFG_INPUT_SCALE,
   PWM_CMD_CHAN_CFG_GLOBAL_GAIN,
   PWM_CMD_CHAN_CFG_INTEGRAL_GAIN,
   PWM_CMD_CHAN_CFG_PROPORTIONAL_GAIN,
   PWM_CMD_CHAN_CFG_COUNT
};

naiapp_cmdtbl_params_t PWM_ChannelCfgMenuCmds[] = {
   {"C",     "    Current Limit",      PWM_CMD_CHAN_CFG_CURRENT_LIMIT,     setCurrentLimit},
   {"S",     "    Input Scale",        PWM_CMD_CHAN_CFG_INPUT_SCALE,       setInputScale},
   {"G",     "    Global Gain",        PWM_CMD_CHAN_CFG_GLOBAL_GAIN,       setGlobalGain},
   {"I",     "    Integral Gain",      PWM_CMD_CHAN_CFG_INTEGRAL_GAIN,     setIntegralGain},
   {"P",     "    Proportional Gain",  PWM_CMD_CHAN_CFG_PROPORTIONAL_GAIN, setProportionalGain},
};

/* PWM Watchdog Menus */
enum pwm_watchdog_commands
{
   PWM_CMD_WATCHDOG_TIMEOUT,
   PWM_CMD_WATCHDOG_ENABLE,
   PWM_CMD_WATCHDOG_COUNT
};

naiapp_cmdtbl_params_t PWM_WatchdogMenuCmds[] = {
   {"T",     "    Watchdog Timeout",   PWM_CMD_WATCHDOG_TIMEOUT,    setPWMWatchdogTimeout},
   {"E",     "    Watchdog Enable",    PWM_CMD_WATCHDOG_ENABLE,     setPWMWatchdogEnable},
};

/* PWM General Control Menus */
enum pwm_general_control_commands
{
   PWM_CMD_BATTLEFIELD_OVERRIDE_ENABLE,
   PWM_CMD_PS_OVERTEMP_OVERRIDE_ENABLE,
   PWM_CMD_SOFT_RESET,
   PWM_CMD_GENERAL_CONTROL_COUNT
};

naiapp_cmdtbl_params_t PWM_GeneralControlMenuCmds[] = {
   {"B",     "    Battlefield Override Enable",    PWM_CMD_BATTLEFIELD_OVERRIDE_ENABLE,   setPWMBattlefieldOverrideEnable},
   {"P",     "    PS Over-Temp Override Enable",   PWM_CMD_PS_OVERTEMP_OVERRIDE_ENABLE,   setPWMPSOvertempOverrideEnable},
   {"R",     "    Soft Reset",                     PWM_CMD_SOFT_RESET,                    setPWMSoftReset},
};

/* PWM Serial Control Menus */
enum pwm_serial_control_commands
{
   PWM_CMD_SERIAL_RX_CLOCK_EDGE,
   PWM_CMD_SERIAL_WATCHDOG_TIMEOUT,
   PWM_CMD_SERIAL_WATCHDOG_ENABLE,
   PWM_CMD_SERIAL_TESTBITS,
   PWM_CMD_SERIAL_TRANSMIT_ENABLE,
   PWM_CMD_SERIAL_DISABLE_CRC_ERROR_COUNT,
   PWM_CMD_SERIAL_DISABLE_DATA_FRAME_COUNT,
   PWM_CMD_SERIAL_CONTROL_COUNT
};

naiapp_cmdtbl_params_t PWM_SerialControlMenuCmds[] = {
   {"Clk",   "    Rx Clock Edge",            PWM_CMD_SERIAL_RX_CLOCK_EDGE,             setPWMSerialRxClockEdge},
   {"WT",    "    Watchdog Timeout",         PWM_CMD_SERIAL_WATCHDOG_TIMEOUT,          setPWMSerialWatchdogTimeout},
   {"WE",    "    Watchdog Enable",          PWM_CMD_SERIAL_WATCHDOG_ENABLE,           setPWMSerialWatchdogEnable},
   {"TB",    "    Test Bits",                PWM_CMD_SERIAL_TESTBITS,                  setPWMSerialTestBits},
   {"TE",    "    Transmit Enable",          PWM_CMD_SERIAL_TRANSMIT_ENABLE,           setPWMSerialTransmitEnable},
   {"CRC",   "    CRC Error Count Disable",  PWM_CMD_SERIAL_DISABLE_CRC_ERROR_COUNT,   setPWMCRCErrorCountDisable},
   {"DF",    "    Data Frame Count Disable", PWM_CMD_SERIAL_DISABLE_DATA_FRAME_COUNT,  setPWMDataFrameCountDisable},
};


/**************************************************************************************************************/
/**
<summary>
The purpose of the PWM_BasicOps is to illustrate the methods to call in the naibrd library to perform basic
 operations to the PWM Devices (64PW2 and 68PW1).

</summary>
*/
/**************************************************************************************************************/

#ifdef __VXWORKS__
int32_t PWM_BasicOps_Sample(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = FALSE;
   int32_t cardIndex;
   int32_t moduleCnt;
   int32_t module;
   uint32_t moduleID = 0;

   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))
               {
                  PWM_BasicOps_run(cardIndex, module, moduleID);
               }
            }
         }

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

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

   return 0;
}


/* Private Function Prototypes */
static bool_t PWM_BasicOps_run(int32_t cardIndex, int32_t module, uint32_t modId)
{
   bool_t bQuit = FALSE;
   bool_t bCmdFound = FALSE;
   int32_t cmd;
   naiapp_AppParameters_t  pwm_basicops_params;
   p_naiapp_AppParameters_t pwm_basicOps_params = &pwm_basicops_params;

   pwm_basicOps_params->cardIndex = cardIndex;
   pwm_basicOps_params->module = module;
   pwm_basicOps_params->channel = DEFAULT_CHANNEL;
   pwm_basicOps_params->maxChannels = naibrd_PWM_GetChannelCount(modId);
   pwm_basicOps_params->modId = modId;
   pwm_basicOps_params->displayHex = FALSE;

   do
   {
      naiapp_utils_LoadParamMenuCommands(PWM_CMD_MAIN_COUNT, PWM_MenuCmds);
      naiapp_display_ParamMenuCommands((int8_t*)SAMPLE_PGM_NAME);
      printf("\n\nPlease enter a command or 'q' to quit:");
      bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
      if (!bQuit)
      {
         if (g_responseCnt > 0)
         {
            bCmdFound = naiapp_utils_GetParamMenuCmdNum(g_responseCnt, g_op, &cmd);
            if (bCmdFound)
            {
               switch (cmd)
               {
                  case PWM_CMD_PWM_CONTROL:
                  case PWM_CMD_DAC_CONTROL:
                  case PWM_CMD_ADC_CONTROL:
                  case PWM_CMD_MEASUREMENT:
                  case PWM_CMD_STATUS:
                  case PWM_CMD_CHANNEL_CFG:
                  case PWM_CMD_WATCHDOG:
                  case PWM_CMD_GENERAL_CONTROL:
                  case PWM_CMD_SERIAL:
                     PWM_MenuCmds[cmd].func(APP_PARAM_COUNT, (int32_t*)pwm_basicOps_params);
                     break;
                  default:
                     break;
               }
            }
            else
            {
               printf("Invalid command entered\n");
            }
         }
      }
   } while (!bQuit);

   return bQuit;
}


/*********************************/
/* PWM Channel Control Functions */
/*********************************/
static nai_status_t handlePWMChannelControls(int32_t paramCount, int32_t* p_params)
{
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;
   while (bContinue)
   {
      getPWMChannelControls(paramCount, p_params);
      bQuit = setPWMChannelControls(paramCount, p_params);
      if (bQuit)
      {
         bContinue = FALSE;
      }
   }

   return NAI_SUCCESS;
}

static nai_status_t getPWMChannelControls(int32_t paramCount, int32_t* p_params)
{
   float32_t current_mA = 0.0;
   float32_t voltage = 0.0;
   bool_t driveEnabled = FALSE;
   uint32_t hexValue = 0;
   int32_t channel;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("\n\nPWM Controls:\n");
   printf("==============\n");
   printf("Chan   Current Command (A)     Voltage Command (V)        Drive Enable    \n");
   printf("--------------------------------------------------------------------------\n");

   for (channel = 1; channel <= pwm_basicOps_params->maxChannels; channel++)
   {
      printf(" %d ", channel);

      /* Retrieve Current Command */
      check_status(naibrd_PWM_GetCurrent(cardIndex, module, channel, &current_mA));
      check_status(naibrd_PWM_GetChannelRaw(cardIndex, module, channel, NAI_PWM_CHAN_RAW_CURRENT_CMD, &hexValue));
      printf("  %8.3f (0x%08X)  ", current_mA/1000.0f, hexValue);

      /* Retrieve Voltage Command */
      check_status(naibrd_PWM_GetVoltage(cardIndex, module, channel, &voltage));
      check_status(naibrd_PWM_GetChannelRaw(cardIndex, module, channel, NAI_PWM_CHAN_RAW_VOLTAGE_CMD, &hexValue));
      printf("  %8.3f (0x%08X)  ", voltage, hexValue);

      /* Retrieve Drive Enable */
      check_status(naibrd_PWM_GetDriveEnable(cardIndex, module, channel, &driveEnabled));
      check_status(naibrd_PWM_GetChannelRaw(cardIndex, module, channel, NAI_PWM_CHAN_RAW_DRIVE_ENABLE, &hexValue));
      if (driveEnabled == TRUE)
      {
         printf("  Enabled");
      }
      else
      {
         printf(" Disabled");
      }
      printf(" (0x%08X)", hexValue);

      printf("\n");
   }
   return NAI_SUCCESS;
}

static bool_t setPWMChannelControls(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t bCmdFound = FALSE;
   int32_t cmd;
   int32_t channel;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;

   sprintf((char*)g_op, "\nPlease select the channel to update or Q to quit (default: 1): ");
   channel = queryPWMChannel(g_op, pwm_basicOps_params->maxChannels, 1);
   if (channel > 0)
   {
      naiapp_utils_LoadParamMenuCommands(PWM_CMD_CHAN_CONTROL_COUNT, PWM_ChannelControlMenuCmds);
      naiapp_display_ParamMenuCommands((int8_t *)"PWM Channel Control Menu");
      printf("Type Channel Control command or %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
      if (!bQuit)
      {
         if (g_responseCnt > 0)
         {
            bCmdFound = naiapp_utils_GetParamMenuCmdNum(g_responseCnt, g_op, &cmd);
            if (bCmdFound)
            {
               switch (cmd)
               {
                  case PWM_CMD_CHAN_CURRENT:
                  case PWM_CMD_CHAN_VOLTAGE:
                  case PWM_CMD_CHAN_DRIVE_ENABLE:
                  case PWM_CMD_CHAN_DRIVE_RESET:
                     PWM_ChannelControlMenuCmds[cmd].func(paramCount, p_params);
                     break;
                  default:
                     break;
               }
            }
         }
      }
   }
   else
   {
      bQuit = TRUE;
   }
   return bQuit;
}

static nai_status_t setCurrentCommand(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   float32_t current;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enter the Current Command in amps for Channel %d: ", channel);
   bQuit = queryFloat32Value(g_op, &current);
   if (!bQuit)
   {
      /* Note, the current API is units of mA */
      status = check_status(naibrd_PWM_SetCurrent(cardIndex, module, channel, current * 1000.0f));
   }
   return status;
}

static nai_status_t setVoltageCommand(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   float32_t voltage;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enter the Voltage Command in volts for Channel %d: ", channel);
   bQuit = queryFloat32Value(g_op, &voltage);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetVoltage(cardIndex, module, channel, voltage));
   }
   //naibrd_ReadReg32(cardIndex, module, 0x10, &outvoltage);
   //printf("\nsetVoltageCommand cardIdx:0x%x, module: 0x%x, outvoltage: 0x%x", cardIndex, module, outvoltage);
   return status;
}

static nai_status_t setDriveEnable(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t responseYes = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enable the PWM Drive for Channel %d (Y or N)?: ", channel);
   bQuit = queryYesNoValue(g_op, &responseYes);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetDriveEnable(cardIndex, module, channel, responseYes));
   }
   return status;
}

static nai_status_t resetDrive(int32_t paramCount, int32_t* p_params)
{
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;

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

   return check_status(naibrd_PWM_ResetDrive(cardIndex, module, channel));
}

/*****************************/
/* PWM DAC Control Functions */
/*****************************/
static nai_status_t handleDACControls(int32_t paramCount, int32_t* p_params)
{
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;
   while (bContinue)
   {
      getDACControls(paramCount, p_params);
      printf("Hit Enter to refresh data or type %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
      if (bQuit)
      {
         bContinue = FALSE;
      }
   }
   return NAI_SUCCESS;
}

static nai_status_t getDACControls(int32_t paramCount, int32_t* p_params)
{
   float32_t dacOutput = 0;
   uint32_t hexValue = 0;
   int32_t dac;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("\n\nDAC Controls:\n");
   printf("==============\n");
   printf("DAC   Output Value\n");
   printf("------------------\n");

   for (dac = 1; dac <= MAX_PWM_DAC_CHANNELS; dac++)
   {
      printf(" %d ", dac);

      /* Retrieve DAC Output */
      check_status(naibrd_PWM_GetDACOutput(cardIndex, module, dac, &dacOutput));
      check_status(naibrd_PWM_GetDAChannelRaw(cardIndex, module, dac, NAI_PWM_CHAN_RAW_DA_OUTPUT, &hexValue));
      printf("%8.3f (0x%08X)", dacOutput, hexValue);

      printf("\n");
   }

   printf("\n");
   return NAI_SUCCESS;
}


/*****************************/
/* PWM ADC Control Functions */
/*****************************/
static nai_status_t handleADCControls(int32_t paramCount, int32_t* p_params)
{
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;

   while (bContinue)
   {
      getADCControls(paramCount, p_params);
      if (g_selectedDevice == DEVICE_64PW2)
      {
         bQuit = setADCControls(paramCount, p_params);
         if (bQuit)
         {
            bContinue = FALSE;
         }
      }
      else
      {
         printf("Hit Enter to refresh data or type %c to quit : ", NAI_QUIT_CHAR);
         bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
         if (bQuit)
         {
            bContinue = FALSE;
         }
      }
   }
   return NAI_SUCCESS;
}

static nai_status_t getADCControls(int32_t paramCount, int32_t* p_params)
{
   float32_t voltage = 0;
   nai_pwm_adc_source_t source;
   bool_t adcEnabled;
   uint32_t hexValue = 0;
   int32_t adc;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("\n\nADC Controls:\n");
   printf("==============\n");
   printf("ADC      Voltage                 Source                Enabled         \n");
   printf("-----------------------------------------------------------------------\n");

   for (adc = 1; adc <= MAX_PWM_ADC_CHANNELS; adc++)
   {
      printf(" %d  ", adc);

      /* Retrieve ADC Input */
      check_status(naibrd_PWM_GetADCInput(cardIndex, module, adc, &voltage));
      check_status(naibrd_PWM_GetADChannelRaw(cardIndex, module, adc, NAI_PWM_CHAN_RAW_AD_INPUT, &hexValue));
      printf("%8.3f (0x%08X)", voltage, hexValue);

      /* Retrieve ADC Source */
      check_status(naibrd_PWM_GetADCSource(cardIndex, module, adc, &source));
      switch (source)
      {
         case NAI_PWM_ADC_SOURCE_SERIAL:
            printf("   Serial");
            break;
         case NAI_PWM_ADC_SOURCE_ETHERNET:
            printf(" Ethernet");
            break;
         case NAI_PWM_ADC_SOURCE_PWM_CH1:
            printf(" PWM Ch 1");
            break;
         case NAI_PWM_ADC_SOURCE_PWM_CH2:
            printf(" PWM Ch 2");
            break;
         default:
            printf("  Unknown");
            break;
      }
      printf(" (0x%08X)    ", source);

      /* Retrieve AD Enable */
      check_status(naibrd_PWM_GetADCEnable(cardIndex, module, adc, &adcEnabled));
      check_status(naibrd_PWM_GetADChannelRaw(cardIndex, module, adc, NAI_PWM_CHAN_RAW_AD_ENABLE, &hexValue));
      if (adcEnabled == TRUE)
      {
         printf(" Enabled");
      }
      else
      {
         printf("Disabled");
      }
      printf(" (0x%08X)", hexValue);

      printf("\n");
   }
   return NAI_SUCCESS;
}

static bool_t setADCControls(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t bCmdFound = FALSE;
   int32_t cmd;
   int32_t adc;

   sprintf((char*)g_op, "\nPlease select the ADC channel to update or Q to quit (default: 1): ");
   adc = queryPWMChannel(g_op, MAX_PWM_ADC_CHANNELS, 1);
   if (adc > 0)
   {
      naiapp_utils_LoadParamMenuCommands(PWM_CMD_ADC_CONTROL_COUNT, PWM_ADCControlMenuCmds);
      naiapp_display_ParamMenuCommands((int8_t *)"PWM ADC Control Menu");
      printf("Type ADC Control command or %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
      if (!bQuit)
      {
         if (g_responseCnt > 0)
         {
            bCmdFound = naiapp_utils_GetParamMenuCmdNum(g_responseCnt, g_op, &cmd);
            if (bCmdFound)
            {
               switch (cmd)
               {
                  case PWM_CMD_ADC_SOURCE:
                  case PWM_CMD_ADC_ENABLE:
                     PWM_ADCControlMenuCmds[cmd].func(paramCount, p_params);
                     break;
                  default:
                     break;
               }
            }
         }
      }
   }
   else
   {
      bQuit = TRUE;
   }
   return bQuit;
}

static nai_status_t setADCEnable(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t responseYes = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enable the ADC Input for Channel %d (Y or N)?: ", channel);
   bQuit = queryYesNoValue(g_op, &responseYes);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetADCEnable(cardIndex, module, channel, responseYes));
   }
   return status;
}

static nai_status_t setADCSource(int32_t paramCount, int32_t* p_params)
{
   nai_status_t status = NAI_SUCCESS;
   bool_t bQuit = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;

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


   printf("Set Source:\n");
   printf("S - Serial\n");
   printf("E - Ethernet\n");
   printf("1 - PWM Ch 1\n");
   printf("2 - PWM Ch 2\n");
   printf(">");
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         if ((toupper(g_op[0]) == 'S'))
         {
            status = check_status(naibrd_PWM_SetADCSource(cardIndex, module, channel, NAI_PWM_ADC_SOURCE_SERIAL));
         }
         else if ((toupper(g_op[0]) == 'E'))
         {
            status = check_status(naibrd_PWM_SetADCSource(cardIndex, module, channel, NAI_PWM_ADC_SOURCE_ETHERNET));
         }
         else if ((toupper(g_op[0]) == '1'))
         {
            status = check_status(naibrd_PWM_SetADCSource(cardIndex, module, channel, NAI_PWM_ADC_SOURCE_PWM_CH1));
         }
         else if ((toupper(g_op[0]) == '2'))
         {
            status = check_status(naibrd_PWM_SetADCSource(cardIndex, module, channel, NAI_PWM_ADC_SOURCE_PWM_CH2));
         }
      }
   }
   return status;
}

/*****************************/
/* PWM Measurement Functions */
/*****************************/
static nai_status_t handlePWMMeasurements(int32_t paramCount, int32_t* p_params)
{
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;
   while (bContinue)
   {
      getPWMMeasurements(paramCount, p_params);
      printf("Hit Enter to refresh data or type %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
      if (bQuit)
      {
         bContinue = FALSE;
      }
   }
   return NAI_SUCCESS;
}

static nai_status_t getPWMMeasurements(int32_t paramCount, int32_t* p_params)
{
   float32_t current1_mA = 0.0f, current2_mA = 0.0f, current3_mA = 0.0f;
   float32_t voltage1 = 0.0f, voltage2 = 0.0f, voltage3 = 0.0f;
   int32_t temperature = 0;
   uint32_t hexValue = 0;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;

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

   printf("\n\nPWM Measurements:\n");
   printf("================\n");

   if (NAI_MODULE_ID_PW1 == pwm_basicOps_params->modId)
   {
      printf("Chan      Current (A)           Voltage (V)      Temperature(C)\n");
      printf("---------------------------------------------------------------\n");

      for (channel = 1; channel <= pwm_basicOps_params->maxChannels; channel++)
      {
         printf(" %d   ", channel);

         /* Retrieve Measured Current */
         check_status(naibrd_PWM_GetMeasuredCurrent(cardIndex, module, channel, &current1_mA));
         check_status(naibrd_PWM_GetChannelRaw(cardIndex, module, channel, NAI_PWM_CHAN_RAW_MEASURED_CURRENT, &hexValue));
         printf("%8.3f (0x%08X)", current1_mA/1000.f, hexValue);

         /* Retrieve Voltage */
         check_status(naibrd_PWM_GetMeasuredVoltage(cardIndex, module, channel, &voltage1));
         check_status(naibrd_PWM_GetChannelRaw(cardIndex, module, channel, NAI_PWM_CHAN_RAW_MEASURED_VOLTAGE, &hexValue));
         printf("%8.3f (0x%08X)", voltage1, hexValue);

         /* Retrieve Temperature */
         check_status(naibrd_PWM_GetMeasuredTemperature(cardIndex, module, channel, &temperature));
         printf("        %d", temperature);

         printf("\n\n");

         printf("PS       Voltage (V)         Temperature(C)\n");
         printf("-------------------------------------------\n");

         /* Retrieve Power Supply Voltage */
         check_status(naibrd_PWM_GetMeasuredPSVoltage(cardIndex, module, &voltage1));
         check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_PS_VOLTAGE, &hexValue));
         printf("    %8.3f (0x%08X)  ", voltage1, hexValue);

         /* Retrieve Power Supply Temperature */
         check_status(naibrd_PWM_GetMeasuredPSTemperature(cardIndex, module, &temperature));
         printf("        %d", temperature);

      }
   }
   else if (NAI_MODULE_ID_PW2 == pwm_basicOps_params->modId)
   {
      printf("Chan    Current1(A)  Current2(A)  Current3(A)  Voltage1  Voltage2  Voltage3  PSCurrent(A)  PSVoltage\n");
      printf("----------------------------------------------------------------------------------------------------\n");

      for (channel = 1; channel <= pwm_basicOps_params->maxChannels; channel++)
      {
         printf(" %d   ", channel);

         /* Retrieve Measured Current */
         check_status(naibrd_PWM_GetDriveMeasureCurrent(cardIndex, module, channel, 1, &current1_mA));
         check_status(naibrd_PWM_GetDriveMeasureCurrent(cardIndex, module, channel, 2, &current2_mA));
         check_status(naibrd_PWM_GetDriveMeasureCurrent(cardIndex, module, channel, 3, &current3_mA));
         printf("%8.3f     %8.3f     %8.3f     ", current1_mA/1000.0f, current2_mA/1000.0f, current3_mA/1000.0f);

         /* Retrieve Voltage */
         check_status(naibrd_PWM_GetDriveMeasureVoltage(cardIndex, module, channel, 1, &voltage1));
         check_status(naibrd_PWM_GetDriveMeasureVoltage(cardIndex, module, channel, 2, &voltage2));
         check_status(naibrd_PWM_GetDriveMeasureVoltage(cardIndex, module, channel, 3, &voltage3));
         printf("%8.3f  %8.3f  %8.3f  ", voltage1, voltage2, voltage3);

         /* Retrieve Power Supply Voltage */
         check_status(naibrd_PWM_GetPSVoltageMeasure(cardIndex, module, channel, &voltage1));

         /* Retrieve Power Supply Current */
         check_status(naibrd_PWM_GetPSCurrentMeasure(cardIndex, module, channel, &current1_mA));
         printf("%8.3f       %8.3f", current1_mA/1000.0f, voltage1);

         printf("\n");
      }
   }
   else
   {
      printf("Feature is not supported by this module.\n");
   }

   printf("\n\n");
   return NAI_SUCCESS;
}

/************************/
/* PWM Status Functions */
/************************/
static nai_status_t handlePWMStatus(int32_t paramCount, int32_t* p_params)
{
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;

   while (bContinue)
   {
      getPWMStatus(paramCount, p_params);
      printf("Hit Enter to refresh data or type %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
      if (bQuit)
      {
         bContinue = FALSE;
      }
   }
   return NAI_SUCCESS;
}

static nai_status_t getPWMStatus(int32_t paramCount, int32_t* p_params)
{
   uint32_t hexValue = 0;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("\n\nPWM Status:\n");
   printf("===========\n");
   printf("  Status           Board Ready    \n");
   printf("----------------------------------\n");

   /* Retrieve PWM Status */
   check_status(naibrd_PWM_GetStatus(cardIndex, module, &hexValue));
   printf("0x%08X    ", hexValue);

   /* Retrieve Board Ready Status */
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_BOARD_READY, &hexValue));
   if (naibrd_PWM_IsBoardReady(cardIndex, module) == NAI_SUCCESS)
   {
      printf("    READY");
   }
   else
   {
      printf("NOT READY");
   }
   printf(" (0x%08X)", hexValue);

   printf("\n");
   return NAI_SUCCESS;
}


/**************************************/
/* PWM Module Configuration Functions */
/**************************************/
static nai_status_t handlePWMModuleCfg(int32_t paramCount, int32_t* p_params)
{
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;
   while (bContinue)
   {
      getPWMModuleCfg(paramCount, p_params);
      bQuit = setPWMModuleCfg(paramCount, p_params);
      if (bQuit)
      {
         bContinue = FALSE;
      }
   }
   return NAI_SUCCESS;
}

static nai_status_t getPWMModuleCfg(int32_t paramCount, int32_t* p_params)
{
   nai_pwm_drive_mode_t mode;
   nai_pwm_source_t source;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("\n\nPWM Module Configuration:\n");
   printf("=========================\n");
   printf("     Drive Mode                 Source         \n");
   printf("-----------------------------------------------\n");

   /* Retrieve Drive Mode */
   check_status(naibrd_PWM_GetDriveMode(cardIndex, module, &mode));
   switch (mode)
   {
      case NAI_PWM_CURRENT_DRIVE:
         printf("Current");
         break;
      case NAI_PWM_VOLTAGE_DRIVE:
         printf("Voltage");
         break;
      default:
         printf("Unknown");
         break;
   }
   printf(" (0x%08X)    ", mode);

   /* Retrieve Source Select */
   check_status(naibrd_PWM_GetSource(cardIndex, module, &source));
   switch (source)
   {
      case NAI_PWM_SOURCE_SERIAL:
         printf(" Serial");
         break;
      case NAI_PWM_SOURCE_OTHER:
         printf("  Other");
         break;
      default:
         printf("Unknown");
         break;
   }
   printf(" (0x%08X)    ", source);
   return NAI_SUCCESS;
}

static bool_t setPWMModuleCfg(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t bCmdFound = FALSE;
   int32_t cmd;

   naiapp_utils_LoadParamMenuCommands(PWM_CMD_MODULE_CFG_COUNT, PWM_ModuleCfgMenuCmds);
   naiapp_display_ParamMenuCommands((int8_t *)"Board Configuration Menu");
   printf("Type Module Configuration command or %c to quit : ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         bCmdFound = naiapp_utils_GetParamMenuCmdNum(g_responseCnt, g_op, &cmd);
         if (bCmdFound)
         {
            switch (cmd)
            {
               case PWM_CMD_MODULE_CFG_DRIVE:
               case PWM_CMD_MODULE_CFG_SOURCE:
                  PWM_ModuleCfgMenuCmds[cmd].func(paramCount, p_params);
                  break;
               default:
                  break;
            }
         }
      }
   }
   return bQuit;
}

static nai_status_t setDriveMode(int32_t paramCount, int32_t* p_params)
{
   nai_status_t status = NAI_SUCCESS;
   bool_t bQuit = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("Set Drive Mode:\n");
   printf("C - Current\n");
   printf("V - Voltage\n");
   printf(">");
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         if ((toupper(g_op[0]) == 'C'))
         {
            status = check_status(naibrd_PWM_SetDriveMode(cardIndex, module, NAI_PWM_CURRENT_DRIVE));
         }
         else if ((toupper(g_op[0]) == 'V'))
         {
            status = check_status(naibrd_PWM_SetDriveMode(cardIndex, module, NAI_PWM_VOLTAGE_DRIVE));
         }
      }
   }
   return status;
}

static nai_status_t setSourceSelect(int32_t paramCount, int32_t* p_params)
{
   nai_status_t status = NAI_SUCCESS;
   bool_t bQuit = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("Set Source:\n");
   printf("S - Serial\n");
   printf("O - Other (VME, PCIe, Ethernet)\n");
   printf(">");
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         if ((toupper(g_op[0]) == 'S'))
         {
            status = check_status(naibrd_PWM_SetSource(cardIndex, module, NAI_PWM_SOURCE_SERIAL));
         }
         else if ((toupper(g_op[0]) == 'O'))
         {
            status = check_status(naibrd_PWM_SetSource(cardIndex, module, NAI_PWM_SOURCE_OTHER));
         }
      }
   }
   return status;
}

/************************************/
/* Channel Configuration Functions  */
/************************************/
static nai_status_t handlePWMChannelCfg(int32_t paramCount, int32_t* p_params)
{
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;

   while (bContinue)
   {
      getPWMChannelCfg(paramCount, p_params);
      bQuit = setPWMChannelCfg(paramCount, p_params);
      if (bQuit)
      {
         bContinue = FALSE;
      }
   }
   return NAI_SUCCESS;
}

static nai_status_t getPWMChannelCfg(int32_t paramCount, int32_t* p_params)
{
   float32_t currentLimit_mA = 0.0;
   uint32_t hexValue = 0;
   int32_t cfgValue = 0;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;

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

   printf("\n\nChannel Configuration:\n");
   printf("====================\n");
   printf("Chan  Current Limit          Input Scale(Kc)      Global Gain(Kg)     Integral Gain(Ki)       Prop Gain(Kp) \n");
   printf("------------------------------------------------------------------------------------------------------------\n");

   for (channel = 1; channel <= pwm_basicOps_params->maxChannels; channel++)
   {
      printf(" %d ", channel);

      /* Retrieve Current Limit */
      check_status(naibrd_PWM_GetCurrentLimit(cardIndex, module, channel, &currentLimit_mA));
      check_status(naibrd_PWM_GetChannelRaw(cardIndex, module, channel, NAI_PWM_CHAN_RAW_CURRENT_LIMIT, &hexValue));
      printf("%8.3f (0x%08X)", currentLimit_mA/1000.0f, hexValue);

      /* Retrieve Input Scale */
      check_status(naibrd_PWM_GetInputScale(cardIndex, module, channel, &cfgValue));
      printf("  %6d (0x%08X)", cfgValue, cfgValue);

      /* Retrieve Global Gain */
      check_status(naibrd_PWM_GetGlobalGain(cardIndex, module, channel, &cfgValue));
      printf("  %6d (0x%08X)", cfgValue, cfgValue);

      /* Retrieve Integral Gain */
      check_status(naibrd_PWM_GetIntegralGain(cardIndex, module, channel, &cfgValue));
      printf("   %6d (0x%08X)", cfgValue, cfgValue);

      /* Retrieve Proportional Gain */
      check_status(naibrd_PWM_GetProportionalGain(cardIndex, module, channel, &cfgValue));
      printf(" %6d (0x%08X)", cfgValue, cfgValue);

      printf("\n");
   }
   return NAI_SUCCESS;
}

static bool_t setPWMChannelCfg(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t bCmdFound = FALSE;
   int32_t cmd;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t channel  = pwm_basicOps_params->channel;

   sprintf((char*)g_op, "\nPlease select the channel to update or Q to quit (default: 1): ");
   channel = queryPWMChannel(g_op, pwm_basicOps_params->maxChannels, 1);
   if (channel > 0)
   {
      naiapp_utils_LoadParamMenuCommands(PWM_CMD_CHAN_CFG_COUNT, PWM_ChannelCfgMenuCmds);
      naiapp_display_ParamMenuCommands((int8_t *)"Channel Configuration Menu");
      printf("Type Channel Configuration command or %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
      if (!bQuit)
      {
         if (g_responseCnt > 0)
         {
            bCmdFound = naiapp_utils_GetParamMenuCmdNum(g_responseCnt, g_op, &cmd);
            if (bCmdFound)
            {
               switch (cmd)
               {
                  case PWM_CMD_CHAN_CFG_CURRENT_LIMIT:
                  case PWM_CMD_CHAN_CFG_INPUT_SCALE:
                  case PWM_CMD_CHAN_CFG_GLOBAL_GAIN:
                  case PWM_CMD_CHAN_CFG_INTEGRAL_GAIN:
                  case PWM_CMD_CHAN_CFG_PROPORTIONAL_GAIN:
                     PWM_ChannelCfgMenuCmds[cmd].func(paramCount, p_params);
                     break;
                  default:
                     break;
               }
            }
         }
      }
   }
   else
   {
      bQuit = TRUE;
   }
   return bQuit;
}

static nai_status_t setCurrentLimit(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   float32_t currentLimit;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;
   nai_status_t status = NAI_SUCCESS;

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


   sprintf((char*)g_op, "Enter the Current Limit in amps for Channel %d: ", channel);
   bQuit = queryFloat32Value(g_op, &currentLimit);
   if (!bQuit)
   {
      /* Note, the current API is units of mA */
      status = check_status(naibrd_PWM_SetCurrentLimit(cardIndex, module, channel, currentLimit * 1000.0f));
   }
   return status;
}

static nai_status_t setInputScale(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   int32_t cfgValue;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enter the Input Scale for Channel %d: ", channel);
   bQuit = queryInt32Value(g_op, &cfgValue);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetInputScale(cardIndex, module, channel, cfgValue));
   }
   return status;
}

static nai_status_t setGlobalGain(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   int32_t cfgValue;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enter the Global Gain for Channel %d: ", channel);
   bQuit = queryInt32Value(g_op, &cfgValue);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetGlobalGain(cardIndex, module, channel, cfgValue));
   }
   return status;
}

static nai_status_t setIntegralGain(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   int32_t cfgValue;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enter the Integral Gain for Channel %d: ", channel);
   bQuit = queryInt32Value(g_op, &cfgValue);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetIntegralGain(cardIndex, module, channel, cfgValue));
   }
   return status;
}

static nai_status_t setProportionalGain(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   int32_t cfgValue;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   int32_t channel  = pwm_basicOps_params->channel;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enter the Proportional Gain for Channel %d: ", channel);
   bQuit = queryInt32Value(g_op, &cfgValue);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetProportionalGain(cardIndex, module, channel, cfgValue));
   }
   return status;
}

/********************************************/
/* PWM VME/PCIe/Ethernet Watchdog Functions */
/********************************************/
static nai_status_t handlePWMWatchdogCfg(int32_t paramCount, int32_t* p_params)
{
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;

   while (bContinue)
   {
      getPWMWatchdogCfg(paramCount, p_params);
      bQuit = setPWMWatchdogCfg(paramCount, p_params);
      if (bQuit)
      {
         bContinue = FALSE;
      }
   }

   return NAI_SUCCESS;
}

static nai_status_t getPWMWatchdogCfg(int32_t paramCount, int32_t* p_params)
{
   float32_t watchdogTimeout = 0;
   bool_t watchdogEnabled;
   uint32_t hexValue = 0;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("\n\nWatchdog Configuration:\n");
   printf("=======================\n");
   printf("   Timeout              Enabled        \n");
   printf("---------------------------------------\n");

   /* Retrieve Watchdog Timeout */
   check_status(naibrd_PWM_GetWatchdogTimeout(cardIndex, module, &watchdogTimeout));
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_WATCHDOG_TIMEOUT, &hexValue));
   printf("%7.2f (0x%08X)", watchdogTimeout, hexValue);

   /* Retrieve Watchdog Enable State */
   check_status(naibrd_PWM_GetWatchdogEnable(cardIndex, module, &watchdogEnabled));
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_WATCHDOG_ENABLE, &hexValue));
   if (watchdogEnabled == TRUE)
   {
      printf("   Enabled");
   }
   else
   {
      printf("  Disabled");
   }
   printf(" (0x%08X)", hexValue);

   printf("\n");

   return NAI_SUCCESS;
}

static bool_t setPWMWatchdogCfg(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t bCmdFound = FALSE;
   int32_t cmd;

   naiapp_utils_LoadParamMenuCommands(PWM_CMD_WATCHDOG_COUNT, PWM_WatchdogMenuCmds);
   naiapp_display_ParamMenuCommands((int8_t *)"PWM Watchdog Menu");
   printf("Type Watchdog command or %c to quit : ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         bCmdFound = naiapp_utils_GetParamMenuCmdNum(g_responseCnt, g_op, &cmd);
         if (bCmdFound)
         {
            switch (cmd)
            {
               case PWM_CMD_WATCHDOG_TIMEOUT:
               case PWM_CMD_WATCHDOG_ENABLE:
                  PWM_WatchdogMenuCmds[cmd].func(paramCount, p_params);
                  break;
               default:
                  break;
            }
         }
      }
   }
   return bQuit;
}

static nai_status_t setPWMWatchdogTimeout(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   float32_t cfgValue;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enter the Watchdog Timeout in milliseconds: ");
   bQuit = queryFloat32Value(g_op, &cfgValue);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetWatchdogTimeout(cardIndex, module, cfgValue));
   }
   return status;
}

static nai_status_t setPWMWatchdogEnable(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t responseYes = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enable the Watchdog (Y or N)?: ");
   bQuit = queryYesNoValue(g_op, &responseYes);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetWatchdogEnable(cardIndex, module, responseYes));
   }
   return status;
}

/*********************************/
/* PWM General Control Functions */
/*********************************/
static nai_status_t handlePWMGeneralControls(int32_t paramCount, int32_t* p_params)
{
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;

   while (bContinue)
   {
      getPWMGeneralControls(paramCount, p_params);
      bQuit = setPWMGeneralControls(paramCount, p_params);
      if (bQuit)
      {
         bContinue = FALSE;
      }
   }

   return NAI_SUCCESS;
}

static nai_status_t getPWMGeneralControls(int32_t paramCount, int32_t* p_params)
{
   bool_t battlefieldOverrideEnabled;
   bool_t psOvertempOverrideEnabled;
   uint32_t hexValue = 0;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("\n\nGeneral Controls:\n");
   printf("=================\n");
   printf("Battlefield Override     PS Over-temp Override\n");
   printf("     Enabled                  Enabled\n");
   printf("----------------------------------------------\n");

   /* Retrieve Battlefield Override Enable State */
   check_status(naibrd_PWM_GetBattlefieldOverrideEnable(cardIndex, module, &battlefieldOverrideEnabled));
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_BATTLEFIELD_OVERRIDE_ENABLE, &hexValue));
   if (battlefieldOverrideEnabled == TRUE)
   {
      printf(" Enabled");
   }
   else
   {
      printf("Disabled");
   }
   printf(" (0x%08X)      ", hexValue);

   /* Retrieve PS Over-Temperature Override Enable State */
   check_status(naibrd_PWM_GetPSOverTempOverrideEnable(cardIndex, module, &psOvertempOverrideEnabled));
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_PS_OVERTEMP_DISABLE_OVERRIDE, &hexValue));
   if (psOvertempOverrideEnabled == TRUE)
   {
      printf(" Enabled");
   }
   else
   {
      printf("Disabled");
   }
   printf(" (0x%08X)", hexValue);

   printf("\n");

   return NAI_SUCCESS;
}

static bool_t setPWMGeneralControls(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t bCmdFound = FALSE;
   int32_t cmd;

   do
   {
      naiapp_utils_LoadParamMenuCommands(PWM_CMD_GENERAL_CONTROL_COUNT, PWM_GeneralControlMenuCmds);
      naiapp_display_ParamMenuCommands((int8_t*)"PWM General Control Menu");
      printf("\n\nPlease enter a command or 'q' to quit:");
      bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);

      if (!bQuit)
      {
         if (g_responseCnt > 0)
         {
            bCmdFound = naiapp_utils_GetParamMenuCmdNum(g_responseCnt, g_op, &cmd);
            if (bCmdFound)
            {
               switch (cmd)
               {
                  case PWM_CMD_BATTLEFIELD_OVERRIDE_ENABLE:
                  case PWM_CMD_PS_OVERTEMP_OVERRIDE_ENABLE:
                  case PWM_CMD_SOFT_RESET:
                     PWM_GeneralControlMenuCmds[cmd].func(paramCount, p_params);
                     break;
                  default:
                     break;
               }
            }
         }
      }
   } while (!bQuit);

   return bQuit;
}

static nai_status_t setPWMSoftReset(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t responseYes = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   sprintf((char*)g_op, "Reset PWM (Y or N)?: ");
   bQuit = queryYesNoValue(g_op, &responseYes);
   if (!bQuit)
   {
      if (responseYes == TRUE)
      {
         check_status(naibrd_PWM_SoftReset(cardIndex, module));
      }
   }
   return NAI_SUCCESS;
}

static nai_status_t setPWMBattlefieldOverrideEnable(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t responseYes = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   sprintf((char*)g_op, "Enable the Battlefield Override (Y or N)?: ");
   bQuit = queryYesNoValue(g_op, &responseYes);
   if (!bQuit)
   {
      check_status(naibrd_PWM_SetBattlefieldOverrideEnable(cardIndex, module, responseYes));
   }
   return NAI_SUCCESS;
}

static nai_status_t setPWMPSOvertempOverrideEnable(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t responseYes = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   sprintf((char*)g_op, "Enable the PS Over-Temperature Override (Y or N)?: ");
   bQuit = queryYesNoValue(g_op, &responseYes);
   if (!bQuit)
   {
      check_status(naibrd_PWM_SetPSOverTempOverrideEnable(cardIndex, module, responseYes));
   }
   return NAI_SUCCESS;
}


/****************************/
/* Serial Control Functions */
/****************************/
static nai_status_t handlePWMSerialControls(int32_t paramCount, int32_t* p_params)
{
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;

   while (bContinue)
   {
      getPWMSerialControls(paramCount, p_params);
      bQuit = setPWMSerialControls(paramCount, p_params);
      if (bQuit)
      {
         bContinue = FALSE;
      }
   }
   return NAI_SUCCESS;
}

static nai_status_t getPWMSerialControls(int32_t paramCount, int32_t* p_params)
{
   nai_pwm_clock_edge_t clockEdge;
   float32_t watchdogTimeout;
   bool_t bEnabled;
   uint32_t testBits;
   int32_t count;
   bool_t bDisabled;
   uint32_t hexValue = 0;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("\n\nSerial Controls:\n");
   printf("====================\n");

   printf("Serial Configuration\n");
   printf("--------------------\n");
   printf("Rx Clock                Serial Watchdog       Serial Watchdog   Serial Test     Serial Transmit\n");
   printf("  Edge                    Timeout (ms)            Enable            Bits            Enable\n");
   printf("----------------------------------------------------------------------------------------------------\n");

   /* Retrieve Rx Clock Edge */
   check_status(naibrd_PWM_GetSerialRxClockEdge(cardIndex, module, &clockEdge));
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_SERIAL_RX_CLOCK_EDGE, &hexValue));
   switch (clockEdge)
   {
      case NAI_PWM_CLOCK_EDGE_RISING:
         printf(" Rising");
         break;
      case NAI_PWM_CLOCK_EDGE_FALLING:
         printf("Falling");
         break;
      default:
         printf("Unknown");
         break;
   }
   printf(" (0x%08X) ", hexValue);

   /* Retrieve Serial Watchdog Timeout */
   check_status(naibrd_PWM_GetSerialWatchdogTimeout(cardIndex, module, &watchdogTimeout));
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_SERIAL_WATCHDOG_TIMEOUT, &hexValue));
   printf("%7.2f (0x%08X)", watchdogTimeout, hexValue);

   /* Retrieve Serial Watchdog Enable State */
   check_status(naibrd_PWM_GetSerialWatchdogEnable(cardIndex, module, &bEnabled));
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_SERIAL_WATCHDOG_ENABLE, &hexValue));
   if (bEnabled == TRUE)
   {
      printf("   Enabled");
   }
   else
   {
      printf("  Disabled");
   }
   printf(" (0x%08X)", hexValue);

   /* Retrieve Serial Test Bits */
   check_status(naibrd_PWM_GetSerialTestBits(cardIndex, module, &testBits));
   printf(" 0x%08X  ", testBits);

   /* Retrieve Serial Transmit Enable */
   check_status(naibrd_PWM_GetSerialTransmitEnable(cardIndex, module, &bEnabled));
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_SERIAL_TRANSMIT_ENABLE, &hexValue));
   if (bEnabled == TRUE)
   {
      printf("  Enabled");
   }
   else
   {
      printf(" Disabled");
   }
   printf(" (0x%08X)", hexValue);

   printf("\n\n");
   printf("CRC Error/Data Frame\n");
   printf("--------------------\n");
   printf("  CRC Error    Data Frame    CRC Error Count     Data Frame Count      Data Frame\n");
   printf("    Count        Count           Disable             Disabled            Status\n");
   printf("----------------------------------------------------------------------------------\n");

   /* Retrieve CRC Error Count */
   check_status(naibrd_PWM_GetCRCErrorCount(cardIndex, module, &count));
   printf("   %5d", count);

   /* Retrieve Data Frame Count */
   check_status(naibrd_PWM_GetDataFrameCount(cardIndex, module, &count));
   printf("        %5d   ", count);

   /* Retrieve CRC Error Count Disable */
   check_status(naibrd_PWM_GetCRCErrorCountDisable(cardIndex, module, &bDisabled));
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_SERIAL_CRC_ERROR_COUNT_DISABLE, &hexValue));
   if (bDisabled == FALSE)
   {
      printf("  Enabled");
   }
   else
   {
      printf(" Disabled");
   }
   printf(" (0x%08X)", hexValue);

   /* Retrieve Data Frame Count Diable */
   check_status(naibrd_PWM_GetDataFrameCountDisable(cardIndex, module, &bDisabled));
   check_status(naibrd_PWM_GetRaw(cardIndex, module, NAI_PWM_RAW_SERIAL_DATA_FRAME_COUNT_DISABLE, &hexValue));
   if (bDisabled == FALSE)
   {
      printf("  Enabled");
   }
   else
   {
      printf(" Disabled");
   }
   printf(" (0x%08X)", hexValue);

   /* Retrieve Data Frame Status */
   check_status(naibrd_PWM_GetDataFrameStatus(cardIndex, module, &hexValue));
   printf("   0x%08X", hexValue);

   printf("\n");
   return NAI_SUCCESS;
}


static bool_t setPWMSerialControls(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t bCmdFound = FALSE;
   int32_t cmd;

   naiapp_utils_LoadParamMenuCommands(PWM_CMD_SERIAL_CONTROL_COUNT, PWM_SerialControlMenuCmds);
   naiapp_display_ParamMenuCommands((int8_t *)"PWM Serial Control Menu");
   printf("Type Serial Control command or %c to quit : ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         bCmdFound = naiapp_utils_GetParamMenuCmdNum(g_responseCnt, g_op, &cmd);
         if (bCmdFound)
         {
            switch (cmd)
            {
               case PWM_CMD_SERIAL_RX_CLOCK_EDGE:
               case PWM_CMD_SERIAL_WATCHDOG_TIMEOUT:
               case PWM_CMD_SERIAL_WATCHDOG_ENABLE:
               case PWM_CMD_SERIAL_TESTBITS:
               case PWM_CMD_SERIAL_TRANSMIT_ENABLE:
               case PWM_CMD_SERIAL_DISABLE_CRC_ERROR_COUNT:
               case PWM_CMD_SERIAL_DISABLE_DATA_FRAME_COUNT:
                  PWM_SerialControlMenuCmds[cmd].func(paramCount, p_params);
                  break;
               default:
                  break;
            }
         }
      }
   }
   return bQuit;
}

static nai_status_t setPWMSerialRxClockEdge(int32_t paramCount, int32_t* p_params)
{
   nai_status_t status = NAI_SUCCESS;
   bool_t bQuit = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;

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

   printf("Set Clock Edge:\n");
   printf("R - Rising\n");
   printf("F - Falling\n");
   printf(">");
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         if ((toupper(g_op[0]) == 'R'))
         {
            status = check_status(naibrd_PWM_SetSerialRxClockEdge(cardIndex, module, NAI_PWM_CLOCK_EDGE_RISING));
         }
         else if ((toupper(g_op[0]) == 'F'))
         {
            status = check_status(naibrd_PWM_SetSerialRxClockEdge(cardIndex, module, NAI_PWM_CLOCK_EDGE_FALLING));
         }
      }
   }
   return status;
}

static nai_status_t setPWMSerialWatchdogTimeout(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   float32_t cfgValue;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enter the Serial Watchdog Timeout in milliseconds: ");
   bQuit = queryFloat32Value(g_op, &cfgValue);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetSerialWatchdogTimeout(cardIndex, module, cfgValue));
   }
   return status;
}

static nai_status_t setPWMSerialWatchdogEnable(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t responseYes = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enable the Serial Watchdog (Y or N)?: ");
   bQuit = queryYesNoValue(g_op, &responseYes);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetSerialWatchdogEnable(cardIndex, module, responseYes));
   }
   return status;
}

static nai_status_t setPWMSerialTestBits(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   uint32_t hexValue;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enter the Serial Test Value in Hex: ");
   bQuit = queryHex32Value(g_op, &hexValue);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetSerialTestBits(cardIndex, module, hexValue));
   }
   return status;
}

static nai_status_t setPWMSerialTransmitEnable(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t responseYes = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Enable the Serial Transmit (Y or N)?: ");
   bQuit = queryYesNoValue(g_op, &responseYes);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetSerialTransmitEnable(cardIndex, module, responseYes));
   }
   return status;
}

static nai_status_t setPWMCRCErrorCountDisable(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t responseYes = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Disable the CRC Error Count (Y or N)?: ");
   bQuit = queryYesNoValue(g_op, &responseYes);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetCRCErrorCountDisable(cardIndex, module, responseYes));
   }
   return status;
}

static nai_status_t setPWMDataFrameCountDisable(int32_t paramCount, int32_t* p_params)
{
   bool_t bQuit = FALSE;
   bool_t responseYes = FALSE;
   p_naiapp_AppParameters_t pwm_basicOps_params = (p_naiapp_AppParameters_t)p_params;
   int32_t cardIndex = pwm_basicOps_params->cardIndex;
   int32_t module = pwm_basicOps_params->module;
   nai_status_t status = NAI_SUCCESS;

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

   sprintf((char*)g_op, "Disable the Data Frame Count (Y or N)?: ");
   bQuit = queryYesNoValue(g_op, &responseYes);
   if (!bQuit)
   {
      status = check_status(naibrd_PWM_SetDataFrameCountDisable(cardIndex, module, responseYes));
   }
   return status;
}


/*********************************/
/*     Private Query Routines    */
/*********************************/
static int32_t queryPWMChannel(int8_t* p_queryText, int32_t maxChannel, int32_t defaultValue)
{
   bool_t bQuit = FALSE;
   bool_t bContinue = TRUE;
   int32_t channel = defaultValue;

   if (maxChannel > 1)
   {
      while (bContinue)
      {
         printf("%s", p_queryText);
         bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
         if (!bQuit)
         {
            if (g_responseCnt > 0)
            {
               channel = (int32_t)atol((const char*)g_op);
               if ((channel > 0) && (channel <= maxChannel))
               {
                  bContinue = FALSE;
               }
               else
               {
                  printf("ERROR: Invalid channel entered\n");
               }
            }
            else
            {
               channel = defaultValue;
               bContinue = FALSE;
            }
         }
         else
         {
            channel = 0;
            bContinue = FALSE;
         }
      }
   }
   return channel;
}

static bool_t queryFloat32Value(int8_t* p_queryText, float32_t* p_outFloat32)
{
   bool_t bQuit = FALSE;

   printf("%s ", p_queryText);
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         *p_outFloat32 = (float32_t)atof((const char*)g_op);
      }
      else
      {
         printf("Invalid value entered\n");
      }
   }
   return bQuit;
}

static bool_t queryInt32Value(int8_t* p_queryText, int32_t* p_outInt32)
{
   bool_t bQuit = FALSE;

   printf("%s ", p_queryText);
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         *p_outInt32 = (int32_t)atol((const char*)g_op);
      }
      else
      {
         printf("Invalid value entered\n");
      }
   }
   return bQuit;
}

static bool_t queryYesNoValue(int8_t* p_queryText, bool_t* p_outresponseYes)
{
   bool_t bQuit = FALSE;

   printf("%s ", p_queryText);
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         if (toupper(g_op[0]) == 'Y')
         {
            *p_outresponseYes = TRUE;
         }
         else if (toupper(g_op[0]) == 'N')
         {
            *p_outresponseYes = FALSE;
         }
         else
         {
            printf("Invalid value entered\n");
            *p_outresponseYes = FALSE;
         }
      }
      else
      {
         printf("Invalid value entered\n");
      }
   }
   return bQuit;
}

static bool_t queryHex32Value(int8_t* p_queryText, uint32_t* p_outHex32)
{
   bool_t bQuit = FALSE;

   printf("%s ", p_queryText);
   bQuit = naiapp_query_ForQuitResponse(sizeof(g_op), NAI_QUIT_CHAR, g_op, &g_responseCnt);
   if (!bQuit)
   {
      if (g_responseCnt > 0)
      {
         *p_outHex32 = naiapp_utils_HexStrToDecUInt32(g_op);
      }
      else
      {
         printf("Invalid value entered\n");
      }
   }
   return bQuit;
}

Help Bot

X