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

Sync BasicOps

Sync BasicOps Sample Application (SSK 1.x)

Overview

The Sync BasicOps sample application demonstrates how to synchronize analog-to-digital (AD) and digital-to-analog (DA) modules on the same NAI board so that they sample and output data in lockstep. Synchronized operation is essential whenever your system requires time-correlated measurements and stimulus — for example, driving a test signal from a DA channel while simultaneously capturing the response on an AD channel with guaranteed timing alignment.

The sample uses the NAI Software Support Kit (SSK 1.x) synchronization and FIFO APIs to configure a master/slave clock and trigger relationship across multiple modules, load DA FIFO output data, trigger all FIFOs simultaneously, and collect the resulting AD FIFO acquisition data to a file. It covers two independent synchronization axes — clock synchronization (all modules sample at the same rate) and trigger synchronization (all FIFOs start at the same instant) — and shows how to configure each one.

This sample supports the following module types:

  • AD modules: AD1 through AD6, ADE, ADF, ADG

  • DA modules: DA1 through DA5

  • Combination modules: CME, CMF, CMG (these contain both AD and DA functionality and participate in synchronization as their underlying AD or DA type)

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

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with at least two sync-capable modules installed (any combination of AD1-AD6, ADE-ADG, DA1-DA5, CME, CMF, CMG).

  • 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 Sync_BasicOps executable from your build output directory. On startup the application looks for a configuration file (default_Sync_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. You can save this configuration so that subsequent runs skip the menu and connect automatically. Once connected, the application scans all module slots, identifies which modules support synchronization, and presents a command menu.

Why Synchronize?

Each NAI module has its own internal clock and FIFO trigger logic. Without synchronization, two modules sampling at nominally the same rate will drift relative to each other — their sample instants will not align, and their FIFOs will start at different times. The synchronization framework solves this by letting you designate one module as the master that provides the clock and/or trigger signal to all other slave modules. When configured correctly:

  • Clock sync ensures every module samples or outputs at exactly the same rate, derived from a single clock source.

  • Trigger sync ensures every FIFO starts capturing or outputting at exactly the same instant, initiated by a single trigger event on the master.

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 AD/DA synchronization. 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_Sync_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. Retrieve the total module count with naibrd_GetModuleCount().

  4. Pass both values to SyncBasicOps_run(), which scans all slots and identifies sync-capable modules.

#if defined (__VXWORKS__)
int32_t Sync_BasicOps(void)
#else
int32_t main(void)
#endif
{
   bool_t bQuit = FALSE;
   int32_t cardIndex = -1;
   int32_t moduleCount;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
   {
      while (!bQuit)
      {
         naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         naibrd_GetModuleCount(cardIndex, &moduleCount);
         bQuit = SyncBasicOps_run(cardIndex, moduleCount);
      }

      printf("Type the Enter key to exit the program: ");
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   }

   naiapp_access_CloseAllOpenCards();

   return 0;
}

Unlike most SSK samples, this application does not prompt for a single module slot. Instead, synchronization operates across all modules on the board. The SyncBasicOps_run() function iterates through every slot and determines which modules support synchronization.

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 index — card indices are zero-based. Ensure the value you pass matches your hardware setup.

  • Module not present at selected slot — the slot you selected does not contain a sync-capable module. The sample will display "NO" in the SyncSupport column for unsupported modules.

Program Structure

Sync Info Structure

The application tracks all per-module state in a single naiapp_syncInfo_t structure. In your own application, you will need to maintain equivalent values for each module participating in synchronized operation.

typedef struct naiapp_syncInfo
{
   int32_t cardIndex;
   int32_t moduleCount;
   uint32_t modId[NAI_MAX_MODULES];
   syncops_module_type_t moduleType[NAI_MAX_MODULES];
   int32_t triggerMasterModNum;
   int32_t channel[NAI_MAX_MODULES];  /* 1 channel per module. */
} naiapp_syncInfo_t;
  • cardIndex — the board connection index, obtained from naiapp_query_CardIndex().

  • moduleCount — total number of module slots on the board.

  • modId[] — the module ID for each slot (e.g., NAI_MODULE_ID_AD1, NAI_MODULE_ID_DA3).

  • moduleType[] — a simplified type classification (SYNCOPS_MOD_TYPE_AD or SYNCOPS_MOD_TYPE_DA) derived by masking the upper 16 bits of the module ID. This lets the sample dispatch to the correct AD or DA API variant.

  • triggerMasterModNum — the module number currently designated as the trigger master.

  • channel[] — the selected FIFO channel for each module (defaults to channel 1).

Module Type Detection

The sample determines whether a module is an AD type or DA type by masking the module ID:

#define SYNCOPS_MOD_TYPE_MASK  0xFFFF0000u
#define SYNCOPS_MOD_TYPE_AD    (syncops_module_type_t)(NAI_MODULE_ID_AD1 & SYNCOPS_MOD_TYPE_MASK)
#define SYNCOPS_MOD_TYPE_DA    (syncops_module_type_t)(NAI_MODULE_ID_DA1 & SYNCOPS_MOD_TYPE_MASK)

Combination modules (CME, CMF, CMG) are classified by their underlying type through the same mask. This pattern lets the sample call the correct AD or DA API for each module without enumerating every module ID individually.

Initialization and FIFO Sizing

When SyncBasicOps_run() starts, it iterates through all module slots and performs the following for each sync-capable module:

  1. Retrieves the module ID with naibrd_GetModuleID().

  2. Classifies the module type and checks sync support via SyncSupported().

  3. Queries the current trigger sync mode to determine if a master is already configured.

  4. Sets the FIFO size on all channels to SYNCOPS_NUM_FIFO_SAMPLES (100 samples).

for(moduleIndex = 0; moduleIndex < moduleCount; moduleIndex++)
{
   syncInfo.channel[moduleIndex] = DEFAULT_CHANNEL;
   syncInfo.modId[moduleIndex] = naibrd_GetModuleID(cardIndex, moduleIndex + 1);
   syncInfo.moduleType[moduleIndex] = GetModuleType(syncInfo.modId[moduleIndex]);

   if (FALSE != SyncSupported(syncInfo.modId[moduleIndex]))
   {
      GetModuleSyncMode(syncInfo, moduleIndex + 1, NAIBRD_SYNC_CONFIG_TRIGGER, &syncMode, &triggerMasterModNum);
      if (NAIBRD_MODULE_SYNC_MODE_MASTER == syncMode)
      {
         syncInfo.triggerMasterModNum = triggerMasterModNum;
      }

      switch(syncInfo.moduleType[moduleIndex])
      {
         case SYNCOPS_MOD_TYPE_AD:
            for (channel = 1; channel <= naibrd_AD_GetChannelCount(syncInfo.modId[moduleIndex]); channel++)
            {
               check_status(naibrd_AD_SetFIFOSize(syncInfo.cardIndex, moduleIndex + 1, channel, SYNCOPS_NUM_FIFO_SAMPLES));
            }
         break;

         case SYNCOPS_MOD_TYPE_DA:
            for (channel = 1; channel <= naibrd_DA_GetChannelCount(syncInfo.modId[moduleIndex]); channel++)
            {
               check_status(naibrd_DA_SetFIFOSize(syncInfo.cardIndex, moduleIndex + 1, channel, SYNCOPS_NUM_FIFO_SAMPLES));
            }
         break;
      }
   }
}

To set the FIFO size in your own application, call naibrd_AD_SetFIFOSize() for AD modules or naibrd_DA_SetFIFOSize() for DA modules. The FIFO size determines how many samples are captured or output per trigger event.

Command Menu

After initialization, the application enters a command loop. The menu system is a sample convenience — in your own code, call these API functions directly.

Command Description

CS

Configure Clock Sync — set the clock synchronization mode for a module

CF

Configure FIFO — set the FIFO trigger synchronization mode for a module

CLF

Clear FIFO — clear FIFO contents for one or all modules

LOAD

Load DA FIFOs — write output data into all sync-enabled DA FIFOs

TRIG

Trigger Master — fire the software trigger on the master to start all FIFOs

STOP

Stop FIFO — disable FIFO triggers on all modules

COLLECT

Collect Data — read AD FIFO data and save to sync_data.txt

The status display printed before each command prompt shows the current sync configuration for every module slot:

static void SyncBasicOps_displayConfigurations(int32_t paramCount, naiapp_syncInfo_t* p_syncInfo)
{
   /* ... */
   printf("------Module Info------    --------SyncClockConfig---------    --------SyncTriggerConfig-------    --------------FIFO Setup--------------\n");
   printf(" ModNum  ID  SyncSupport   Mode                MasterModNum    Mode                MasterModNum    Rate   Channel   NumSamples  FifoCount\n");
   /* ... */
}

This display lets you verify at a glance which modules are configured as master, which are slaves, and the current FIFO state before issuing commands.

Clock Synchronization (CS Command)

Clock synchronization ensures that all participating modules sample or output at exactly the same rate, derived from a single clock source. To configure clock synchronization for a module in your own application, call naibrd_AD_SetModuleSyncMode() (for AD modules) or naibrd_DA_SetModuleSyncMode() (for DA modules) with NAIBRD_SYNC_CONFIG_CLOCK as the configuration type.

The sample presents five clock sync modes:

Mode Description

0 — DISABLED

The module uses its internal clock independently. No synchronization.

1 — MASTER

This module supplies its clock to all slave modules. The master module number is set to itself.

2 — SLAVE (USER CLOCK)

The module syncs to an external user-supplied clock signal and can relay it to other slaves.

3 — SLAVE (INTERNAL)

The module receives its clock from another module on the same board that is configured as MASTER or USER CLOCK.

4 — SLAVE (EXTERNAL BOARD)

The module receives its clock from an off-board master.

nai_status_t SyncBasicOps_configClockSync(int32_t paramCount, int32_t* p_params)
{
   naiapp_syncInfo_t* p_syncInfo = (naiapp_syncInfo_t*)p_params;
   /* ... user selects module and mode ... */

   switch (modeSelect)
   {
      case 0:
         masterModNum = 0;
         status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK,
            NAIBRD_MODULE_SYNC_MODE_DISABLED, masterModNum);
      break;

      case 1:
         masterModNum = modNum;
         status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK,
            NAIBRD_MODULE_SYNC_MODE_MASTER, masterModNum);
      break;

      case 2:
         masterModNum = 0;
         status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK,
            NAIBRD_MODULE_SYNC_MODE_SLAVE_USER_CLOCK, masterModNum);
      break;

      case 3:
         bQuit = GetMasterModule(p_syncInfo, &masterModNum);
         status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK,
            NAIBRD_MODULE_SYNC_MODE_SLAVE_INTERNAL, masterModNum);
      break;

      case 4:
         bQuit = GetMasterModule(p_syncInfo, &masterModNum);
         status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK,
            NAIBRD_MODULE_SYNC_MODE_SLAVE_BOARD_CLOCK, masterModNum);
      break;
   }
}

