SSK 1.x ↔ 2.x: A Translation Guide

This guide is for developers who may have a working product on one NAI Software Support Kit and now need to work in the other — a new product that ships with the other SSK, or an update that moves you across versions.

This page is a translation reference, not a recommendation. If you’re deciding which SSK to use in the first place, see Choosing the Right SSK.

The mental model carries over

Both versions work the same way: you open a handle to the board, configure the module, read or write, then close. The cardIndex / module / channel addressing model is identical. What changes between versions is names, folder layout, header paths, and a few function signatures — not the workflow.

The entire connection skeleton is the same code in both kits. The menu-and-connect helpers — naiapp_RunBoardMenu, naiapp_query_CardIndex, naiapp_query_ModuleNumber, naiapp_access_CloseAllOpenCards — are byte-for-byte identical across 1.x and 2.x. The differences this guide covers live in the board/module API around that skeleton.

Companion references

Folder-structure mapping

SSK 1.x lays the library and the samples out in a flat tree at the package root; SSK 2.x groups everything under a base/ directory and splits the library into one folder per component. They contain the same pieces, reorganized:

SSK 1.x  (naibrd_SSK_Windows_Rev1.63/)
├── App/             prebuilt sample executables
├── AppSrc/          sample source, flat by module family
│   ├── AD/AD_BasicOps/        <- the worked example below
│   ├── DA/  Discrete/  SER/  1553/  ...
│   └── naiapp_common/         shared menu/connection helpers
├── include/         library headers (naibrd.h, nai.h, functions/, boards/, ...)
├── src/             library implementation
├── Lib/             prebuilt libraries (platform subdirs, e.g. Lib/Linux_ARM)
├── Drivers/         platform driver install (platform-specific)
└── Documentation/   offline docs
SSK 2.x  (Windows/ssk2/)
├── base/
│   ├── nai_libs/          libraries, one folder each (naibrd, naiether, naiif, nailib, naips)
│   │   └── <lib>/include/ + <lib>/src/
│   ├── nai_bsp/           board support package + platform config (platform-specific)
│   └── nai_sample_apps/
│       ├── naiapp_common/         shared menu/connection helpers (include/ + src/)
│       └── naiapp_src/
│           └── board_modules/     samples, lowercase, e.g. ad/ad_basic_ops/src/
├── build/            build outputs (platform-specific)
└── docs/             offline docs

Where each 1.x location ends up in 2.x:

SSK 1.xSSK 2.x
AppSrc/<Family>/<Sample>/base/nai_sample_apps/naiapp_src/board_modules/<family>/<sample>/src/
AppSrc/naiapp_common/base/nai_sample_apps/naiapp_common/
include/ + src/ (one tree)base/nai_libs/<lib>/include/ + …/src/ (split per library)
Documentation/docs/
Lib/ (prebuilt)produced under build/
Drivers/folded into base/nai_bsp/

Two naming conventions also flip: sample folders are PascalCase in 1.x (AD/AD_BasicOps/) and lowercase in 2.x (ad/ad_basic_ops/), and 2.x adds an extra src/ level inside each sample.

Folder layout varies slightly by platform

The trees above are the Windows packages. Drivers/, Lib/ subdirectories (1.x), and nai_bsp/ config + build/ (2.x) differ by OS/architecture. Onboard packages (PetaLinux/VxWorks) also add a naiapp_src/devices/ folder (GPIO, RTC, watchdog) that the Windows Ethernet-host package does not include. For the authoritative per-platform layout see SSK 1.x Package Guide and SSK 2.x Package Guide.

API naming cheat sheet

Some renames are systematic — apply them mechanically across your whole file. Others are per-function and must be looked up in the API reference. Start with the systematic rules:

