TTL Output Sample Application (SSK 1.x)
Overview
The TTL Output sample application demonstrates the minimum steps required to drive a single channel of an NAI TTL (Transistor-Transistor Logic) discrete I/O module using the NAI Software Support Kit (SSK 1.x). Where the broader TTL BasicOps sample exercises the full range of TTL operations (I/O format, status, VCC banks, overcurrent reset), this sample narrows the focus to one task: configure a channel as an output, then command its logic level.
After you select a channel, the sample opens a small command menu with three operations:
| Command | Description |
|---|---|
| High | Drive the output to a logic 1 (high) |
| Low | Drive the output to a logic 0 (low) |
| Toggle | Flip the output to the opposite of its current state |
It supports the Gen 5 24-channel TTL modules (TL1–TL8) and the legacy Gen 3 D7 module. Each menu command maps directly to a naibrd_TTL_*() API call, so the sample doubles as a focused reference for the output-drive portion of the TTL API.
Prerequisites
Before running this sample, make sure you have:
- An NAI board with a TTL module installed (TL1–TL8, or a legacy D7).
- 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 TTL_Output executable from your build output directory. On startup the application looks for a configuration file (default_TTL_Output.txt). On the first run this file will not exist — the application presents an interactive board menu where you configure a board connection, card index, and module slot. You can save this configuration so that subsequent runs skip the menu and connect automatically. After selecting the module you are prompted for a channel, and the TTL output command menu opens for that channel.
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 TTL.
The main() function follows a standard SSK 1.x startup flow:
- Call
naiapp_RunBoardMenu()to load a saved configuration file (if one exists) or present the interactive board menu. - Query the user for a card index with
naiapp_query_CardIndex(). - Retrieve the module count with
naibrd_GetModuleCount()and query for a module slot withnaiapp_query_ModuleNumber(). - Retrieve the module ID with
naibrd_GetModuleID()and, if valid, hand control toRun_TTL_Output().
#if defined (__VXWORKS__)
int32_t TTL_Output(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
uint32_t moduleID = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
if (stop != TRUE)
{
moduleID = naibrd_GetModuleID(cardIndex, module);
if ((moduleID != 0))
Run_TTL_Output(cardIndex, module, moduleID);
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
naiapp_access_CloseAllOpenCards();
return 0;
}Important
Common connection errors you may encounter at this stage:
- No board found — verify that the board is powered on and physically connected. Check that the configuration file lists the correct interface and address.
- Connection timeout — confirm network settings (for Ethernet connections) or bus configuration (for PCI/PCIe). Firewalls and IP mismatches are frequent causes.
- Invalid card or module index — indices are zero-based for cards and one-based for modules. Ensure the values you pass match your hardware setup.
- “Module selection not recognized as TTL module” — the selected slot does not contain a TTL module.
naibrd_TTL_GetChannelCount()returns 0 for non-TTL modules, and the sample rejects the selection.
Program Structure
Entry Point
On standard platforms the entry point is main(). On VxWorks the entry point is TTL_Output() — the SSK 1.x build system selects the correct variant via a preprocessor guard:
#if defined (__VXWORKS__)
int32_t TTL_Output(void)
#else
int32_t main(void)
#endifConfirming the Module and Selecting a Channel
Run_TTL_Output() first confirms the selected slot holds a TTL module by checking that it reports a non-zero channel count:
MaxChannel = naibrd_TTL_GetChannelCount(ModuleID);
if (MaxChannel == 0)
printf(" *** Module selection not recognized as TTL module. ***\n\n");
else
Run_TTL_Output_Start(cardIndex, module, ModuleID, MaxChannel);int32_t naibrd_TTL_GetChannelCount(uint32_t modid)— returns the number of TTL channels for the given module ID, or 0 if the module is not a TTL module.
Run_TTL_Output_Start() then prompts for a channel with naiapp_query_ChannelNumber() and stores the card, module, and selected channel in an naiapp_AppParameters_t struct. That struct is passed to each command handler, which is how the High / Low / Toggle handlers know which channel to act on.
Command Loop
The inner loop displays the channel’s current state, prints the command menu, and dispatches the selection through the TTL_Output_MainMenuCmds[] table to the matching handler function. This menu-driven structure is a convenience of the sample — in your own application you would call the naibrd_TTL_*() functions directly once the channel is configured.
Configuring the Channel for Output
Before an output can be driven, the channel must be reset and placed in an output-capable mode. Cfg_TTL_Setup() does this, and the exact call depends on the module generation:
static int32_t Cfg_TTL_Setup(int32_t cardIndex, int32_t module, int32_t modid, int32_t channel)
{
int32_t status;
status = (int32_t)check_status(naibrd_TTL_Reset(cardIndex, module, channel, NAI_TTL_RESET_TIMER_ONLY));
switch (modid)
{
case NAI_MODULE_ID_TL1:
case NAI_MODULE_ID_TL2:
status |= (int32_t)check_status(naibrd_TTL_SetOpMode(cardIndex, module, channel, NAI_TTL_MODE_STD_INPUT_OUTPUT));
break;
case NAI_MODULE_ID_D7:
status |= (int32_t)check_status(naibrd_TTL_SetIOFormat(cardIndex, module, channel, NAI_TTL_GEN5_IOFORMAT_OUTPUT));
}
return status;
}nai_status_t naibrd_TTL_Reset(int32_t cardIndex, int32_t module, int32_t channel, nai_ttl_reset_type_t resetType)— resets the channel.NAI_TTL_RESET_TIMER_ONLYclears the channel’s timer/counter state without disturbing other configuration.nai_status_t naibrd_TTL_SetOpMode(int32_t cardIndex, int32_t module, int32_t channel, nai_ttl_enhanced_mode_t mode)— sets the Gen 5 channel operating mode.NAI_TTL_MODE_STD_INPUT_OUTPUTselects the standard bidirectional I/O mode used for basic output drive on TL1/TL2.nai_status_t naibrd_TTL_SetIOFormat(int32_t cardIndex, int32_t module, int32_t channel, nai_ttl_ioformat_t format)— sets the channel’s input/output format.NAI_TTL_GEN5_IOFORMAT_OUTPUTconfigures the channel as an output.
Note
The two branches reflect a difference in how the module generations expose output configuration: the TL1/TL2 path selects an operating mode with
naibrd_TTL_SetOpMode(), while the D7 path sets the I/O format directly withnaibrd_TTL_SetIOFormat(). For a different TTL module, follow the pattern for the closest matching case and consult that module’s manual.
The sample also forces the channel’s VCC bank to the internal supply so the output has power to drive with no external supply required:
naibrd_TTL_SetBankVCCSource(cardIndex, module, 1, NAI_TTL_VCC_INTERNAL);nai_status_t naibrd_TTL_SetBankVCCSource(int32_t cardIndex, int32_t module, int32_t bank, nai_ttl_vcc_t source)— selects the supply source for a VCC bank.NAI_TTL_VCC_INTERNALuses the module’s internal supply;NAI_TTL_VCC_EXTERNALuses an externally provided one.
Important
VCC configuration applies to an entire bank, so it affects every channel that shares that bank. This sample sets bank 1 to the internal supply. If your channel is wired to an external supply, or lives in a different bank, adjust this call accordingly — selecting internal VCC on a bank wired for external supply (or vice versa) will leave the output unable to drive correctly.
Driving the Output
With the channel configured, each menu command drives the output through a single naibrd_TTL_SetOutputState() call. High and Low set the state directly:
/* High */
naibrd_TTL_SetOutputState(cardIndex, module, channel, NAI_TTL_STATE_HI); /* drive high */
/* Low */
naibrd_TTL_SetOutputState(cardIndex, module, channel, NAI_TTL_STATE_LO); /* drive low */nai_status_t naibrd_TTL_SetOutputState(int32_t cardIndex, int32_t module, int32_t channel, nai_ttl_state_t state)— sets the commanded output level.NAI_TTL_STATE_HIdrives the output high;NAI_TTL_STATE_LOdrives it low.
Toggle first reads the current state, then commands the opposite level:
naibrd_TTL_GetOutputState(cardIndex, module, channel, &state);
if (NAI_TTL_STATE_HI == state)
naibrd_TTL_SetOutputState(cardIndex, module, channel, NAI_TTL_STATE_LO);
else
naibrd_TTL_SetOutputState(cardIndex, module, channel, NAI_TTL_STATE_HI);nai_status_t naibrd_TTL_GetOutputState(int32_t cardIndex, int32_t module, int32_t channel, nai_ttl_state_t* outstate)— reads back the channel’s commanded output state.
Each handler returns NAI_SUCCESS when the underlying API call succeeds and NAI_ERROR_UNKNOWN otherwise, so a failed board access surfaces to the command loop.
Reading Back State
After every command the sample reprints the channel header so you can confirm the change. Print_TTL_Channel_Header() reads back the channel’s operating mode and output state:
nai_ttl_state_t state;
nai_ttl_enhanced_mode_t mode;
naibrd_TTL_GetOpMode(cardIndex, module, channel, &mode);
naibrd_TTL_GetOutputState(cardIndex, module, channel, &state);
printf(" %2d %3d %c \r\n", channel, (uint32_t)mode, (state == NAI_TTL_STATE_LO) ? 'L' : 'H');nai_status_t naibrd_TTL_GetOpMode(int32_t cardIndex, int32_t module, int32_t channel, nai_ttl_enhanced_mode_t* outmode)— reads back the channel’s operating mode.nai_status_t naibrd_TTL_GetOutputState(int32_t cardIndex, int32_t module, int32_t channel, nai_ttl_state_t* outstate)— reads back the commanded output state, printed asHorL.
Troubleshooting Reference
This table summarizes common errors and symptoms covered in the sections above. Consult your module’s manual for hardware-specific diagnostic procedures.
| Error / Symptom | Possible Causes | Suggested Resolution |
|---|---|---|
| No board found or connection timeout | Board not powered, incorrect or missing configuration file, network issue | Verify hardware is powered and connected. If default_TTL_Output.txt exists, check that it lists the correct interface and address; otherwise configure and save your connection in the board menu. |
| ”Module selection not recognized as TTL module” | Selected slot is not a TTL module, or wrong module number | naibrd_TTL_GetChannelCount() returns 0 for non-TTL modules. Verify the slot contains a TL1–TL8 or D7. |
| Output level does not change | Channel not configured for output, or the wrong channel was selected | Confirm the channel was set up via Cfg_TTL_Setup() (operating mode / I/O format) before commanding a state, and that the channel you are probing is the one you selected. |
| Output changes state but drives nothing | VCC bank not powered as wired | This sample sets bank 1 to internal VCC. Match the bank’s VCC source to how it is wired (naibrd_TTL_SetBankVCCSource()). |
| Configuration path skipped for your module | Module ID not handled in Cfg_TTL_Setup() | The sample handles TL1/TL2 and D7 explicitly. For another TTL module, follow the closest matching branch and its manual. |
Full Source
The complete source for this sample is provided below for reference. The sections above explain each part in detail.
Full Source — TTL_Output.c (SSK 1.x)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
/* Common Sample Program include files */
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_ttl.h"
#include "advanced/nai_ether_adv.h"
static const int8_t *CONFIG_FILE = (const int8_t *)"default_TTL_Output.txt";
static const int32_t DEF_TTL_FIRST_CHAN = 1;
/* Function Prototypes */
void Run_TTL_Output(int32_t cardIndex, int32_t module, int32_t ModuleID);
void Run_TTL_Output_Start(int32_t cardIndex, int32_t module, uint32_t ModuleID, int32_t MaxChannel);
static void Print_TTL_Channel_Header(int32_t cardIndex, int32_t module, int32_t channelCount);
nai_status_t Set_TTL_High(int32_t paramCount, int32_t* p_params);
nai_status_t Set_TTL_Low(int32_t paramCount, int32_t* p_params);
nai_status_t Set_TTL_Toggle(int32_t paramCount, int32_t* p_params);
static int32_t Cfg_TTL_Setup(int32_t cardIndex, int32_t module, int32_t modid, int32_t channel);
enum ttl_SynchronousPreload_commands
{
TTL_OUTPUT_CMD_HIGH,
TTL_OUTPUT_CMD_LOW,
TTL_OUTPUT_CMD_TOGGLE,
TTL_OUTPUT_CMD_LAST
};
naiapp_cmdtbl_params_t TTL_Output_MainMenuCmds[] =
{
{"High", "Output a logic 1 (high)", TTL_OUTPUT_CMD_HIGH, Set_TTL_High },
{"Low", "Output a logic 0 (low)", TTL_OUTPUT_CMD_LOW, Set_TTL_Low },
{"Toggle", "Toggle the output state", TTL_OUTPUT_CMD_TOGGLE, Set_TTL_Toggle }
};
/**************************************************************************************************************/
/**
<summary>
main obtains and/or loads device configuration.
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t TTL_Output(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
uint32_t moduleID = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
if (stop != TRUE)
{
moduleID = naibrd_GetModuleID(cardIndex, module);
if ((moduleID != 0))
{
Run_TTL_Output(cardIndex, module, moduleID);
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
/**************************************************************************************************************/
/**
<summary>
Run_TTL_Output prompts the user for the card, module and channel to use for the application and calls
Run_TTL_Output_Start if the card, module, channel is valid for as a TLL module.
</summary>
*/
/**************************************************************************************************************/
void Run_TTL_Output(int32_t cardIndex, int32_t module, int32_t ModuleID)
{
int32_t MaxChannel;
MaxChannel = naibrd_TTL_GetChannelCount(ModuleID);
if (MaxChannel == 0)
{
printf(" *** Module selection not recognized as TTL module. ***\n\n");
}
else
{
Run_TTL_Output_Start(cardIndex, module, ModuleID, MaxChannel);
}
}
/**************************************************************************************************************/
/**
<summary>
Run_TTL_Output_Start runs the inner menu which allows the user to select a channel and an output state.
</summary>
*/
/**************************************************************************************************************/
void Run_TTL_Output_Start(int32_t cardIndex, int32_t module, uint32_t ModuleID, int32_t MaxChannel)
{
bool_t bQuit = FALSE;
bool_t bContinue = TRUE;
bool_t bCmdFound = FALSE;
int32_t chan = 0;
int32_t defaultchan = 1;
int32_t cmd;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
naiapp_AppParameters_t ttl_params;
p_naiapp_AppParameters_t ttl_output_params = &ttl_params;
ttl_output_params->cardIndex = cardIndex;
ttl_output_params->module = module;
while (bContinue)
{
printf(" \r\n\r\n");
printf("Channel selection \r\n");
printf("================= \r\n");
defaultchan = DEF_TTL_FIRST_CHAN;
bQuit = naiapp_query_ChannelNumber(MaxChannel, defaultchan, &ttl_output_params->channel);
check_status(naibrd_TTL_SetBankVCCSource(cardIndex, module, 1, (nai_ttl_vcc_t)NAI_TTL_VCC_INTERNAL));
/* Configure the channel for first use */
Cfg_TTL_Setup(cardIndex, module, ModuleID, chan);
/* Load commands from the state table and get a response*/
naiapp_utils_LoadParamMenuCommands(TTL_OUTPUT_CMD_LAST, TTL_Output_MainMenuCmds);
/* Ensure that we're using the internal power supply */
check_status(naibrd_TTL_SetBankVCCSource(cardIndex, module, 1, (nai_ttl_vcc_t)NAI_TTL_VCC_INTERNAL));
while (bContinue)
{
/* Display_TTL_SynchronousPreload_Channel(cardIndex, module, chan, ModuleID); */
naiapp_display_ParamMenuCommands((int8_t *)"TTL Synchronous Preload Operation Menu");
/* Print the state of the channel */
Print_TTL_Channel_Header(cardIndex, module, chan);
printf("\nType TTL command or %c to quit : ", NAI_QUIT_CHAR);
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)
{
switch (cmd)
{
case TTL_OUTPUT_CMD_HIGH:
case TTL_OUTPUT_CMD_LOW:
case TTL_OUTPUT_CMD_TOGGLE:
if (NULL != TTL_Output_MainMenuCmds[cmd].func) /* Ensure that the function pointer is valid */
{
TTL_Output_MainMenuCmds[cmd].func(APP_PARAM_COUNT, (int32_t*)ttl_output_params);
Print_TTL_Channel_Header(cardIndex, module, chan);
}
else
printf("No function is associated with the command %s.\r\n", TTL_Output_MainMenuCmds[cmd].cmdstr);
break;
default:
printf("Invalid command entered\n");
break;
}
}
else
printf("Invalid command entered\n");
}
}
else
bContinue = FALSE;
}
}
}
/**************************************************************************************************************/
/**
<summary>
Print_TTL_Channel_Header Formats and prints a header which indicates the channel number, mode, and output status.
</summary>
*/
/**************************************************************************************************************/
static void Print_TTL_Channel_Header(int32_t cardIndex, int32_t module, int32_t channel)
{
uint32_t status;
nai_ttl_state_t state;
nai_ttl_enhanced_mode_t mode;
printf(" \r\n\r\n");
printf("=======================\r\n");
printf(" Channel Status \r\n");
printf("=======================\r\n");
printf(" Ch Mode State \r\n");
printf("-----------------------\r\n");
status = check_status(naibrd_TTL_GetOpMode(cardIndex, module, channel, &mode));
status |= check_status(naibrd_TTL_GetOutputState(cardIndex, module, channel, &state));
printf(" %2d %3d %c \r\n", channel, (uint32_t)mode, (state == NAI_TTL_STATE_LO) ? 'L' : 'H');
}
/*============================================================================================================= */
/* Sample Code Starts Here */
/*============================================================================================================= */
/**************************************************************************************************************/
/**
<summary>
Cfg_TTL_Setup resets and configures the specified channel to NAI_TTL_MODE_OUTPUT mode.
</summary>
*/
/**************************************************************************************************************/
static int32_t Cfg_TTL_Setup(int32_t cardIndex, int32_t module, int32_t modid, int32_t channel)
{
int32_t status;
status = (int32_t)check_status(naibrd_TTL_Reset(cardIndex, module, channel, NAI_TTL_RESET_TIMER_ONLY));
switch (modid)
{
case NAI_MODULE_ID_TL1:
case NAI_MODULE_ID_TL2:
status |= (int32_t)check_status(naibrd_TTL_SetOpMode(cardIndex, module, channel, NAI_TTL_MODE_STD_INPUT_OUTPUT));
break;
case NAI_MODULE_ID_D7:
status |= (int32_t)check_status(naibrd_TTL_SetIOFormat(cardIndex, module, channel, NAI_TTL_GEN5_IOFORMAT_OUTPUT));
}
return status;
}
/**************************************************************************************************************/
/**
<summary>
Set_TTL_High will set the output state of the specified channel to logic 1 (High).
</summary>
*/
/**************************************************************************************************************/
nai_status_t Set_TTL_High(int32_t paramCount, int32_t* p_params)
{
int32_t status;
p_naiapp_AppParameters_t p_ttl_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_ttl_params->cardIndex;
int32_t module = p_ttl_params->module;
int32_t channel = p_ttl_params->channel;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
status = check_status(naibrd_TTL_SetOutputState(cardIndex, module, channel, NAI_TTL_STATE_HI));
if (status == NAI_SUCCESS)
return NAI_SUCCESS;
else
return NAI_ERROR_UNKNOWN;
}
/**************************************************************************************************************/
/**
<summary>
Set_TTL_Low will set the output state of the specified channel to logic 0 (Low).
</summary>
*/
/**************************************************************************************************************/
nai_status_t Set_TTL_Low(int32_t paramCount, int32_t* p_params)
{
int32_t status;
p_naiapp_AppParameters_t p_ttl_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_ttl_params->cardIndex;
int32_t module = p_ttl_params->module;
int32_t channel = p_ttl_params->channel;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
status = check_status(naibrd_TTL_SetOutputState(cardIndex, module, channel, NAI_TTL_STATE_LO));
if (status == NAI_SUCCESS)
return NAI_SUCCESS;
else
return NAI_ERROR_UNKNOWN;
}
/**************************************************************************************************************/
/**
<summary>
Set_TTL_Toggle will check the output state of the specified channel and will toggle it accordingly
(i.e. High -> Low, Low -> High).
</summary>
*/
/**************************************************************************************************************/
nai_status_t Set_TTL_Toggle(int32_t paramCount, int32_t* p_params)
{
int32_t status;
nai_ttl_state_t state;
p_naiapp_AppParameters_t p_ttl_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_ttl_params->cardIndex;
int32_t module = p_ttl_params->module;
int32_t channel = p_ttl_params->channel;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
status = check_status(naibrd_TTL_GetOutputState(cardIndex, module, channel, &state));
if (NAI_TTL_STATE_HI == state)
status |= check_status(naibrd_TTL_SetOutputState(cardIndex, module, channel, NAI_TTL_STATE_LO));
else
status |= check_status(naibrd_TTL_SetOutputState(cardIndex, module, channel, NAI_TTL_STATE_HI));
if (status == NAI_SUCCESS)
return NAI_SUCCESS;
else
return NAI_ERROR_UNKNOWN;
}