The SetModuleSyncMode() helper dispatches to the correct API based on module type:

static nai_status_t SetModuleSyncMode(naiapp_syncInfo_t syncInfo, int32_t modNum,
   naibrd_module_sync_config_type_t config, naibrd_module_sync_mode_type_t mode, int32_t masterModNum)
{
   switch(syncInfo.moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = naibrd_AD_SetModuleSyncMode(syncInfo.cardIndex, modNum, config, mode, masterModNum);
         break;

      case SYNCOPS_MOD_TYPE_DA:
         status = naibrd_DA_SetModuleSyncMode(syncInfo.cardIndex, modNum, config, mode, masterModNum);
         break;
   }
}

API parameters:

  • cardIndex — the board connection index.

  • modNum — the 1-based module slot number.

  • config — either NAIBRD_SYNC_CONFIG_CLOCK (for clock sync) or NAIBRD_SYNC_CONFIG_TRIGGER (for trigger sync).

  • mode — one of the NAIBRD_MODULE_SYNC_MODE_* enumeration values.

  • masterModNum — the module slot that serves as the clock source. Set to the module’s own slot number for MASTER mode, or to 0 to disable.

For slave modes that reference another module on the board (SLAVE_INTERNAL), the masterModNum parameter must point to a slot that has already been configured as MASTER or USER_CLOCK.

Important

Common Errors

  • NAI_ERROR_NOT_SUPPORTED — the module at the selected slot does not support synchronization. Verify the module type is one of the supported AD, DA, or CM modules.

  • Clock drift between modules — if you see timing differences in collected data, verify that all slave modules reference the same master. Use the status display to confirm the MasterModNum column is consistent.

  • SLAVE mode with no master configured — configuring a module as SLAVE_INTERNAL before any module is set as MASTER will result in no clock signal being provided. Always configure the master first.

FIFO Trigger Synchronization (CF Command)

Trigger synchronization controls when FIFOs start their I/O operations. This is independent of clock synchronization — you can synchronize clocks without synchronizing triggers, or vice versa. In a typical synchronized acquisition/output scenario, you configure both.

To configure trigger synchronization, call naibrd_AD_SetModuleSyncMode() or naibrd_DA_SetModuleSyncMode() with NAIBRD_SYNC_CONFIG_TRIGGER, then configure the FIFO trigger control register with naibrd_AD_SetFIFOTrigCtrl() or naibrd_DA_SetFIFOTrigCtrl().

The sample presents four trigger sync modes:

Mode Description

0 — DISABLED

The module uses its own internal FIFO trigger. No synchronization.

1 — MASTER

This module supplies the FIFO trigger to all slave modules. Configured with software trigger + continuous mode.

2 — SLAVE (USER TRIGGER)

The module’s FIFO is triggered by an external signal and relays it to slaves. Configured with positive-edge trigger + continuous mode.

3 — SLAVE (INTERNAL)

The module’s FIFO is triggered from a MASTER or USER TRIGGER module on the same board. Configured with positive-edge trigger + continuous mode.

nai_status_t SyncBasicOps_configFifo(int32_t paramCount, int32_t* p_params)
{
   naiapp_syncInfo_t* p_syncInfo = (naiapp_syncInfo_t*)p_params;
   /* ... user selects module and mode ... */

   switch (modeSelect)
   {
      case 0:
         p_syncInfo->triggerMasterModNum = 0;
         status = ConfigFifoSync(p_syncInfo, modNum, NAIBRD_MODULE_SYNC_MODE_DISABLED,
            (uint32_t)NAI_AD_GEN5_FIFO_TRIG_STOP);
      break;

      case 1:
         p_syncInfo->triggerMasterModNum = modNum;
         status = ConfigFifoSync(p_syncInfo, modNum, NAIBRD_MODULE_SYNC_MODE_MASTER,
            (uint32_t)(NAI_AD_GEN5_FIFO_TRIG_SOFT | NAI_AD_GEN5_FIFO_TRIG_CONTINUOUS));
      break;

      case 2:
         p_syncInfo->triggerMasterModNum = 0;
         status = ConfigFifoSync(p_syncInfo, modNum, NAIBRD_MODULE_SYNC_MODE_SLAVE_USER_CLOCK,
            (uint32_t)(NAI_AD_GEN5_FIFO_TRIG_POS_EDGE | NAI_AD_GEN5_FIFO_TRIG_CONTINUOUS));
      break;

      case 3:
         bQuit = GetMasterModule(p_syncInfo, &(p_syncInfo->triggerMasterModNum));
         status = ConfigFifoSync(p_syncInfo, modNum, NAIBRD_MODULE_SYNC_MODE_SLAVE_INTERNAL,
            (uint32_t)(NAI_AD_GEN5_FIFO_TRIG_POS_EDGE | NAI_AD_GEN5_FIFO_TRIG_CONTINUOUS));
      break;
   }

   naiapp_query_ChannelNumber(p_syncInfo->moduleCount, DEFAULT_CHANNEL, &(p_syncInfo->channel[modNum-1]));
}

The ConfigFifoSync() helper sets the trigger sync mode and then configures the FIFO trigger control register:

static nai_status_t ConfigFifoSync(naiapp_syncInfo_t *p_syncInfo, int32_t modNum,
   naibrd_module_sync_mode_type_t mode, uint32_t trigCtrl)
{
   nai_status_t status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_TRIGGER,
      mode, p_syncInfo->triggerMasterModNum);

   switch(p_syncInfo->moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = naibrd_AD_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum,
            p_syncInfo->channel[modNum-1], (nai_ad_fifo_trig_t)trigCtrl);
         break;

      case SYNCOPS_MOD_TYPE_DA:
         status = naibrd_DA_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum,
            p_syncInfo->channel[modNum-1], (nai_da_fifo_trig_t)trigCtrl);
         naibrd_DA_SetFIFOCtrl(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1],
            NAI_DA_GEN5_FIFO_CTRL_REPEAT_MODE | NAI_DA_GEN5_FIFO_CTRL_ENABLE);
         break;
   }
}

FIFO trigger control flags:

  • NAI_AD_GEN5_FIFO_TRIG_SOFT / NAI_DA_GEN5_FIFO_TRIG_SOFT — enables software trigger as the trigger source.

  • NAI_AD_GEN5_FIFO_TRIG_POS_EDGE / NAI_DA_GEN5_FIFO_TRIG_PSLOPE — triggers on the positive edge of the sync signal from the master.

  • NAI_AD_GEN5_FIFO_TRIG_CONTINUOUS / NAI_DA_GEN5_FIFO_TRIG_CONTINUOUS — keeps the FIFO running continuously after the initial trigger.

  • NAI_AD_GEN5_FIFO_TRIG_ENABLE / NAI_DA_GEN5_FIFO_TRIG_ENABLE — enables the FIFO trigger (set separately when starting I/O).

  • NAI_AD_GEN5_FIFO_TRIG_STOP / NAI_DA_GEN5_FIFO_TRIG_STOP — stops the FIFO.

For DA modules, the sample also calls naibrd_DA_SetFIFOCtrl() to enable FIFO repeat mode. This API may return NAI_ERROR_NOT_SUPPORTED on some DA module variants that do not require it — this is expected and does not indicate a problem.

After selecting the trigger mode, the sample prompts for a channel number. This channel is used for subsequent FIFO operations on that module.

Important

Common Errors

  • NAI_ERROR_NOT_SUPPORTED — the selected module does not support FIFO trigger synchronization. Verify the module type.

  • FIFO does not start — ensure the trigger enable bit is set (this happens in the TRIG command, not in CF). The CF command only configures the trigger source and mode.

  • Slave triggers before master — if a slave module’s FIFO starts unexpectedly, check that its trigger mode is set to positive-edge (not software trigger). Only the master should use software trigger.

Clear FIFO (CLF Command)

To clear stale data from a module’s FIFO before starting a new synchronized acquisition or output cycle, call naibrd_AD_ClearFIFO() for AD modules or naibrd_DA_ClearFIFO() for DA modules. The sample lets you clear a single module’s FIFO or all FIFOs at once.

static nai_status_t SyncBasicOps_clearFifo(int32_t paramCount, int32_t* p_params)
{
   naiapp_syncInfo_t *p_syncInfo = (naiapp_syncInfo_t*)p_params;
   /* ... user selects module or 'A' for all ... */

   for(modNum = startMod; modNum <= endMod; modNum++)
   {
      switch(p_syncInfo->moduleType[modNum-1])
      {
         case SYNCOPS_MOD_TYPE_AD:
            status = naibrd_AD_ClearFIFO(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1]);
            break;

         case SYNCOPS_MOD_TYPE_DA:
            status = naibrd_DA_ClearFIFO(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1]);
            break;
      }
   }
}

API parameters:

  • cardIndex — the board connection index.

  • modNum — the 1-based module slot number.

  • channel — the channel whose FIFO to clear. The sample uses the channel selected during FIFO configuration.

Always clear FIFOs before starting a new acquisition cycle. Stale data in the FIFO will be read out alongside new data, corrupting your results.

Important