WhatSSK 1.xSSK 2.xRule
Module function prefixnaibrd_AD_…naibrd_AD_…Same prefix — but specific names may differ (see below)
Module enum/typenai_ad_mode_t, nai_ad_range_mode_tnaibrd_ad_mode_t, naibrd_ad_polarity_tnai_<fam>_*_tnaibrd_<fam>_*_t
Module constantNAI_AD_MODE_VOLTAGE, NAI_MODULE_ID_AD4NAIBRD_AD_MODE_VOLTAGE, NAIBRD_MODULE_ID_CF1NAI_AD_* / NAI_MODULE_ID_*NAIBRD_AD_* / NAIBRD_MODULE_ID_*
Boolean literalsTRUE, FALSENAI_TRUE, NAI_FALSE1.x samples use bare TRUE/FALSE; 2.x prefixes them NAI_ (not NAIBRD_)
Other framework constantsNAI_QUIT_CHARidenticalUnchanged
Connection helpersnaiapp_RunBoardMenu, naiapp_query_CardIndex, …identicalUnchanged
Header include path#include "functions/naibrd_ad.h"#include "nai_libs/naibrd/include/functions/naibrd_ad.h"short relative → fully-qualified from base/

The pattern to internalize: board/module-domain identifiers picked up the naibrd / NAIBRD prefix in 2.x (functions stay naibrd_…; types go nai_<fam>_*_tnaibrd_<fam>_*_t; constants go NAI_<FAM>_*NAIBRD_<FAM>_*), while framework identifiers stayed in the NAI_ / naiapp_ namespace — booleans even gained a plain NAI_ (TRUENAI_TRUE), never NAIBRD_. So don’t blanket-replace NAI_NAIBRD_.

Not every function maps mechanically. These examples are all from the AD module and confirmed present in both kits:

SSK 1.xSSK 2.xNote
naibrd_AD_ConvertToVoltageRangenaibrd_AD_ConvertToRangerenamed
naibrd_AD_GetBreakFrequencynaibrd_AD_GetFilterBreakFrequencyrenamed
naibrd_AD_GetFloatingPointScaleFactor + …Offsetnaibrd_AD_GetFloatingPointAttributetwo getters consolidated into one (attribute selected by argument)
(none)naibrd_AD_GetData, naibrd_AD_GetActiveChannel, naibrd_AD_SetActiveChannelnew in 2.x

When a name doesn't translate mechanically

The most reliable reference is the SSK itself — open the per-module header (functions/naibrd_<fam>.h) and search it for keywords, as described in Finding a function’s counterpart below. The online Doxygen (SSK 1.x · SSK 2.x) is fine for browsing, but it can be incomplete so when the two disagree, trust the header.

Finding a function’s counterpart

The function names won’t line up exactly, so don’t hunt by name — hunt by what the function does. Both versions organize the API the same way, which makes the match findable in a minute or two:

  1. Stay in the same module family. A 1.x naibrd_AD_* call has its counterpart among the 2.x naibrd_AD_* calls — same family, same header (functions/naibrd_ad.h). You never search the whole API, just one module’s functions.

  2. Search by the operation, not the full name. Pick the distinctive noun and search the other kit’s module header for it. Looking for 1.x naibrd_AD_GetBreakFrequency in 2.x? Search the AD header for Frequency — you land on naibrd_AD_GetFilterBreakFrequency. Search Voltage after GetVoltage and you’re nudged toward GetData, once you notice voltage became a mode argument. The header is the complete list of what the kit actually ships — more so than the online docs.

  3. Line up the two sample apps. The same sample ships in both kits (the AD BasicOps walkthrough below is one). Open both and read them in parallel — the call at the same point in the workflow is the equivalent, even when it’s named differently. The matching samples are the most reliable Rosetta Stone you have.

  4. When in doubt, grep both trees. From each SSK root:

    # 1.x
    grep -rn "Frequency" include/functions/naibrd_ad.h
    # 2.x
    grep -rn "Frequency" base/nai_libs/naibrd/include/functions/naibrd_ad.h

    lists every candidate in seconds.