Common Errors

  • Stale data in collected output — if your collected data contains unexpected values at the beginning, you likely did not clear the FIFO before triggering. Always issue CLF (or call the clear API) before TRIG.

  • NAI_ERROR_INVALID_MODULE — the selected module slot does not contain a sync-capable module.

Load DA FIFO Data (LOAD Command)

Before triggering a synchronized output, you must load waveform data into the DA module FIFOs. The sample writes an alternating pattern of 0.0 V and 5.0 V into each sync-enabled DA module’s FIFO, creating a simple square-wave output.

static nai_status_t SyncBasicOps_loadData(int32_t paramCount, int32_t* p_params)
{
   naiapp_syncInfo_t *p_syncInfo = (naiapp_syncInfo_t*)p_params;
   float32_t data[] = {0.0, 5.0};
   uint32_t written = 0;

   for (modNum = 1; modNum <= p_syncInfo->moduleCount; modNum++)
   {
      if (SYNCOPS_MOD_TYPE_DA == p_syncInfo->moduleType[modNum-1])
      {
         status = GetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_TRIGGER, &mode, &masterModNum);
         if (NAIBRD_MODULE_SYNC_MODE_DISABLED != mode)
         {
            /* Disable the FIFO to stop it from sending data while loading. */
            status = naibrd_DA_GetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum,
               p_syncInfo->channel[modNum-1], &trigCtrl);
            trigCtrl &= ~NAI_DA_GEN5_FIFO_TRIG_ENABLE;
            status = naibrd_DA_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum,
               p_syncInfo->channel[modNum-1], trigCtrl);

            /* Load the FIFO with data. */
            for (dataIndex = 0; dataIndex < SYNCOPS_NUM_FIFO_SAMPLES; dataIndex++)
            {
               status = naibrd_DA_SetFIFO32(p_syncInfo->cardIndex, modNum,
                  p_syncInfo->channel[modNum-1], 1,
                  &(data[dataIndex % (sizeof(data) / sizeof(data[0]))]), &written);
            }
         }
      }
   }
}

Key steps in your own code:

  1. Disable the FIFO trigger before loading data. Read the current trigger control with naibrd_DA_GetFIFOTrigCtrl(), clear the NAI_DA_GEN5_FIFO_TRIG_ENABLE bit, and write it back with naibrd_DA_SetFIFOTrigCtrl(). This prevents the FIFO from outputting data while you are loading it.

  2. Write samples one at a time using naibrd_DA_SetFIFO32(). The written output parameter confirms how many samples were accepted.

  3. The sample loads SYNCOPS_NUM_FIFO_SAMPLES (100) values, alternating between 0.0 and 5.0.

The LOAD command only writes to DA modules that have trigger synchronization enabled. If a DA module’s sync mode is DISABLED, the command skips it and prints a message.

Important

Common Errors

  • DA outputs nothing after trigger — verify that data was loaded before triggering. The LOAD command must be issued after CF (which configures the FIFO) and before TRIG.

  • FIFO overrun while loading — if the FIFO trigger was not disabled before loading, the FIFO may be simultaneously outputting and accepting data. Always disable the trigger enable bit before loading.

  • NAI_ERROR_NOT_SUPPORTED — the naibrd_DA_SetFIFOCtrl() call during CF may return this on some DA variants. This is expected and does not prevent FIFO loading.

Trigger Master (TRIG Command)

The TRIG command starts all synchronized FIFO operations by enabling the trigger on every module and then issuing a software trigger on the master. This single trigger event starts AD acquisition and DA output simultaneously across all synchronized modules.

nai_status_t SyncBasicOps_triggerMaster(int32_t paramCount, int32_t* p_params)
{
   naiapp_syncInfo_t *p_syncInfo = (naiapp_syncInfo_t*)p_params;

   /* Enable the FIFO triggers on all modules. */
   SetFifoTriggers(p_syncInfo, TRUE);

   if (0 != p_syncInfo->triggerMasterModNum)
   {
      /* Fire the software trigger on the master -- all slaves will trigger as well. */
      status = SoftwareTrigger(*p_syncInfo, p_syncInfo->triggerMasterModNum);
   }
   else
   {
      printf("Waiting for external trigger..\n");
   }
}

The SetFifoTriggers() helper iterates over all modules, reads the current FIFO trigger control register, and sets (or clears) the enable bit:

static nai_status_t SetFifoTriggers(naiapp_syncInfo_t *p_syncInfo, bool_t trigEnable)
{
   for(modIndex = 0; modIndex < p_syncInfo->moduleCount; modIndex++)
   {
      switch(p_syncInfo->moduleType[modIndex])
      {
         case SYNCOPS_MOD_TYPE_AD:
            naibrd_AD_GetFIFOTrigCtrl(p_syncInfo->cardIndex, modIndex + 1,
               p_syncInfo->channel[modIndex], (nai_ad_fifo_trig_t*)(&trigCtrl));
            if (trigEnable)
               trigCtrl |= (uint32_t)NAI_AD_GEN5_FIFO_TRIG_ENABLE;
            else
               trigCtrl &= (uint32_t)~NAI_AD_GEN5_FIFO_TRIG_ENABLE;
            naibrd_AD_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modIndex + 1,
               p_syncInfo->channel[modIndex], (nai_ad_fifo_trig_t)(trigCtrl));
            break;

         case SYNCOPS_MOD_TYPE_DA:
            naibrd_DA_GetFIFOTrigCtrl(p_syncInfo->cardIndex, modIndex + 1,
               p_syncInfo->channel[modIndex], (nai_da_fifo_trig_t*)(&trigCtrl));
            if (trigEnable)
               trigCtrl |= (uint32_t)NAI_DA_GEN5_FIFO_TRIG_ENABLE;
            else
               trigCtrl &= (uint32_t)~NAI_DA_GEN5_FIFO_TRIG_ENABLE;
            naibrd_DA_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modIndex + 1,
               p_syncInfo->channel[modIndex], (nai_da_fifo_trig_t)(trigCtrl));
            break;
      }
   }
}

The SoftwareTrigger() helper calls the appropriate API for the master’s module type:

static nai_status_t SoftwareTrigger(naiapp_syncInfo_t syncInfo, int32_t modNum)
{
   switch(syncInfo.moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = naibrd_AD_SoftwareTrigger(syncInfo.cardIndex, modNum);
         break;

      case SYNCOPS_MOD_TYPE_DA:
         status = naibrd_DA_SoftwareTrigger(syncInfo.cardIndex, modNum);
         break;
   }
}

In your own code, the trigger sequence is:

  1. Enable the FIFO trigger on every participating module (set the TRIG_ENABLE bit).

  2. Issue naibrd_AD_SoftwareTrigger() or naibrd_DA_SoftwareTrigger() on the master module only. The hardware propagates the trigger to all slaves automatically.

If no trigger master has been configured (triggerMasterModNum is 0), the sample prints a message and waits for an external trigger signal.

Important

Common Errors

  • FIFOs do not start — verify that trigger sync has been configured (CF command) and that the trigger enable bit was set. The TRIG command enables triggers automatically, but if you call the APIs directly, you must set the enable bit yourself.

  • Only the master module runs — slave modules were not configured with a matching triggerMasterModNum. Re-run CF for each slave and specify the correct master module.

  • No trigger master configured — if triggerMasterModNum is 0, no software trigger is issued. Configure at least one module as MASTER using the CF command.

Stop FIFO (STOP Command)

The STOP command disables FIFO triggers on all modules, halting both acquisition and output. It calls the same SetFifoTriggers() helper used by the TRIG command, but with trigEnable set to FALSE.

static nai_status_t SyncBasicOps_stopFifo(int32_t paramCount, int32_t* p_params)
{
   return paramCount == SYNC_PARAM_COUNT ? SetFifoTriggers((naiapp_syncInfo_t*)p_params, FALSE) : NAI_ERROR_INVALID_VALUE;
}

To stop FIFO I/O in your own application, read each module’s FIFO trigger control register, clear the TRIG_ENABLE bit, and write it back. This is the same read-modify-write pattern shown in the SetFifoTriggers() function above.

Important

Common Errors

  • Data still being collected after STOP — if FIFOs are configured in continuous mode and you do not clear the enable bit on every module, some modules may continue running. Ensure SetFifoTriggers() (or equivalent) covers all modules.

Collect AD FIFO Data (COLLECT Command)

The COLLECT command reads the captured AD FIFO data from all sync-enabled AD modules and writes it to a tab-delimited text file (sync_data.txt). This is where you retrieve the synchronized acquisition results.

nai_status_t SyncBasicOps_collectData(int32_t paramCount, int32_t* p_params)
{
   naiapp_syncInfo_t *p_syncInfo = (naiapp_syncInfo_t*)p_params;
   FILE *dataFile = fopen(DATA_FILE, "w");

   /* Loop through all modules and save FIFO data for sync-enabled AD modules. */
   for (modNum = 1; modNum <= p_syncInfo->moduleCount; modNum++)
   {
      if (SYNCOPS_MOD_TYPE_AD == p_syncInfo->moduleType[modNum-1])
      {
         status = GetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_TRIGGER, &mode, &masterModNum);
         if (NAIBRD_MODULE_SYNC_MODE_DISABLED != mode)
         {
            /* Disable the FIFO to stop collection before reading. */
            status = naibrd_AD_GetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum,
               p_syncInfo->channel[modNum-1], &trigCtrl);
            trigCtrl &= ~NAI_AD_GEN5_FIFO_TRIG_ENABLE;
            status = naibrd_AD_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum,
               p_syncInfo->channel[modNum-1], trigCtrl);

            /* Read the AD FIFO data. */
            status = ReadFIFO32(*p_syncInfo, modNum, &(read[modNum-1]));
         }
      }
   }

   /* Write all collected data to file. */
   for(dataIndex = 0; dataIndex < SYNCOPS_NUM_FIFO_SAMPLES; dataIndex++)
   {
      /* ... format and write each row ... */
   }
   fclose(dataFile);
}

The ReadFIFO32() helper calls naibrd_AD_ReadFIFO32() to bulk-read all samples from the FIFO into the global fifoData[] array:

static nai_status_t ReadFIFO32(naiapp_syncInfo_t syncInfo, int32_t modNum, uint32_t *p_outRead)
{
   switch(syncInfo.moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = naibrd_AD_ReadFIFO32(syncInfo.cardIndex, modNum, syncInfo.channel[modNum-1],
            SYNCOPS_NUM_FIFO_SAMPLES, fifoData[modNum-1], p_outRead);
         break;
   }
}

Key steps in your own code:

  1. Disable the FIFO trigger before reading. This prevents new samples from being written into the FIFO while you read.

  2. Read the FIFO with naibrd_AD_ReadFIFO32(). The p_outRead output parameter tells you how many samples were actually read.

  3. Process or store the data as needed. The sample writes it to sync_data.txt.

The output file format has one column per module and one row per sample index, making it easy to import into a spreadsheet or analysis tool to verify that the AD channels captured time-aligned data.

Important

Common Errors

  • File cannot be opened — the sample writes to sync_data.txt in the current working directory. Ensure the application has write permissions.

  • FIFO count is zero — no data was captured. Verify that the TRIG command was issued and that the AD modules are configured with trigger sync enabled.

  • Fewer samples than expected — if p_outRead is less than SYNCOPS_NUM_FIFO_SAMPLES, the FIFO did not fill completely before collection. Check that the FIFO size was set correctly and that sufficient time elapsed between trigger and collect.

  • Data misalignment between modules — if the timing of samples from different AD modules does not match, verify that both clock sync and trigger sync are configured with the same master module.

Typical Workflow

A typical synchronized acquisition and output session follows this sequence:

  1. CS — Configure clock sync. Set one module as MASTER, all others as SLAVE (INTERNAL) pointing to the master.

  2. CF — Configure FIFO trigger sync. Set one module as MASTER (typically the same one), all others as SLAVE (INTERNAL) pointing to the master. Select the desired channel for each module.

  3. CLF — Clear all FIFOs to remove any stale data.

  4. LOAD — Load DA FIFO data on all sync-enabled DA modules.

  5. TRIG — Fire the software trigger on the master. All FIFOs start simultaneously.

  6. COLLECT — After the FIFOs fill, read the AD FIFO data and save to file.

  7. STOP — Disable all FIFO triggers.

You can repeat steps 3-7 for additional acquisition cycles without reconfiguring the sync relationships.

Troubleshooting Reference

Note
This section summarizes errors covered in the preceding sections. Consult your module’s manual for hardware-specific diagnostics.
Error / Symptom Possible Causes Suggested Resolution

NAI_ERROR_NOT_SUPPORTED

Module does not support synchronization or the specific FIFO control API.

Verify the module is one of the supported types (AD1-AD6, ADE-ADG, DA1-DA5, CME-CMG). For naibrd_DA_SetFIFOCtrl(), this error is expected on some DA variants and can be safely ignored.

NAI_ERROR_INVALID_MODULE

The module slot does not contain a recognized module type.

Check the module ID and ensure the slot is populated with a sync-capable module.

No board found / Connection timeout

Board not powered, incorrect interface settings, firewall blocking Ethernet.

Verify physical connection. Check configuration file settings. Confirm network/bus configuration.

FIFOs do not start after TRIG

Trigger enable bit not set; no trigger master configured; slave not pointing to correct master.

Verify that CF was run for all modules. Confirm the status display shows the correct master/slave relationships. Ensure at least one module is MASTER.

Only master module runs

Slave modules not configured or referencing wrong master.

Re-run CF for each slave module and specify the correct master module number.

AD FIFO count is zero after trigger

Trigger sync not configured; clock sync not configured; FIFO not cleared before trigger.

Run both CS and CF before triggering. Clear FIFOs with CLF before each acquisition cycle.

Data misalignment between modules

Modules using different clocks; trigger sync configured but clock sync is not (or vice versa).

Configure both clock sync (CS) and trigger sync (CF) with the same master module for all participants.

Stale data in collected output

FIFO not cleared before starting a new acquisition cycle.

Always issue CLF before TRIG to clear old data from all FIFOs.

DA outputs nothing after trigger

DA FIFO not loaded with data; FIFO trigger not enabled; sync mode disabled.

Run LOAD before TRIG. Verify CF was configured for the DA module with a non-disabled mode.

sync_data.txt cannot be opened

Application lacks write permissions in the current working directory.

Run the application from a directory where you have write access.

Fewer AD samples than expected

FIFO did not fill completely; collection happened too soon after trigger.

Ensure sufficient time for the FIFO to fill (based on sample rate and FIFO size) before running COLLECT.

Full Source

Full Source — Sync_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"
#include "nai_ad_utils.h"

/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_ad.h"
#include "functions/naibrd_da.h"
#include "advanced/nai_ether_adv.h"
#include "boards/naibrd_gen5.h"

static const int8_t *SAMPLE_PGM_NAME = (const int8_t *)"Synchronization Basic Operation Program";
static const int8_t *CONFIG_FILE = (const int8_t *)"default_Sync_BasicOps.txt";

static const char *DATA_FILE = (const char*)"sync_data.txt";

/* Module Type definitions. The Module type is the 16 msb of the module ID. So module ID's like AD1, AD2, AD3, etc are
    all AD module types. The module ID of ANY AD module can give us the module type by masking out the
    lower 16 bits and retaining the upper 16 bits. This is true for all NAI modules (AD, DA, CM, etc).
*/
#define SYNCOPS_MOD_TYPE_MASK  0xFFFF0000u
typedef uint32_t syncops_module_type_t;
#define SYNCOPS_MOD_TYPE_UNKNOWN (syncops_module_type_t)0u;
#define SYNCOPS_MOD_TYPE_AD      (syncops_module_type_t)(NAI_MODULE_ID_AD1 & SYNCOPS_MOD_TYPE_MASK)
#define SYNCOPS_MOD_TYPE_DA      (syncops_module_type_t)(NAI_MODULE_ID_DA1 & SYNCOPS_MOD_TYPE_MASK)

#define SYNCOPS_FIFO_TRIG_SOFT(t)           ((uint32_t)(t == SYNCOPS_MOD_TYPE_AD ? NAIBRD_AD_FIFO_TRIG_SOFT : NAIBRD_DA_GEN5_FIFO_TRIG_SOFT))
#define SYNCOPS_FIFO_TRIG_POS_EDGE(t)       ((uint32_t)(t == SYNCOPS_MOD_TYPE_AD ? NAIBRD_AD_FIFO_TRIG_POS_EDGE : NAIBRD_DA_GEN5_FIFO_TRIG_PSLOPE))
#define SYNCOPS_FIFO_TRIG_NEG_EDGE(t)       ((uint32_t)(t == SYNCOPS_MOD_TYPE_AD ? NAIBRD_AD_FIFO_TRIG_NEG_EDGE : NAIBRD_DA_GEN5_FIFO_TRIG_NSLOPE))
#define SYNCOPS_FIFO_TRIG_EITHER_EDGE(t)    ((uint32_t)(t == SYNCOPS_MOD_TYPE_AD ? NAIBRD_AD_FIFO_TRIG_EITHER_EDGE : NAIBRD_DA_GEN5_FIFO_TRIG_EITHER_SLOPE))
#define SYNCOPS_FIFO_TRIG_STOP(t)           ((uint32_t)(t == SYNCOPS_MOD_TYPE_AD ? NAIBRD_AD_FIFO_TRIG_STOP : NAIBRD_DA_GEN5_FIFO_TRIG_STOP))
#define SYNCOPS_FIFO_TRIG_ENABLE(t)         ((uint32_t)(t == SYNCOPS_MOD_TYPE_AD ? NAIBRD_AD_FIFO_TRIG_ENABLE : NAIBRD_DA_GEN5_FIFO_TRIG_ENABLE))
#define SYNCOPS_FIFO_TRIG_CONTINUOUS(t)     ((uint32_t)(t == SYNCOPS_MOD_TYPE_AD ? NAIBRD_AD_FIFO_TRIG_CONTINUOUS : NAIBRD_DA_GEN5_FIFO_TRIG_CONTINUOUS))

/* Structure to hold sync info. */
typedef struct naiapp_syncInfo
{
   int32_t cardIndex;
   int32_t moduleCount;
   uint32_t modId[NAI_MAX_MODULES];
   syncops_module_type_t moduleType[NAI_MAX_MODULES];
   int32_t triggerMasterModNum;
   int32_t channel[NAI_MAX_MODULES];  /*1 channel per module. */
} naiapp_syncInfo_t;

#define SYNC_PARAM_COUNT 6

/* Function prototypes */
static bool_t SyncBasicOps_run(int32_t cardIndex, int32_t moduleCount);
static void SyncBasicOps_displayConfigurations(int32_t paramCount, naiapp_syncInfo_t *p_syncInfo);

/* AD Basic Ops Command Functions */
static nai_status_t SyncBasicOps_configClockSync(int32_t paramCount, int32_t* p_params);
static nai_status_t SyncBasicOps_configFifo(int32_t paramCount, int32_t* p_params);
static nai_status_t SyncBasicOps_clearFifo(int32_t paramCount, int32_t* p_params);
static nai_status_t SyncBasicOps_triggerMaster(int32_t paramCount, int32_t* p_params);
static nai_status_t SyncBasicOps_stopFifo(int32_t paramCount, int32_t* p_params);
static nai_status_t SyncBasicOps_collectData(int32_t paramCount, int32_t* p_params);
static nai_status_t SyncBasicOps_loadData(int32_t paramCount, int32_t* p_params);