Finally, when there’s no like-named function, it almost always took one of two shapes: it was consolidated (several 1.x calls became one 2.x call with a selector argument — GetFloatingPointScaleFactor + …OffsetGetFloatingPointAttribute), or redesigned (a selector moved into a parameter — GetVoltageGetData(…, data_mode, …)). So if a direct match is missing, look for a more general function that takes an extra argument.

Worked example — AD BasicOps, side by side

The same sample ships in both kits — 1.x at AppSrc/AD/AD_BasicOps/AD_BasicOps.c, 2.x at base/nai_sample_apps/naiapp_src/board_modules/ad/ad_basic_ops/src/ad_basic_ops.c. They’re nearly line-for-line parallel. Here are the four phases of the lifecycle, side by side, with the actual source from each kit.

1. Includes — header paths get longer

The 1.x sample includes by short relative path; 2.x includes are fully qualified from base/.

/* SSK 1.x */
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_ad.h"
#include "boards/naibrd_gen5.h"
/* SSK 2.x */
#include "nai_libs/nailib/include/naitypes.h"
#include "nai_libs/naibrd/include/naibrd.h"
#include "nai_libs/naibrd/include/functions/naibrd_ad.h"
#include "nai_libs/naiif/include/naiif_stdio.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_menu.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_query.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_access.h"

What changed: only the path prefixes. The header names (naibrd.h, functions/naibrd_ad.h, the naiapp_boardaccess_* set) are the same — they just live under nai_libs/… and nai_sample_apps/… now.

2. Open the board — identical workflow

This is the connection skeleton. Apart from the boolean literal (TRUENAI_TRUE) and the module-id lookup call, it’s the same code.

/* SSK 1.x */
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
   while (!bQuit)
   {
      naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
      naibrd_GetModuleCount(cardIndex, &moduleCount);
      naiapp_query_ModuleNumber(moduleCount, 1, &module);
      modId = naibrd_GetModuleID(cardIndex, module);
      bQuit = ADBasicOps_run(cardIndex, module, modId);
   }
}
/* SSK 2.x */
if (naiapp_RunBoardMenu(CONFIG_FILE) == NAI_TRUE)
{
   while (!bQuit)
   {
      naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
      naibrd_GetModuleCount(cardIndex, &moduleCount);
      naiapp_query_ModuleNumber(moduleCount, 1, &module);
      naibrd_GetModuleName(cardIndex, module, &modId);
      bQuit = ADBasicOps_run(cardIndex, module, modId);
   }
}

What changed: == TRUE== NAI_TRUE, and the module identifier is fetched with naibrd_GetModuleID(...) (returns the id) in 1.x vs naibrd_GetModuleName(cardIndex, module, &modId) (writes it through a pointer) in 2.x. The four naiapp_* calls are byte-for-byte identical.

3. Read a channel — the rename in action

Reading a voltage is where the per-function rename shows up: 1.x calls naibrd_AD_GetVoltage, 2.x calls naibrd_AD_GetData with an explicit mode argument.

/* SSK 1.x */
nai_ad_mode_t data_mode = NAI_AD_MODE_VOLTAGE;
check_status(naibrd_AD_GetMode(cardIndex, module, channel, &data_mode));
check_status(naibrd_AD_GetVoltage(cardIndex, module, channel, &data));
/* SSK 2.x */
naibrd_ad_mode_t data_mode = NAIBRD_AD_MODE_VOLTAGE;
check_status(naibrd_AD_GetMode(cardIndex, module, channel, &data_mode));
check_status(naibrd_AD_GetData(cardIndex, module, channel, data_mode, &data));

What changed: the type nai_ad_mode_tnaibrd_ad_mode_t and the constant NAI_AD_MODE_VOLTAGENAIBRD_AD_MODE_VOLTAGE (systematic). The read itself was redesigned: naibrd_AD_GetVoltage(...)naibrd_AD_GetData(..., data_mode, &data), which takes the mode as a parameter so one call covers voltage, current, and RMS. naibrd_AD_GetMode kept its name in both.