/* Application Functions */
static bool_t SyncSupported(uint32_t modID);
static const char* SyncModeString(naibrd_module_sync_mode_type_t mode);
static bool_t GetMasterModule(naiapp_syncInfo_t *p_syncInfo, int32_t *p_masterModNum);
static syncops_module_type_t GetModuleType(uint32_t modID);
static nai_status_t ConfigFifoSync(naiapp_syncInfo_t *p_syncInfo, int32_t modNum, naibrd_module_sync_mode_type_t mode, uint32_t trigCtrl);
static nai_status_t SetFifoTriggers(naiapp_syncInfo_t *p_syncInfo, bool_t trigEnable);
static nai_status_t GetModuleSyncMode(naiapp_syncInfo_t syncInfo, int32_t modNum, naibrd_module_sync_config_type_t config,
   naibrd_module_sync_mode_type_t *p_mode, int32_t *p_masterModNum);
static nai_status_t SetModuleSyncMode(naiapp_syncInfo_t syncInfo, int32_t modNum, naibrd_module_sync_config_type_t config,
   naibrd_module_sync_mode_type_t mode, int32_t masterModNum);
static nai_status_t ReadFIFO32(naiapp_syncInfo_t syncInfo, int32_t modNum, uint32_t *p_outRead);
static nai_status_t SoftwareTrigger(naiapp_syncInfo_t syncInfo, int32_t modNum);
static nai_status_t GetFIFOSize(naiapp_syncInfo_t syncInfo, int32_t modNum, int32_t channel, uint32_t *p_fifoSize);
static nai_status_t GetFIFOCount(naiapp_syncInfo_t syncInfo, int32_t modNum, int32_t channel, uint32_t *p_fifoCount);
static nai_status_t GetModuleRate(naiapp_syncInfo_t syncInfo, int32_t modNum, uint32_t *p_rate);

#define DEFAULT_CHANNEL 1
#define SYNCOPS_NUM_FIFO_SAMPLES  100u

static float32_t fifoData[NAI_MAX_MODULES][SYNCOPS_NUM_FIFO_SAMPLES];

/****** Command Table *******/
/* Invariant: enumeration of cmd table starts from 0 and increments by 1 */
enum sync_basicOps_commands
{
   SYNC_BASICOPS_CMD_CONFIG_CLOCK_SYNC,         /* Configure Clock Sync */
   SYNC_BASICOPS_CMD_CONFIG_FIFO,               /* Configure FIFO */
   SYNC_BASICOPS_CMD_CLEAR_FIFO,                /* Clear FIFO */
   SYNC_BASICOPS_CMD_LOAD_FIFO_DATA,            /* Load the DA FIFO's with data. */
   SYNC_BASICOPS_CMD_SEND_FIFO_TRIGGER,         /* Trigger to start fifo i/o. */
   SYNC_BASICOPS_CMD_STOP_FIFO,                 /* Stop fifo i/o. */
   SYNC_BASICOPS_CMD_COLLECT_FIFO_DATA,         /* Read the AD FIFO's and store the data to a file. */
   SYNC_BASICOPS_CMD_COUNT
};

naiapp_cmdtbl_params_t Sync_BasicOpsCmds[] =
{
   {"CS",      "Configure Clock Sync",                                     SYNC_BASICOPS_CMD_CONFIG_CLOCK_SYNC,       SyncBasicOps_configClockSync  },
   {"CF",      "Configure FIFO",                                           SYNC_BASICOPS_CMD_CONFIG_FIFO,             SyncBasicOps_configFifo       },
   {"CLF",     "Clear FIFO contents",                                      SYNC_BASICOPS_CMD_CLEAR_FIFO,              SyncBasicOps_clearFifo        },
   {"LOAD",    "Load the DA FIFO's with data.",                            SYNC_BASICOPS_CMD_LOAD_FIFO_DATA,          SyncBasicOps_loadData         },
   {"TRIG",    "Trigger Master to start FIFOs on the Master and Slave.",   SYNC_BASICOPS_CMD_SEND_FIFO_TRIGGER,       SyncBasicOps_triggerMaster    },
   {"STOP",    "Stop fifo i/o",                                            SYNC_BASICOPS_CMD_STOP_FIFO,               SyncBasicOps_stopFifo         },
   {"COLLECT", "Read the AD FIFO's and store the data to a file. ",        SYNC_BASICOPS_CMD_COLLECT_FIFO_DATA,       SyncBasicOps_collectData      }
};

/*****************************************************************************/
/**
 * <summary>
 * The purpose of the AD_BasicOps is to illustrate the methods to call in the
 * naibrd library to perform basic operations with the AD modules for
 * configuration setup and reading the channels.
 *
 * The following system configuration routines from the nai_sys_cfg.c file are
 * called to assist with the configuration setup for this program prior to
 * calling the naibrd AD routines.
 * - ConfigDevice
 * - DisplayDeviceCfg
 * - GetBoardSNModCfg
 * - CheckModule
 * </summary>
 */
 /*****************************************************************************/
#if defined (__VXWORKS__)
int32_t Sync_BasicOps(void)
#else
int32_t main(void)
#endif
{
   bool_t bQuit = FALSE;
   int32_t cardIndex = -1;
   int32_t moduleCount;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
   {
      while (!bQuit)
      {
         naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         naibrd_GetModuleCount(cardIndex, &moduleCount);
         bQuit = SyncBasicOps_run(cardIndex, moduleCount);
      }

      printf("Type the Enter key to exit the program: ");
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   }

   naiapp_access_CloseAllOpenCards();

   return 0;
}
/*****************************************************************************/
/**
 * <summary>
 * SyncBasicOps_run illustrates the channel configuration and prepares the menu
 * which will handle user command requests. Returns TRUE if the user enters
 * the Quit Command at any point within its scope.
 * </summary>
 */
 /*****************************************************************************/
static bool_t SyncBasicOps_run(int32_t cardIndex, int32_t moduleCount)
{
   bool_t bQuit = FALSE;
   bool_t bCmdFound = FALSE;
   int32_t cmd;
   naiapp_syncInfo_t syncInfo;
   int32_t moduleIndex = 0;
   naibrd_module_sync_mode_type_t syncMode;
   int32_t triggerMasterModNum = 0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;
   int32_t channel = 0;

   syncInfo.cardIndex = cardIndex;
   syncInfo.moduleCount = moduleCount;
   syncInfo.triggerMasterModNum = 0;
   for(moduleIndex = 0; moduleIndex < moduleCount; moduleIndex++)
   {
      syncInfo.channel[moduleIndex] = DEFAULT_CHANNEL;
      syncInfo.modId[moduleIndex] = naibrd_GetModuleID(cardIndex, moduleIndex + 1);
      syncInfo.moduleType[moduleIndex] = GetModuleType(syncInfo.modId[moduleIndex]);

      if (FALSE != SyncSupported(syncInfo.modId[moduleIndex]))
      {
         GetModuleSyncMode(syncInfo, moduleIndex + 1, NAIBRD_SYNC_CONFIG_TRIGGER, &syncMode, &triggerMasterModNum);
         if (NAIBRD_MODULE_SYNC_MODE_MASTER == syncMode)
         {
            syncInfo.triggerMasterModNum = triggerMasterModNum;
         }

         switch(syncInfo.moduleType[moduleIndex])
         {
            case SYNCOPS_MOD_TYPE_AD:
               for (channel = 1; channel <= naibrd_AD_GetChannelCount(syncInfo.modId[moduleIndex]); channel++)
               {
                  check_status(naibrd_AD_SetFIFOSize(syncInfo.cardIndex, moduleIndex + 1, channel, SYNCOPS_NUM_FIFO_SAMPLES));
               }
            break;

            case SYNCOPS_MOD_TYPE_DA:
               for (channel = 1; channel <= naibrd_DA_GetChannelCount(syncInfo.modId[moduleIndex]); channel++)
               {
                  check_status(naibrd_DA_SetFIFOSize(syncInfo.cardIndex, moduleIndex + 1, channel, SYNCOPS_NUM_FIFO_SAMPLES));
               }
            break;

            default:
               printf("SyncBasicOps_run-> ERROR! Unsupported Module Type %u\n", syncInfo.moduleType[moduleIndex]);
               break;
         }
      }
   }

   do
   {
      naiapp_utils_LoadParamMenuCommands(SYNC_BASICOPS_CMD_COUNT, Sync_BasicOpsCmds);
      SyncBasicOps_displayConfigurations(SYNC_PARAM_COUNT, &syncInfo);
      naiapp_display_ParamMenuCommands((int8_t*)SAMPLE_PGM_NAME);
      printf("\n\nPlease enter a command or 'q' to quit:");
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (!bQuit)
      {
         if (inputResponseCnt > 0)
         {
            bCmdFound = naiapp_utils_GetParamMenuCmdNum(inputResponseCnt, inputBuffer, &cmd);
            if (bCmdFound)
            {
               Sync_BasicOpsCmds[cmd].func(SYNC_PARAM_COUNT, (int32_t*)&syncInfo);
            }
            else
            {
               printf("Invalid command entered\n");
            }
         }
      }

   } while (!bQuit);
   return bQuit;
}
/*****************************************************************************/
/**
 * <summary>
 * ADBasicOps_displayConfigurations illustrates the methods to call in the naibrd library
 * to retrieve the basic operation configuration states and status states
 * as well as the current voltage reading for all channels.
 * </summary>
 */
 /*****************************************************************************/
static void SyncBasicOps_displayConfigurations(int32_t paramCount, naiapp_syncInfo_t* p_syncInfo)
{
   int32_t modNum = 0;
   naibrd_module_sync_mode_type_t clockMode = NAIBRD_MODULE_SYNC_MODE_DISABLED;
   int32_t clockMasterModNum = 0;
   naibrd_module_sync_mode_type_t triggerMode = NAIBRD_MODULE_SYNC_MODE_DISABLED;
   int32_t triggerMasterModNum = 0;
   uint32_t numSamplesPerTrigger = 0u;
   uint32_t fifoCount = 0;
   uint32_t rate = 0;
   char szModID[] = "/0/0/0/0";

   if (SYNC_PARAM_COUNT == paramCount)
   {
      printf("\n\n\n");
      printf("------Module Info------    --------SyncClockConfig---------    --------SyncTriggerConfig-------    --------------FIFO Setup--------------\n");
      printf(" ModNum  ID  SyncSupport   Mode                MasterModNum    Mode                MasterModNum    Rate   Channel   NumSamples  FifoCount\n");
      printf("-----------------------------------------------------------------------------------------------------------------------------------------\n");

      for (modNum = 1; modNum <= p_syncInfo->moduleCount; modNum++)
      {
         naiapp_utils_ConvertModIdToAscii(p_syncInfo->modId[modNum-1], szModID);

         if (FALSE != SyncSupported(p_syncInfo->modId[modNum-1]))
         {
            GetModuleRate(*p_syncInfo, modNum, &rate);
            GetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK, &clockMode, &clockMasterModNum);
            GetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_TRIGGER, &triggerMode, &triggerMasterModNum);
            GetFIFOSize(*p_syncInfo, modNum, p_syncInfo->channel[modNum-1], &numSamplesPerTrigger);
            GetFIFOCount(*p_syncInfo, modNum, p_syncInfo->channel[modNum-1], &fifoCount);

            printf("   %d     %s    YES       %-25s %d         %-25s %d          %-9d %-2d      %3u        %u\r\n", modNum, szModID,
               SyncModeString(clockMode), clockMasterModNum, SyncModeString(triggerMode), triggerMasterModNum, rate, p_syncInfo->channel[modNum-1],
                  numSamplesPerTrigger, fifoCount);
         }
         else
         {
            printf("   %d     %s    NO        ---                      ---        ---                      ---        ---       ---       ---      ---\r\n",
               modNum, szModID);
         }
      }
   }
}

/*****************************************************************************/
/**
 * <summary>
 * ADBasicOps_setRangePolarity handles the user request to set the configuration states
 * of Range and Polarity for the selected channel.
 * </summary>
 */
 /*****************************************************************************/
nai_status_t SyncBasicOps_configClockSync(int32_t paramCount, int32_t* p_params)
{
   nai_status_t status = NAI_ERROR_UNKNOWN;
   naiapp_syncInfo_t* p_syncInfo = (naiapp_syncInfo_t*)p_params;
   int32_t modNum = 0;
   int32_t masterModNum = 0;
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;
   int32_t modeSelect = 0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (SYNC_PARAM_COUNT == paramCount)
   {
      while (bContinue)
      {
         printf("Select module to configure (1-%d): ", p_syncInfo->moduleCount);
         bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
         if (!bQuit)
         {
            if (inputResponseCnt >= 0)
            {
               modNum = (int32_t)atol((const char*)inputBuffer);
            }

            if ((modNum <= 0) || (modNum > p_syncInfo->moduleCount))
            {
               printf("ERROR: Invalid module value.\r\n\r\n");
            }
            else
            {
               bContinue = FALSE;
            }
         }
         else
         {
            bContinue = FALSE;
         }
      }

      if (!bQuit)
      {
         bContinue = TRUE;

         while(bContinue)
         {
            printf("\n\nPlease select Clock Sync Mode for this module:\n");
            printf(" 0) DISABLED: This module uses its internal clock and does not sync with other modules.\n");
            printf(" 1) MASTER: This module supplies the clock to other slave modules.\n");
            printf(" 2) SLAVE- USER CLOCK: This module syncs with a user supplied clock and supplies it to other slave modules.\n");
            printf(" 3) SLAVE- INTERNAL CLOCK: This module receives the clock from a MASTER/USER CLOCK module.\n");
            printf(" 4) SLAVE- EXTERNAL BOARD CLOCK: This module receives the clock that is supplied by an off-board master.\n");
            printf("\n\nPlease enter your selection: ");

            bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
            if (!bQuit)
            {
               if (inputResponseCnt > 0)
               {
                  modeSelect = (int32_t)atol((const char*)inputBuffer);

                  bContinue = FALSE;
                  switch (modeSelect)
                  {
                     case 0:
                        masterModNum = 0; /* 0 disables. */
                        status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK, NAIBRD_MODULE_SYNC_MODE_DISABLED, masterModNum);
                     break;

                     case 1:
                        masterModNum = modNum; /* Master gets the clock from itself. */
                        status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK, NAIBRD_MODULE_SYNC_MODE_MASTER, masterModNum);
                     break;

                     case 2:
                        masterModNum = 0; /* 0 disables. */
                        status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK, NAIBRD_MODULE_SYNC_MODE_SLAVE_USER_CLOCK, masterModNum);
                     break;

                     case 3:
                        bQuit = GetMasterModule(p_syncInfo, &masterModNum);
                        status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK, NAIBRD_MODULE_SYNC_MODE_SLAVE_INTERNAL, masterModNum);
                     break;

                     case 4:
                        bQuit = GetMasterModule(p_syncInfo, &masterModNum);
                        status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_CLOCK, NAIBRD_MODULE_SYNC_MODE_SLAVE_BOARD_CLOCK, masterModNum);
                     break;

                     default:
                         printf("ERROR: Invalid module value.\r\n\r\n");
                         bContinue = TRUE;
                     break;
                  }
               }
               else
               {
                  printf("ERROR: Invalid module value.\r\n\r\n");
                  bContinue = TRUE;
               }
            }
            else
            {
               bContinue = FALSE;
            }
         }
      }
   }

   return status;
}

nai_status_t SyncBasicOps_configFifo(int32_t paramCount, int32_t* p_params)
{
   nai_status_t status = NAI_ERROR_UNKNOWN;
   naiapp_syncInfo_t* p_syncInfo = (naiapp_syncInfo_t*)p_params;
   int32_t modNum = 0;
   bool_t bContinue = TRUE;
   bool_t bQuit = FALSE;
   int32_t modeSelect = 0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (SYNC_PARAM_COUNT == paramCount)
   {
      while (bContinue)
      {
         printf("Select module to configure (1-%d): ", p_syncInfo->moduleCount);
         bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
         if (!bQuit)
         {
            if (inputResponseCnt >= 0)
            {
               modNum = (int32_t)atol((const char*)inputBuffer);
            }

            if ((modNum <= 0) || (modNum > p_syncInfo->moduleCount))
            {
               printf("ERROR: Invalid module value.\r\n\r\n");
            }
            else
            {
               bContinue = FALSE;
            }
         }
         else
         {
            bContinue = FALSE;
         }
      }

      if (!bQuit)
      {
         bContinue = TRUE;

         while(bContinue)
         {
            printf("\n\nPlease select FIFO Trigger Sync Mode for this module:\n");
            printf(" 0) DISABLED: This module uses its internal FIFO Trigger and does not sync with other modules.\n");
            printf(" 1) MASTER: This module supplies the FIFO Trigger to other slave modules.\n");
            printf(" 2) SLAVE- USER TRIGGER: This module's FIFO is triggered externally and triggers the FIFOs on slave modules.\n");
            printf(" 3) SLAVE- INTERNAL TRIGGER: This module's FIFO is triggered from a MASTER/USER TRIGGER module.\n");
            /*printf(" 4) SLAVE- EXTERNAL BOARD TRIGGER: This module's FIFO is triggered by an off-board master.\n");*/
            printf("\n\nPlease enter your selection: ");

            bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
            if (!bQuit)
            {
               if (inputResponseCnt > 0)
               {
                  modeSelect = (int32_t)atol((const char*)inputBuffer);

                  bContinue = FALSE;
                  switch (modeSelect)
                  {
                     case 0:
                        p_syncInfo->triggerMasterModNum = 0; /* 0 disables. */
                        status = ConfigFifoSync(p_syncInfo, modNum, NAIBRD_MODULE_SYNC_MODE_DISABLED, (uint32_t)NAI_AD_GEN5_FIFO_TRIG_STOP);
                     break;

                     case 1:
                        p_syncInfo->triggerMasterModNum = modNum; /* Master gets the clock from itself. */
                        status = ConfigFifoSync(p_syncInfo, modNum, NAIBRD_MODULE_SYNC_MODE_MASTER,
                           (uint32_t)(NAI_AD_GEN5_FIFO_TRIG_SOFT | NAI_AD_GEN5_FIFO_TRIG_CONTINUOUS));
                     break;

                     case 2:
                        p_syncInfo->triggerMasterModNum = 0; /* 0 disables. */
                        status = ConfigFifoSync(p_syncInfo, modNum, NAIBRD_MODULE_SYNC_MODE_SLAVE_USER_CLOCK,
                           (uint32_t)(NAI_AD_GEN5_FIFO_TRIG_POS_EDGE | NAI_AD_GEN5_FIFO_TRIG_CONTINUOUS));
                     break;

                     case 3:
                        bQuit = GetMasterModule(p_syncInfo, &(p_syncInfo->triggerMasterModNum));
                        status = ConfigFifoSync(p_syncInfo, modNum, NAIBRD_MODULE_SYNC_MODE_SLAVE_INTERNAL,
                           (uint32_t)(NAI_AD_GEN5_FIFO_TRIG_POS_EDGE | NAI_AD_GEN5_FIFO_TRIG_CONTINUOUS));
                     break;

                     /*
                     case 4:
                        bQuit = GetMasterModule(p_syncInfo, &(p_syncInfo->triggerMasterModNum));
                        status = ConfigFifoSync(p_syncInfo, modNum, NAIBRD_MODULE_SYNC_MODE_SLAVE_BOARD_CLOCK,
                           (uint32_t)(NAI_AD_GEN5_FIFO_TRIG_POS_EDGE | NAI_AD_GEN5_FIFO_TRIG_CONTINUOUS));
                     break;
                     */
                     default:
                         printf("ERROR: Invalid module value.\r\n\r\n");
                         bContinue = TRUE;
                     break;
                  }

                  naiapp_query_ChannelNumber(p_syncInfo->moduleCount, DEFAULT_CHANNEL, &(p_syncInfo->channel[modNum-1]));

               }
               else
               {
                  printf("ERROR: Invalid module value.\n\n");
                  bContinue = TRUE;
               }
            }
            else
            {
               bContinue = FALSE;
            }
         }
      }
   }

   return status;
}