4. Close — identical

/* SSK 1.x */
naiapp_access_CloseAllOpenCards();
/* SSK 2.x */
naiapp_access_CloseAllOpenCards();

What changed: nothing. Teardown is the same call in both.

Gotchas and breaking changes

Most differences fail loudly at compile time (a renamed function just won’t link), which is the easy case. These are the ones that don’t announce themselves:

Watch out for these

  • Consolidated / redesigned calls hide behavior in an argument. A renamed function (ConvertToVoltageRangeConvertToRange) fails to compile and you fix it. But when several calls became one — GetFloatingPointScaleFactor + …OffsetGetFloatingPointAttribute, or GetVoltageGetData(…, data_mode, …) — the behavior moved into a parameter. Pass the wrong selector and it compiles fine but reads the wrong thing. Check the argument, not just the name.
  • The constant prefix is domain-specific — don’t blanket-replace NAI_NAIBRD_. Only board/module identifiers changed (NAI_AD_*NAIBRD_AD_*, NAI_MODULE_ID_*NAIBRD_MODULE_ID_*). Framework constants did not: NAI_QUIT_CHAR is unchanged, and the boolean literals went TRUE/FALSENAI_TRUE/NAI_FALSE (plain NAI_, never NAIBRD_). A global search-and-replace will mangle these.
  • Header includes are fully qualified from base/ in 2.x. A 1.x #include "functions/naibrd_ad.h" won’t resolve as-is; it’s #include "nai_libs/naibrd/include/functions/naibrd_ad.h" in 2.x. Update the paths, not just the file names.
  • Onboard-only samples don’t exist in the host package. The naiapp_src/devices/ samples (GPIO, RTC, watchdog) ship only in onboard packages (PetaLinux/VxWorks), not the Windows Ethernet-host kit. If a device sample you remember isn’t there, you’re likely looking at a different-platform package — see the SSK 2.x Package Guide.

How to port your code

The sections above are the reference; here’s the procedure. Porting an application from one SSK to the other goes fastest in this order:

  1. Start from the matching sample, not a blank file. Find the same sample in the kit you’re moving to (this guide used AD BasicOps; the folder map shows where samples live in each). Get it building and running first — it proves your toolchain and gives you a known-good reference to diff against.

  2. Swap the includes. Repoint every #include from the short relative paths to the fully-qualified nai_libs/… / nai_sample_apps/… form (or the reverse). The header names don’t change — only the path prefixes. See the include step of the walkthrough.

  3. Apply the systematic renames mechanically. Run through the first cheat-sheet table: module types nai_<fam>_*_tnaibrd_<fam>_*_t, module constants NAI_<FAM>_*NAIBRD_<FAM>_*, and booleans TRUE/FALSENAI_TRUE/NAI_FALSE. These are safe find-and-replace — but scoped to module/board identifiers only, never a blanket NAI_NAIBRD_.

  4. Resolve the leftover function calls. Whatever still won’t compile is a per-function difference. For each one, use Finding a function’s counterpart — search the other kit’s module header by what the call does, line it up against the matching sample, and watch for calls that were consolidated or redesigned to take an extra argument.

  5. Rebuild, then run the sample again before touching your own logic. SSK 2.x builds with CMake (CMakeLists.txt under base/); SSK 1.x samples ship both a Visual Studio solution and a CMake file. For the exact build and deploy commands per platform, follow the Software Development Guide 1.X or Software Development Guide 2.X, and Connecting to Boards for toolchain and target setup.

Moving the other direction works the same way

Going 2.x → 1.x uses the identical procedure — just read every mapping in this guide right-to-left. The systematic renames reverse cleanly; the per-function lookups are where you’ll spend your time either way.