static nai_status_t SyncBasicOps_clearFifo(int32_t paramCount, int32_t* p_params)
{
   naiapp_syncInfo_t *p_syncInfo = (naiapp_syncInfo_t*)p_params;
   nai_status_t status = NAI_ERROR_UNKNOWN;
   bool_t bQuit = FALSE;
   int32_t startMod = 0;
   int32_t endMod = 0;
   int32_t modNum = 0;
   bool_t bContinue = TRUE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (SYNC_PARAM_COUNT == paramCount)
   {
      while(bContinue)
      {
         printf("Please enter the module number of the FIFO to clear, or 'A' to clear all FIFOs [1-%d,A]:", p_syncInfo->moduleCount);
         bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
         if (!bQuit)
         {
            if (inputResponseCnt > 0)
            {
               if (inputBuffer[0] == 'A' || inputBuffer[0] == 'a')
               {
                  startMod = 1;
                  endMod = p_syncInfo->moduleCount;
                  bContinue = FALSE;
               }
               else
               {
                  startMod = endMod = (int32_t)atol((const char*)inputBuffer);
                  if ((endMod <= 0) || (endMod > p_syncInfo->moduleCount)
                     || !SyncSupported(naibrd_GetModuleID(p_syncInfo->cardIndex, endMod)))
                  {
                     printf("ERROR: Invalid module value.\r\n\r\n");
                  }
                  else
                  {
                     bContinue = FALSE;
                  }
               }
            }
            else
            {
               printf("ERROR: Invalid module value.\r\n\r\n");
            }
         }
      }

      if (!bQuit)
      {
         for(modNum = startMod; modNum <= endMod; modNum++)
         {
            switch(p_syncInfo->moduleType[modNum-1])
            {
               case SYNCOPS_MOD_TYPE_AD:
                  status = check_status(naibrd_AD_ClearFIFO(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1]));
                  break;

               case SYNCOPS_MOD_TYPE_DA:
                  status = check_status(naibrd_DA_ClearFIFO(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1]));
                  break;

               default:
                  break;
            }
         }
      }
   }

   return status;
}

nai_status_t SyncBasicOps_triggerMaster(int32_t paramCount, int32_t* p_params)
{
   naiapp_syncInfo_t *p_syncInfo = (naiapp_syncInfo_t*)p_params;
   nai_status_t status = NAI_ERROR_UNKNOWN;
   uint32_t samplesToCollect = 0u;

   if (SYNC_PARAM_COUNT == paramCount)
   {
      /* Enable the fifo's to collect data. Once enabled, fifo's will continue to collect until they reach FIFOSize. If data is
            removed from the fifo while it's enabled, the fifo will begin collecting again until it reaches FIFOSize. The fifo needs
            to be disabled after the collection in order to access the data without collecting more. */

      SetFifoTriggers(p_syncInfo, TRUE);

      if (0 != p_syncInfo->triggerMasterModNum)
      {
         printf("Triggering FIFO on MASTER module %d (all slaves will trigger as well)...", p_syncInfo->triggerMasterModNum);
         status = SoftwareTrigger(*p_syncInfo, p_syncInfo->triggerMasterModNum);
         printf("Trigger Complete. FIFO is collecting data.\n");
         printf("Waiting for FIFO I/O to complete...");
         GetFIFOSize(*p_syncInfo, p_syncInfo->triggerMasterModNum, p_syncInfo->channel[p_syncInfo->triggerMasterModNum - 1], &samplesToCollect);
         /* Keep checking the fifo count of the master until it is equal to FifoSize(numSamplesPerTrigger). All slave fifos will collect
               data at the same rate, so only check one module (in this case the master) to see when data collection is complete. */
      }
      else
      {
         printf("Waiting for external trigger..\n");
      }
   }

   return status;
}

static nai_status_t SyncBasicOps_stopFifo(int32_t paramCount, int32_t* p_params)
{
   return paramCount == SYNC_PARAM_COUNT ? SetFifoTriggers((naiapp_syncInfo_t*)p_params, FALSE) : NAI_ERROR_INVALID_VALUE;
}

static nai_status_t SyncBasicOps_loadData(int32_t paramCount, int32_t* p_params)
{
   naiapp_syncInfo_t *p_syncInfo = (naiapp_syncInfo_t*)p_params;
   int32_t modNum = 0;
   naibrd_module_sync_mode_type_t mode;
   int32_t masterModNum = 0;
   nai_status_t status = NAI_ERROR_UNKNOWN;
   int32_t dataIndex = 0;
   float32_t data[] = {0.0, 5.0};
   uint32_t written = 0;
   nai_da_fifo_trig_t trigCtrl = (nai_da_fifo_trig_t)0;

   if (SYNC_PARAM_COUNT == paramCount)
   {
      for (modNum = 1; modNum <= p_syncInfo->moduleCount; modNum++)
      {
         if (SYNCOPS_MOD_TYPE_DA == p_syncInfo->moduleType[modNum-1])
         {
            status = GetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_TRIGGER, &mode, &masterModNum);
            if (NAIBRD_MODULE_SYNC_MODE_DISABLED != mode)
            {
               /* Disable the fifo to stop it from sending data. */
               status = check_status(naibrd_DA_GetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1], &trigCtrl));
               trigCtrl &= ~NAI_DA_GEN5_FIFO_TRIG_ENABLE;
               status = check_status(naibrd_DA_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1],trigCtrl));

               /* Load the fifo with data. */
               for (dataIndex = 0; (dataIndex < SYNCOPS_NUM_FIFO_SAMPLES) && (status == NAI_SUCCESS); dataIndex++)
               {
                  status = check_status(naibrd_DA_SetFIFO32(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1], 1, &(data[dataIndex%(sizeof(data) / sizeof(data[0]))]), &written));
               }
            }
            else
            {
               printf("Sync mode is disabled for this module.\r\n");
            }
         }
      }
   }

   return status;
}

nai_status_t SyncBasicOps_collectData(int32_t paramCount, int32_t* p_params)
{
   naiapp_syncInfo_t *p_syncInfo = (naiapp_syncInfo_t*)p_params;
   int32_t modNum = 0;
   naibrd_module_sync_mode_type_t mode;
   int32_t masterModNum = 0;
   nai_status_t status = NAI_ERROR_UNKNOWN;
   int32_t dataIndex = 0;
   char line[500];
   char tmpString[50];
   uint32_t read[NAI_MAX_MODULES];
   FILE *dataFile = fopen(DATA_FILE, "w");
   nai_ad_fifo_trig_t trigCtrl = (nai_ad_fifo_trig_t)0;

   if (SYNC_PARAM_COUNT == paramCount)
   {
      if (NULL == dataFile)
      {
         printf("Can not open file %s\n", DATA_FILE);
      }
      else
      {
         memset(read, 0, sizeof(read));

         /* loop through all modules and save the fifo data on the modules that are not disabled (some mode of sync enabled). */
         sprintf(line, "%s", "Index  ");
         for (modNum = 1; modNum <= p_syncInfo->moduleCount; modNum++)
         {
            if (SYNCOPS_MOD_TYPE_AD == p_syncInfo->moduleType[modNum-1])
            {
               status = GetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_TRIGGER, &mode, &masterModNum);
               if (NAIBRD_MODULE_SYNC_MODE_DISABLED != mode)
               {
                  /* Disable the fifo to stop it from collecting data. */
                  status = check_status(naibrd_AD_GetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1], &trigCtrl));
                  trigCtrl &= ~NAI_AD_GEN5_FIFO_TRIG_ENABLE;
                  status = check_status(naibrd_AD_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1], trigCtrl));

                  /* read the data that is in the A/D fifo. */
                  status = ReadFIFO32(*p_syncInfo, modNum, &(read[modNum-1]));
                  if (NAI_SUCCESS == status)
                  {
                     sprintf(tmpString, "Module%-6d", modNum);
                     strcat(line, tmpString);
                  }
               }
            }
         }

         fprintf(dataFile, "%s\n", line);

         for(dataIndex = 0; dataIndex < SYNCOPS_NUM_FIFO_SAMPLES; dataIndex++)
         {
            sprintf(line, "%3u   ", dataIndex);
            for (modNum = 1; modNum < NAI_MAX_MODULES; modNum++)
            {
               if (read[modNum-1] > 0)
               {
                  sprintf(tmpString, "%12.3f", fifoData[modNum-1][dataIndex]);
                  strcat(line, tmpString);
               }
            }
            fprintf(dataFile, "%s\n", line);
            line[0] = '\0';
         }

         fclose(dataFile);
         printf("Data saved to %s\n", DATA_FILE);
      }
   }

   return status;
}

const char* SyncModeString(naibrd_module_sync_mode_type_t mode)
{
   const char* retVal = NULL;

   switch(mode)
   {
      case NAIBRD_MODULE_SYNC_MODE_DISABLED:
         retVal = "DISABLED";
         break;
      case NAIBRD_MODULE_SYNC_MODE_SLAVE_INTERNAL:
         retVal = "SLAVE (INTERNAL BOARD)";
         break;
      case NAIBRD_MODULE_SYNC_MODE_SLAVE_BOARD_CLOCK:
         retVal = "SLAVE (EXT BOARD SOURCE)";
         break;
      case NAIBRD_MODULE_SYNC_MODE_SLAVE_USER_CLOCK:
         retVal = "SLAVE (EXT I/O SOURCE)";
         break;
      case NAIBRD_MODULE_SYNC_MODE_MASTER:
         retVal = "MASTER";
         break;
      default:
         retVal = "ERROR!";
         break;
   }

   return retVal;
}

static bool_t SyncSupported(uint32_t modID)
{
   bool_t retVal = FALSE;

   switch(modID)
   {
      case NAI_MODULE_ID_AD1:
      case NAI_MODULE_ID_AD2:
      case NAI_MODULE_ID_AD3:
      case NAI_MODULE_ID_AD4:
      case NAI_MODULE_ID_AD5:
      case NAI_MODULE_ID_AD6:
      case NAI_MODULE_ID_ADE:
      case NAI_MODULE_ID_ADF:
      case NAI_MODULE_ID_ADG:
      case NAI_MODULE_ID_CME:
      case NAI_MODULE_ID_CMF:
      case NAI_MODULE_ID_CMG:
      case NAI_MODULE_ID_DA1:
      case NAI_MODULE_ID_DA2:
      case NAI_MODULE_ID_DA3:
      case NAI_MODULE_ID_DA4:
      case NAI_MODULE_ID_DA5:
         retVal = TRUE;
         break;
      default:
         retVal = FALSE;
         break;
   }

   return retVal;
}

static syncops_module_type_t GetModuleType(uint32_t modID)
{
   return (syncops_module_type_t)(modID & SYNCOPS_MOD_TYPE_MASK);
}

static bool_t GetMasterModule(naiapp_syncInfo_t *p_syncInfo, int32_t *p_masterModNum)
{
   bool_t bQuit = FALSE;
   bool_t bContinue = TRUE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   while(bContinue)
   {
      printf("Enter the module to sync to (master module) [1-%d]\n", p_syncInfo->moduleCount);
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (!bQuit)
      {
         if (inputResponseCnt > 0)
         {
            *p_masterModNum = (int32_t)atol((const char*)inputBuffer);
            if ((*p_masterModNum <= 0) || (*p_masterModNum > p_syncInfo->moduleCount)
               || !SyncSupported(naibrd_GetModuleID(p_syncInfo->cardIndex, *p_masterModNum)))
            {
               printf("ERROR: Invalid module value.\r\n\r\n");
            }
            else
               bContinue = FALSE;
         }
         else
         {
            printf("ERROR: Invalid module value.\r\n\r\n");
         }
      }
   }
   return bQuit;
}

static nai_status_t ConfigFifoSync(naiapp_syncInfo_t *p_syncInfo, int32_t modNum, naibrd_module_sync_mode_type_t mode, uint32_t trigCtrl)
{
   nai_status_t status = SetModuleSyncMode(*p_syncInfo, modNum, NAIBRD_SYNC_CONFIG_TRIGGER, mode, p_syncInfo->triggerMasterModNum);

   switch(p_syncInfo->moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = check_status(naibrd_AD_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1],
            (nai_ad_fifo_trig_t)trigCtrl));
         break;

      case SYNCOPS_MOD_TYPE_DA:
         status = check_status(naibrd_DA_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1],
            (nai_da_fifo_trig_t)trigCtrl));

         /* This API does not apply to all DA's, and may return NAAI_ERROR_NOT_SUPPORTED. This is ok because this setting is not needed by
             the modules that do not support it. */
         naibrd_DA_SetFIFOCtrl(p_syncInfo->cardIndex, modNum, p_syncInfo->channel[modNum-1],
               NAI_DA_GEN5_FIFO_CTRL_REPEAT_MODE | NAI_DA_GEN5_FIFO_CTRL_ENABLE);
         break;

      default:
         status = NAI_ERROR_INVALID_MODULE;
         break;
   }

   return status;
}

static nai_status_t SetFifoTriggers(naiapp_syncInfo_t *p_syncInfo, bool_t trigEnable)
{
   int32_t modIndex = 0;
   nai_status_t status = NAI_ERROR_UNKNOWN;
   uint32_t trigCtrl = 0u;

   for(modIndex = 0; modIndex < p_syncInfo->moduleCount; modIndex++)
   {
      switch(p_syncInfo->moduleType[modIndex])
      {
         case SYNCOPS_MOD_TYPE_AD:
            status = check_status(naibrd_AD_GetFIFOTrigCtrl(p_syncInfo->cardIndex, modIndex + 1, p_syncInfo->channel[modIndex],
               (nai_ad_fifo_trig_t*)(&trigCtrl)));
            if (FALSE != trigEnable)
            {
               trigCtrl |= (uint32_t)NAI_AD_GEN5_FIFO_TRIG_ENABLE;
            }
            else
            {
               trigCtrl &= (uint32_t)~NAI_AD_GEN5_FIFO_TRIG_ENABLE;
            }
            status = check_status(naibrd_AD_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modIndex + 1, p_syncInfo->channel[modIndex],
               (nai_ad_fifo_trig_t)(trigCtrl)));
            break;

         case SYNCOPS_MOD_TYPE_DA:
            status = check_status(naibrd_DA_GetFIFOTrigCtrl(p_syncInfo->cardIndex, modIndex + 1, p_syncInfo->channel[modIndex],
               (nai_da_fifo_trig_t*)(&trigCtrl)));
            if (FALSE != trigEnable)
            {
               trigCtrl |= (uint32_t)NAI_DA_GEN5_FIFO_TRIG_ENABLE;
            }
            else
            {
               trigCtrl &= (uint32_t)~NAI_DA_GEN5_FIFO_TRIG_ENABLE;
            }
            status = check_status(naibrd_DA_SetFIFOTrigCtrl(p_syncInfo->cardIndex, modIndex + 1, p_syncInfo->channel[modIndex],
               (nai_da_fifo_trig_t)(trigCtrl)));
            break;

         default:
            break;
      }
   }

   return status;
}

static nai_status_t GetModuleSyncMode(naiapp_syncInfo_t syncInfo, int32_t modNum, naibrd_module_sync_config_type_t config,
   naibrd_module_sync_mode_type_t *p_mode, int32_t *p_masterModNum)
{
   nai_status_t status = NAI_ERROR_UNKNOWN;

   switch(syncInfo.moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = check_status(naibrd_AD_GetModuleSyncMode(syncInfo.cardIndex, modNum, config, p_mode, p_masterModNum));
         break;

      case SYNCOPS_MOD_TYPE_DA:
         status = check_status(naibrd_DA_GetModuleSyncMode(syncInfo.cardIndex, modNum, config, p_mode, p_masterModNum));
         break;

      default:
         status = NAI_ERROR_NOT_SUPPORTED;
         break;
   }

   return status;
}

static nai_status_t SetModuleSyncMode(naiapp_syncInfo_t syncInfo, int32_t modNum, naibrd_module_sync_config_type_t config,
   naibrd_module_sync_mode_type_t mode, int32_t masterModNum)
{
   nai_status_t status = NAI_ERROR_UNKNOWN;

   switch(syncInfo.moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = check_status(naibrd_AD_SetModuleSyncMode(syncInfo.cardIndex, modNum, config, mode, masterModNum));
         break;

      case SYNCOPS_MOD_TYPE_DA:
         status = check_status(naibrd_DA_SetModuleSyncMode(syncInfo.cardIndex, modNum, config, mode, masterModNum));
         break;

      default:
         status = NAI_ERROR_NOT_SUPPORTED;
         break;
   }

   return status;
}

static nai_status_t ReadFIFO32(naiapp_syncInfo_t syncInfo, int32_t modNum, uint32_t *p_outRead)
{
   nai_status_t status = NAI_ERROR_UNKNOWN;

   switch(syncInfo.moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = check_status(naibrd_AD_ReadFIFO32(syncInfo.cardIndex, modNum, syncInfo.channel[modNum-1], SYNCOPS_NUM_FIFO_SAMPLES,
            fifoData[modNum-1], p_outRead));
         break;

      default:
         status = NAI_ERROR_INVALID_MODULE;
         *p_outRead = 0;
         break;
   }

   return status;
}

static nai_status_t SoftwareTrigger(naiapp_syncInfo_t syncInfo, int32_t modNum)
{
   nai_status_t status = NAI_ERROR_UNKNOWN;

   switch(syncInfo.moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = check_status(naibrd_AD_SoftwareTrigger(syncInfo.cardIndex, modNum));
         break;

      case SYNCOPS_MOD_TYPE_DA:
         status = check_status(naibrd_DA_SoftwareTrigger(syncInfo.cardIndex, modNum));
         break;

      default:
         status = NAI_ERROR_INVALID_MODULE;
         break;
   }

   return status;
}

static nai_status_t GetFIFOSize(naiapp_syncInfo_t syncInfo, int32_t modNum, int32_t channel, uint32_t *p_fifoSize)
{
   nai_status_t status = NAI_ERROR_UNKNOWN;

   switch(syncInfo.moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = check_status(naibrd_AD_GetFIFOSize(syncInfo.cardIndex, modNum, channel, p_fifoSize));
         break;

      case SYNCOPS_MOD_TYPE_DA:
         status = check_status(naibrd_DA_GetFIFOSize(syncInfo.cardIndex, modNum, channel, p_fifoSize));
         break;

      default:
         status = NAI_ERROR_INVALID_MODULE;
         break;
   }

   return status;
}

static nai_status_t GetFIFOCount(naiapp_syncInfo_t syncInfo, int32_t modNum, int32_t channel, uint32_t *p_fifoCount)
{
   nai_status_t status = NAI_ERROR_UNKNOWN;

   switch(syncInfo.moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = check_status(naibrd_AD_GetFIFOCount(syncInfo.cardIndex, modNum, channel, p_fifoCount));
         break;

      case SYNCOPS_MOD_TYPE_DA:
         status = check_status(naibrd_DA_GetFIFOCount(syncInfo.cardIndex, modNum, channel, p_fifoCount));
         break;

      default:
         status = NAI_ERROR_INVALID_MODULE;
         break;
   }

   return status;
}

static nai_status_t GetModuleRate(naiapp_syncInfo_t syncInfo, int32_t modNum, uint32_t *p_rate)
{
   nai_status_t status = NAI_ERROR_UNKNOWN;

   switch(syncInfo.moduleType[modNum-1])
   {
      case SYNCOPS_MOD_TYPE_AD:
         status = check_status(naibrd_AD_GetSampleRate(syncInfo.cardIndex, modNum, p_rate));
         break;

      case SYNCOPS_MOD_TYPE_DA:
         status = check_status(naibrd_DA_GetFIFORate(syncInfo.cardIndex, modNum, 1, p_rate));
         break;

      default:
         status = NAI_ERROR_INVALID_MODULE;
         break;
   }

   return status;
}

Help Bot

X