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

CAN Interactive

CAN Interactive Sample Application (SSK 1.x)

Overview

The CAN Interactive sample application is a menu-driven tool for configuring and exercising CAN bus transmit and receive operations on NAI CB-series modules using the NAI Software Support Kit (SSK 1.x). It lets you set bit timing parameters, build CAN data frames, transmit single or repeated messages, listen for incoming traffic on all channels, and inspect error counters and FIFO status — all through an interactive console interface.

This sample supports the following CAN module types:

  • CB1 — Gen5 CAN A/B (standard/extended identifier filtering)

  • CB2 — Gen5 J1939

  • CB3 — Gen5 J1939 with per-channel protocol selection

  • CB6 — Gen5 J1939 with per-channel protocol selection and physical line-break detection

The application automatically detects whether the installed module uses CAN A/B or J1939 protocol and adjusts its transmit and receive calls accordingly. It serves as a practical API reference — each menu command maps directly to one or more naibrd_CAN_*() API calls that you can lift into your own code.

CAN Bus Background

CAN (Controller Area Network) is a multi-master serial bus widely used in embedded and vehicle systems. Key concepts used throughout this sample:

  • Message ID — each CAN frame carries an identifier (11-bit standard or 29-bit extended) that determines message priority and content. In CAN A/B mode the application lets you set arbitrary message IDs. In J1939 mode the identifier encodes a Parameter Group Number (PGN), priority, source address, and destination address.

  • Data frame — a CAN 2.0 data frame carries 0 to 8 bytes of payload. The sample lets you set the data, data length, and optionally a multi-byte data pattern.

  • Bit timing — the baud rate on a CAN bus is determined by four parameters: prescaler, synchronization jump width (SJW), time segment 1 (TSEG1, the setup/propagation time), and time segment 2 (TSEG2, the hold time). The module’s 8 MHz clock is divided by these values according to: Baud = 8 MHz / Prescaler + 1) * (3 + SJW + TSEG1 + TSEG2.

  • Acceptance filter — hardware-level message filtering that compares incoming message IDs against an acceptance code and mask. A bit set to 1 in the mask means "don’t care" for that bit position; a bit set to 0 means the corresponding bit in the incoming ID must match the acceptance code. This reduces software overhead by discarding unwanted traffic in hardware.

  • Control word — a per-channel register that enables or disables transmit, receive, acceptance filtering, CAN A/B standard/extended filtering, and channel reset.

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a CB module installed (CB1, CB2, CB3, or CB6).

  • A CAN bus connection between the module and at least one other CAN node (or a loopback cable for self-test).

  • 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 CAN_Interactive executable from your build output directory. On startup the application looks for a configuration file (default_CANTx.txt). On the first run, this file will not exist — the application will present an interactive board menu where you configure a board connection, card index, and module slot. You can save this configuration so that subsequent runs skip the menu and connect automatically. Once connected, a top-level menu lets you choose between Single Transmit and Multi Transmit modes, each with its own configuration submenu.

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 CAN. 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_CANTx.txt) is not included with the SSK — it is created when the user saves their connection settings from the board menu. On the first run, the menu will always appear.

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

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

  4. Store the card index and module count in global state, then enter the main command loop via Run_CAN_TransmitByChoice().

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

   if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
   {
      while (stop != TRUE)
      {
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         userInput.nCardIdx = cardIndex;
         if (stop != TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
            g_moduleCount = moduleCnt;
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &userInput.nModuleNumber);
            if (stop != TRUE)
            {
               Run_CAN_TransmitByChoice();
            }
         }

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

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

   return 0;
}
Important

Common connection errors you may encounter at this stage:

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

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

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

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

Program Structure

Application Parameters

The sample stores all user-configurable state in a global _userInput struct. In your own application you will track the same values, typically in a configuration struct or function parameters:

Field Purpose

nCardIdx

Board card index (zero-based).

nModuleNumber

Module slot number (one-based). Set to 0 to target all CAN modules on the board.

nChannelNumber

CAN channel number (one-based).

nPreScaler

Bit-timing prescaler value.

nSJW

Synchronization jump width.

nTseg1

Time segment 1 (setup/propagation time).

nTseg2

Time segment 2 (hold time).

nModeAB

Protocol mode: 0 = CAN-A (standard 11-bit ID), 1 = CAN-B (extended 29-bit ID).

nCtrlWord

Channel control word (Tx enable, Rx enable, filtering, reset).

nAcceptanceMask

32-bit acceptance mask for receive filtering.

nAcceptanceCode

32-bit acceptance code for receive filtering.

nData

Single-byte transmit data value (used when data pattern is disabled).

nDataLength

Number of payload bytes (1—​8).

nUseDataPattern

1 = use multi-byte data pattern, 0 = repeat single data byte.

nMsgNumber

Message ID. Set to 1 for auto-increment mode.

nRepeat

1 = repeat transmission in a loop, 0 = single shot.

nLoopCount

Number of transmissions when repeat is enabled.

nDelay_Ms

Delay in milliseconds between repeated transmissions.

nIncrement

Data increment step for multi-transmit mode.

The command loop uses a three-level menu system. The menu system is a sample convenience — in your own code, call these API functions directly.

  • Top-Level Menu — choose S for Single Transmit or M for Multi Transmit.

  • Mode Menu — within each mode, choose C for Configuration or R for Run.

  • Configuration Submenu — set individual parameters (module, channel, bit timing, control word, data, acceptance filter, etc.) and execute operations (transmit, listen, read/write).

Bit Timing Configuration

CAN bus communication requires all nodes on the bus to use the same baud rate. The baud rate is determined by four bit-timing parameters that you configure before enabling transmit or receive.

Set Prescaler (P)

To set the clock prescaler that divides the module’s 8 MHz oscillator, call naibrd_CAN_SetBitTiming(). The sample stores the value and applies it when you execute a transmit or listen command.

The default prescaler is 0x00 for both 1 Mbit (CAN A/B modules) and 500 Kbit (J1939 modules). The application automatically selects the appropriate default based on the detected module protocol.

if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
   defaultPreScaler = PRESCALER_500K;

printf("\nEnter CAN <<Pre-scaler>> or %c to quit [[default = 0x%02X]]: ",
       NAI_QUIT_CHAR, defaultPreScaler);

Set Synchronization Jump Width (S)

The SJW defines the maximum number of time quanta by which the bit timing can be lengthened or shortened to resynchronize with the bus. To set SJW in your application, include it in the naibrd_CAN_SetBitTiming() call along with the other timing parameters.

Set Time Segment 1 — TSEG1 (O)

TSEG1 covers the propagation delay and phase buffer segment 1. It determines the sample point position within each bit period. For 1 Mbit CAN A/B operation, the default is 3; for 500 Kbit J1939, the default is 12.

Set Time Segment 2 — TSEG2 (T)

TSEG2 defines the phase buffer segment 2 (hold time after the sample point). For 1 Mbit CAN A/B operation, the default is 2; for 500 Kbit J1939, the default is 1.

Applying Bit Timing to Hardware

All four bit-timing parameters are written to the module in a single API call. The sample calls setCanBitTiming() before any transmit or listen operation:

static void setCanBitTiming()
{
   int32_t activeModuleNumber = CAN_DEFAULT_MODULE;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   check_status(naibrd_CAN_SetBitTiming(userInput.nCardIdx, activeModuleNumber,
      userInput.nChannelNumber, userInput.nPreScaler, userInput.nSJW,
      userInput.nTseg1, userInput.nTseg2));
}

To configure bit timing in your own application, call naibrd_CAN_SetBitTiming() with the card index, module, channel, prescaler, SJW, TSEG1, and TSEG2. The resulting baud rate is: 8 MHz / Prescaler + 1) * (3 + SJW + TSEG1 + TSEG2.

The predefined timing constants in the SSK are:

Baud Rate Prescaler SJW TSEG1 TSEG2

1 Mbit

0

0

3

2

500 Kbit

0

0

12

1

250 Kbit

1

0

12

1

Important

Common Errors

  • Baud rate mismatch — if the transmitting and receiving nodes are not configured to the same baud rate, you will see error frames and no successful data exchange. All nodes on a CAN bus segment must use identical bit timing.

  • Bit timing set after Tx/Rx enabled — always configure bit timing before enabling transmit or receive via the control word. Changing timing while the channel is active can cause bus errors.

Control Word Configuration (CW)

The control word is a per-channel register that governs transmit/receive enable, acceptance filtering, and channel reset. To set the control word in your application, call naibrd_CAN_SetControlRaw().

The sample prompts for a 6-character binary string where each character maps to a control bit:

Position Bit Function

1st char

D15

Reset channel (clears Rx and Tx FIFO buffers when set to 1).

2nd char

D5

Standard/Extended filter: 1 = accept only Standard mode messages, 0 (with D4=1) = accept only Extended mode messages.

3rd char

D4

Enable CAN A/B filtering: 1 = use the D5 standard/extended filter.

4th char

D3

Use acceptance code/mask for Rx filtering: 1 = enable, 0 = disable.

5th char

D2

Rx enable: 1 = enable receive, 0 = disable.

6th char

D0

Tx enable: 1 = enable transmit, 0 = disable.

For example, the default input 000011 enables both Rx (D2) and Tx (D0) with no filtering and no channel reset, which produces a control word value of 0x0005.

static void setCanControlRegister()
{
   int32_t activeModuleNumber = CAN_DEFAULT_MODULE;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   check_status(naibrd_CAN_SetControlRaw(userInput.nCardIdx, activeModuleNumber,
      userInput.nChannelNumber, userInput.nCtrlWord));
}
Important

Common Errors

  • No data received with filtering enabled — if you enable acceptance filtering (D3=1) but the acceptance mask and code do not match the incoming message IDs, all frames will be silently discarded. Verify your mask/code values with the AM and AC commands.

  • Transmit fails silently — the Tx enable bit (D0) must be set before calling a transmit function. If Tx is disabled, the frame is queued but never sent.

Acceptance Filter Configuration

CAN acceptance filtering allows the hardware to discard messages that do not match a specified pattern, reducing the load on your application.

Set Acceptance Mask (AM)

The acceptance mask is a 32-bit value where each bit controls whether the corresponding bit in the incoming message ID is checked (0 = must match) or ignored (1 = don’t care). To pass all messages, set the mask to 0xFFFFFFFF. To require an exact match, set the mask to 0x00000000.

printf("\nSet CAN acceptance mask <<ACC. MASK>> (32bit value) or %c to quit "
       "[default = 0x00000000]: ", NAI_QUIT_CHAR);

In your own code, write the mask to hardware with naibrd_CAN_SetAcceptMask() and read it back with naibrd_CAN_GetAcceptMask().

Set Acceptance Code (AC)

The acceptance code is the 32-bit reference value that incoming message IDs are compared against (after masking). Only messages whose masked ID matches the masked acceptance code are placed in the receive FIFO.

In your own code, call naibrd_CAN_SetAcceptCode() and naibrd_CAN_GetAcceptCode().

Note
Acceptance filtering only takes effect when bit D3 of the control word is set to 1. Use the CW command to enable it.
Important

Common Errors

  • All messages filtered out — a mask of 0x00000000 with the wrong acceptance code rejects every message. Start with a mask of 0xFFFFFFFF (pass all) and narrow down.

  • Filtering has no effect — acceptance filtering is only active when D3 of the control word is set. Check your control word with CW.

Module and Channel Selection

Select Module (M)

To target a specific module slot, enter its one-based module number. Enter 0 to target all CAN modules on the board — the sample will iterate over every module slot and apply operations to each one that contains a CB module.

Select Channel ©

CAN modules contain multiple independent channels. Enter the one-based channel number. The number of available channels depends on your module type; call naibrd_CAN_GetChannelCount() to query this at runtime.

Set Mode A/B (AB)

For CB1 modules that support both CAN-A (standard 11-bit identifiers) and CAN-B (extended 29-bit identifiers), this command selects the protocol mode. Enter 0 for CAN-A or 1 for CAN-B. J1939 modules (CB2, CB3, CB6) always use 29-bit extended identifiers.

Important

Common Errors

  • NAI_ERROR_NOT_SUPPORTED — attempting to set Mode A/B on a J1939-only module (CB2) returns this error. CB3 and CB6 support per-channel protocol selection.

  • Invalid channel number — channel indices are one-based. Passing zero or a value exceeding the module’s channel count results in an error.

Data Configuration

Set Data (D)

Enter a single hex byte (e.g., A5) that will be repeated across all payload positions. This is used when data pattern mode is disabled.

Set Data Pattern (DP)

Enter a multi-byte hex string (up to 8 bytes, e.g., 0102030405060708). The string is parsed in pairs of hex characters and stored as the transmit payload. This gives you full control over each byte in the CAN data frame.

Enable Data Pattern (UDP)

Toggle whether the transmit uses the single data byte (0) or the multi-byte data pattern (1). Default is 1 (use data pattern).

Set Data Length (L)

Set the number of payload bytes in each CAN frame (1—​8). CAN 2.0 frames support a maximum Data Length Code (DLC) of 8 bytes.

nLength = atoi((const char *)inputBuffer);
if ((nLength <= CAN_MAX_MODE_AB_DATA_LENGTH) && (nLength > CAN_DATA_LENGTH_ZERO))
{
   userInput.nDataLength = nLength;
}
else
   printf("\nCAN Transmit <<Data Length>> Error.  Data Length Limit[1-8]");

Set Message Number (N)

Set the CAN message identifier (in hex) for transmitted frames. The default value of 1 enables auto-increment mode, where the message ID increases by one with each transmission. To use a fixed message ID, enter a value greater than 1.

In CAN A/B mode, this value is used directly as the 11-bit or 29-bit identifier. In J1939 mode, the sample uses hardcoded PGN, priority, and destination values in fireJ1939Message().

Important

Common Errors

  • Data length exceeds 8 bytes — CAN 2.0 frames are limited to 8 bytes. Values outside the 1—​8 range are rejected.

  • Data pattern shorter than data length — if you set a data pattern of 2 bytes but a data length of 8, the remaining bytes will be zero-filled from the buffer initialization.

Single Transmit Operations

The Single Transmit mode lets you configure and fire individual CAN messages. From the Single Transmit Configuration submenu, you can set all parameters and then execute operations.

Transmit (X)

Applies the current bit timing and control word to the hardware, then transmits a CAN frame. The sample detects the module protocol and calls the appropriate transmit function:

memset(u8Buffer, 0x0, sizeof(u8Buffer));
fillTxBuffer(u8Buffer);
if (userInput.nRepeat == NO)
{
   if (userInput.nMsgNumber == CAN_INCREMENT_AUTO)
      userInput.nRealTimeMsgNum++;
   msgid = userInput.nRealTimeMsgNum;

   if (IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1))
      fireMessage(activeModuleNumber, msgid, is_CAN_A, u8Buffer);
   else if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
      fireJ1939Message(activeModuleNumber, msgid, u8Buffer);
}

For CAN A/B modules, fireMessage() calls naibrd_CAN_QueueTransmit() to place the frame in the Tx FIFO, then naibrd_CAN_SetTxEnable() to trigger transmission:

static void fireMessage(int32_t moduleNumber, int32_t msgid,
                        bool_t isCanA, uint8_t* u8Buffer)
{
   userInput.nChannelNumber = userInput.nP6ChanNumber;
   check_status(naibrd_CAN_QueueTransmit(userInput.nCardIdx, moduleNumber,
      userInput.nChannelNumber, isCanA, msgid, u8Buffer, userInput.nDataLength));
   check_status(naibrd_CAN_SetTxEnable(userInput.nCardIdx, moduleNumber,
      userInput.nChannelNumber, CAN_TX_ENABLE));
   Show_TxResult();
}

For J1939 modules, fireJ1939Message() calls naibrd_CAN_QueueTransmit_J1939() with PGN, priority, and destination parameters:

static void fireJ1939Message(int32_t moduleNumber, int32_t msgid,
                             uint8_t* u8Buffer)
{
   userInput.nChannelNumber = userInput.nP6ChanNumber;
   check_status(naibrd_CAN_QueueTransmit_J1939(userInput.nCardIdx, moduleNumber,
      userInput.nChannelNumber, 0xFEBF, 0x7 /*Priority*/, 0xFF /*Destination*/,
      u8Buffer, userInput.nDataLength));
   check_status(naibrd_CAN_SetTxEnable(userInput.nCardIdx, moduleNumber,
      userInput.nChannelNumber, CAN_TX_ENABLE));
   Show_TxResult();
}

Repeated Transmit with Loop

To send multiple frames in sequence, enable the loop with LOOP (set to 1), set the loop count with LC, and optionally set the inter-frame delay with DLY (default 1000 ms). When you execute X, the sample transmits nLoopCount frames with the configured delay between each.

Listen for Received Messages (RX)

The Listen command applies the current bit timing, then spawns a background thread that continuously polls the Rx FIFO on all channels of the selected module. The thread calls showRxData(), which reads each channel’s Rx frame count and, when frames are available, calls naibrd_CAN_Receive() (CAN A/B) or naibrd_CAN_Receive_J1939() (J1939) to dequeue and display the data:

if (IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1))
   check_status(naibrd_CAN_Receive(userInput.nCardIdx, activeModuleNumber,
      nChan, nBufLength, &bIsModeA, &nMsgId, unMsg, &nLength));
else if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
   check_status(naibrd_CAN_Receive_J1939(userInput.nCardIdx, activeModuleNumber,
      nChan, nBufLength, &nPGN, &nSource, &nDest, unMsg, &nLength));

The listener displays a table showing the module, channel, Rx FIFO count, Rx frame count, last error code, error passive/active status, Rx error count, and the received data bytes. Press Q to stop the listener thread and return to the configuration menu.

For interrupt-driven receive handling instead of polling, see CAN Interrupt Basic Sample Application.

Transmit and Receive (XR)

The XR command combines transmit and receive by applying bit timing and control word settings, then spawning a listener thread while the main thread remains available for input. This is useful for loopback testing where the same module transmits and receives. This command is available on Linux and VxWorks platforms.

Transmit on Multiple Channels (XM)

The XM command transmits on all channels of the selected module (or all CAN modules if module is set to 0). It fills each channel’s buffer with an 8-byte pattern ('1' through '8') and fires messages on every channel in sequence. This is useful for stress-testing multi-channel setups.

Copy Configuration to All Channels (COPY)

The COPY command applies the current bit-timing and control-word settings to every channel on the selected module (or all CAN modules). It first writes bit timing to all channels, then enables the control register on all channels. This two-pass approach ensures all channels have valid timing before Tx/Rx is enabled:

/* First pass: set bit timing on all channels */
for (chanIdx = 0; chanIdx < maxChannels; chanIdx++)
   check_status(naibrd_CAN_SetBitTiming(userInput.nCardIdx, activeModuleNumber,
      chanIdx + 1, userInput.nPreScaler, userInput.nSJW,
      userInput.nTseg1, userInput.nTseg2));

/* Second pass: enable control register on all channels */
for (chanIdx = 0; chanIdx < maxChannels; chanIdx++)
   check_status(naibrd_CAN_SetControlRaw(userInput.nCardIdx, activeModuleNumber,
      chanIdx + 1, userInput.nCtrlWord));

Register Read/Write Test (RW)

The RW command is a low-level diagnostic that performs 100,000 write-then-read-back cycles on a set of CAN module registers. It verifies data integrity by comparing each read value to the written value and reports any mismatches. This is primarily useful for validating board-to-host communication, not for normal CAN operations.

Ethernet Transmit Test (ETH)

The ETH command sends a test string over a TCP socket connection. This is a network diagnostic utility, not a CAN bus operation. It is available on Linux and VxWorks platforms only.

Show Configuration

Before each transmit operation, the sample displays a configuration summary table showing the current module, channel, mode, control word, acceptance mask/code, bit timing parameters, calculated baud rate, and Tx/Rx FIFO counts. This is done by calling the corresponding naibrd_CAN_Get*() API functions:

check_status(naibrd_CAN_GetControlRaw(userInput.nCardIdx, activeModuleNumber,
   userInput.nChannelNumber, &can_ctrl));
check_status(naibrd_CAN_GetAcceptMask(userInput.nCardIdx, activeModuleNumber,
   userInput.nChannelNumber, DEF_ACCEPTANCE_FILTER, &nValue));
check_status(naibrd_CAN_GetAcceptCode(userInput.nCardIdx, activeModuleNumber,
   userInput.nChannelNumber, DEF_ACCEPTANCE_FILTER, &nValue));
check_status(naibrd_CAN_GetBitTiming(userInput.nCardIdx, activeModuleNumber,
   userInput.nChannelNumber, &nValue, &nValue2, &nValue3, &nValue4));
check_status(naibrd_CAN_GetTxBufferCount(userInput.nCardIdx, activeModuleNumber,
   userInput.nChannelNumber, &nValue));
check_status(naibrd_CAN_GetRxBufferCount(userInput.nCardIdx, activeModuleNumber,
   userInput.nChannelNumber, &nValue));

Show Transmit Results

After each transmission, Show_TxResult() displays per-channel status including Tx FIFO count, Tx frame count, Rx FIFO count, Rx frame count, last error code, error passive/active status, and Tx/Rx error counts. These values are retrieved via:

  • naibrd_CAN_GetTxBufferCount() / naibrd_CAN_GetRxBufferCount() — FIFO occupancy.

  • naibrd_CAN_GetTxFrameCount() / naibrd_CAN_GetRxFrameCount() — cumulative frame counters.

  • naibrd_CAN_GetLastError() — last error code on the channel.

  • naibrd_CAN_GetErrorCount() — error passive/active state, Tx error count, Rx error count.

Important

Common Errors

  • Tx FIFO count not decrementing — the channel may not have a valid bus connection. Check cabling and ensure at least one other node is acknowledging frames. A CAN transmitter that receives no ACK will retry indefinitely and enter error passive state.

  • Error passive state — when the Tx or Rx error counter exceeds 127, the node enters error passive mode. This typically indicates a physical bus problem (termination, wiring, baud mismatch).

  • Rx frame count is zero during Listen — ensure Rx is enabled in the control word (D2=1) and that another node is transmitting on the bus. If using acceptance filtering, verify the mask and code match the incoming message IDs.

Multi Transmit Mode

The Multi Transmit mode provides a streamlined configuration submenu for repeated transmissions with incrementing data. It shares the same underlying API calls as Single Transmit but adds an increment parameter.

Multi Transmit Configuration

The Multi Transmit configuration submenu supports: Module (M), Channel (C), Prescaler (P), SJW (S), Mode A/B (AB), TSEG1 (O), TSEG2 (T), Data (D), Data Length (DL), Loop Count (L), Increment Step (I), and Message Number (N).

Set Increment Step (I)

The increment step controls how the data value changes between successive transmissions in multi-transmit mode. Default is 1.

Note
The Multi Transmit Run function (CAN_MulitXmitRun) is a placeholder in the current SSK 1.x release and returns immediately. Use Single Transmit with loop enabled for repeated transmissions.

Troubleshooting Reference

This section summarizes common errors covered in the preceding sections. Consult your module’s manual for hardware-specific diagnostics.

Error / Symptom Possible Causes Suggested Resolution

No board found

Board not powered, incorrect interface or address in configuration file.

Verify power and physical connection. Check default_CANTx.txt settings.

Connection timeout

Incorrect network settings, firewall blocking traffic, IP mismatch.

Confirm Ethernet settings or PCI/PCIe bus configuration.

Invalid card or module index

Zero-based card index or one-based module index out of range.

Verify hardware slot population with the board menu.

Baud rate mismatch

Transmitter and receiver configured with different bit-timing parameters.

Ensure all nodes on the CAN bus use identical prescaler, SJW, TSEG1, and TSEG2 values.

Error passive state

Tx or Rx error counter exceeded 127 due to bus errors.

Check physical wiring, termination resistors, and baud rate consistency across all nodes.

No data received (Listen shows nothing)

Rx not enabled in control word, no transmitting node on bus, acceptance filter rejecting all messages.

Set control word D2=1 (Rx enable). Verify bus connectivity. Set acceptance mask to 0xFFFFFFFF to pass all messages.

Tx FIFO not draining

No ACK from any other node on the bus; transmitter retrying indefinitely.

Connect at least one other CAN node or use a loopback cable. Check termination.

Data length error

Data length set to 0 or greater than 8.

CAN 2.0 frames support 1—​8 bytes. Set a valid data length with the L command.

NAI_ERROR_NOT_SUPPORTED

Attempting an operation not supported by the installed module variant.

Verify module type. Mode A/B selection is not available on J1939-only modules (CB2).

Register read/write mismatch

Communication integrity failure between host and module.

Check board connection type and cable quality. Run RW diagnostic to isolate the issue.

Full Source

Full Source — CAN_Interactive.c (SSK 1.x)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined (LINUX)
#include <ctype.h>
#include <pthread.h>
/*for ethernet code*/
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#endif
#if defined (__VXWORKS__)
#include "inetLib.h"
#include <netdb.h>
#endif
/*Specified to CAN Transmit*/
#include "CAN_Interactive.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"

/* Common CAN Sample Program include files */
#include "nai_can_cfg.h"

/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_can.h"
#include "naibrd_ether.h"
#include "advanced/nai_ether_adv.h"

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

/* Function prototypes */
#define DEF_CAN_CARD_INDEX                 0
#define DEF_CAN_MODULE                     1
#define DEF_CAN_TX_CHANNEL                 1

#define CAN_ALL_MODULES_INDICATOR          0
#define CAN_DEFAULT_MODULE                 1

static struct _userInput
{
   uint32_t nAcceptanceMask;
   uint32_t nAcceptanceCode;
   uint32_t nDelay_Ms;
   uint8_t nRepeat;
   uint8_t nUseDataPattern;
   int32_t nCardIdx;
   int32_t nModuleNumber;
   int32_t nChannelNumber;
   int32_t nP6ChanNumber;
   int32_t nPreScaler;
   int32_t nSJW;
   int32_t nModeAB;
   int32_t nTseg1;
   int32_t nTseg2;
   int32_t nData;
   int32_t nDataLength;
   int32_t nLoopCount;
   int32_t nIncrement;
   int32_t nMsgNumber;
   int32_t nRealTimeMsgNum;
   uint16_t nCtrlWord;
   int8_t n8UserThreadEscapeKey;
   int32_t nRxMsgCounter;
   union
   {
      uint16_t n16DataArray;
      struct
      {
         uint8_t loByte;
         uint8_t hiByte;
      } nBytes;
   } nDataArray[4];
}userInput;

/****** static function *******/
static void CAN_SetSingleXmit();
static void CAN_SetMultiXmit();
static void Run_CAN_TransmitByChoice();
static void Show_CanDemoFunc_Commands();
static void Show_CanSingleXmitFunc_Commands();
static void Show_CanMultiXmitFunc_Commands();
static void CAN_SingleXmitConfig();
static void CAN_SingleXmitRun();
static void CAN_MultiXmitConfig();
static void CAN_MulitXmitRun();
static void CAN_SetModule();
static void CAN_SetChan();
static void CAN_SetPreScaler();
static void CAN_SetSJW();
static void CAN_SetModeAB();
static void CAN_SetTseg1();
static void CAN_SetTseg2();
static void CAN_SetData();
static void CAN_SetDataPattern();
static void Show_CanSingleXmitConfigSubMenuFunc_Commands();
static void Show_CanMultiXmitConfigSubMenuFunc_Commands();
static void CAN_SetDataLength();
static void CAN_SetMessageNumber();
static void CAN_SetDataLoopCount();
static void CAN_SetIncrement();
static void Show_CanConfiguration();
static void fillTxBuffer(uint8_t *u8Buffer);
static void Show_TxResult();
static void setCanBitTiming();
static void setCanControlRegister();
static void CAN_SetDataPatternEnable();
static void CAN_SetDelay();
static void CAN_SetLoopEnable();
static void fireMessage(int32_t, int32_t, bool_t, uint8_t*);
static void fireJ1939Message(int32_t, int32_t, uint8_t*);
static void CAN_SetCtrlWord();
static uint16_t constructCanCtrlWord(const char*, uint8_t);
static uint32_t calcBaudRate(uint32_t unPreScaler, uint32_t unSJW, uint32_t unSetupTime, uint32_t unHoldTime);
static void CAN_SetAccMask();
static void CAN_SetAccCode();
static void CAN_Listen();
static void showRxData();
static uint32_t tcpTx(uint8_t *MsgBuf, int32_t MsgLeg);
static void basicReadWrite();
static void testEthernetTx();
static void testTxRx();
static void testTxMultiChan();
static void applyToAllCANChan();

/****** Command Table *******/
enum canFunc_MainMenuCommands
{
   CAN_FUNC_CMD_SINGLE_XMIT_MMENU,
   CAN_FUNC_CMD_MULTI_XMIT_MMENU,
   CAN_FUNC_CMD_COUNT
};

enum canFunc_singleXmitCommands
{
   CAN_FUNC_CMD_SINGLE_XMIT_MMENU_CONFIG,
   CAN_FUNC_CMD_SINGLE_XMIT_MMENU_RUN,
   CAN_FUNC_CMD_SINGLE_XMIT_MMENU_COUNT
};

enum canFunc_MultiXmitCommands
{
   CAN_FUNC_CMD_MULTI_XMIT_MMENU_CONFIG,
   CAN_FUNC_CMD_MULTI_XMIT_MMENU_RUN,
   CAN_FUNC_CMD_MULTI_XMIT_MMENU_COUNT
};

enum canFunc_singleXmitConfigSubMenuCommands
{
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_MODULE,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_CHAN,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_PRESCALER,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SJW,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_MODE_AB,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TSEG1,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TSEG2,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_CTRL_WORD,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_ACC_MASK,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_ACC_CODE,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_DATA,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_DATA_PATTERN,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_DATA_LENGTH,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_MSG_NUMBER,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_USE_DATA_PATTERN,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SET_DELAY,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SET_LOOP_ENABLE,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SET_LOOP_COUNT,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_LISTEN,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_RW,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TX,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_ETHERNET_TX,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TX_RX,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TX_MULTI_CHAN,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_COPY_ALL_CHAN,
   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_COUNT
};

enum canFunc_multiXmitConfigSubMenuCommands
{
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_MODULE,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_CHAN,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_PRESCALER,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_SJW,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_MODE_AB,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_TSEG1,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_TSEG2,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_DATA,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_DATA_LENGTH,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_LOOP_COUNT,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_INCREMENT,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_MSG_NUMBER,
   CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_COUNT
};

struct canDemofunc_cmdtbl {
   int8_t *cmdstr;
   int8_t *menustr;
   int32_t  cmdnum;
   void(*func)();
};

struct canDemofuncChannel_cmdtbl {
   int8_t *cmdstr;
   int8_t *menustr;
   int32_t  cmdnum;
   void(*func)(int32_t cardIndex, int32_t module, int32_t channel);
};

/****** Command Tables *******/
static struct canDemofunc_cmdtbl CAN_DemoFuncMenuCmds[] = {
   {(int8_t *)"S",   (int8_t *)"Single Xmit",          CAN_FUNC_CMD_SINGLE_XMIT_MMENU,          CAN_SetSingleXmit},\
   {(int8_t *)"M ",  (int8_t *)"Multi Xmit",           CAN_FUNC_CMD_MULTI_XMIT_MMENU,         CAN_SetMultiXmit},\
   {NULL,            NULL,                             0,                               NULL}
};

static struct canDemofunc_cmdtbl CAN_SingleXmitFuncMenuCmds[] = {
   {(int8_t *)"C",   (int8_t *)"CAN Configuration",    CAN_FUNC_CMD_SINGLE_XMIT_MMENU_CONFIG,   CAN_SingleXmitConfig},\
   {(int8_t *)"R ",  (int8_t *)"Run",                  CAN_FUNC_CMD_SINGLE_XMIT_MMENU_RUN,         CAN_SingleXmitRun},\
   {NULL,            NULL,                             0,                               NULL}
};

static struct canDemofunc_cmdtbl CAN_MultiXmitFuncMenuCmds[] = {
   {(int8_t *)"C",   (int8_t *)"CAN Configuration",    CAN_FUNC_CMD_MULTI_XMIT_MMENU_CONFIG,    CAN_MultiXmitConfig},\
   {(int8_t *)"R ",  (int8_t *)"Run",                 CAN_FUNC_CMD_MULTI_XMIT_MMENU_RUN,         CAN_MulitXmitRun},\
   {NULL,            NULL,                             0,                               NULL}
};

static struct canDemofunc_cmdtbl CAN_SingleXmitConfigSubMenuCmds[] = {
   {(int8_t *)"M",   (int8_t *)"Select Module",       CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_MODULE,              CAN_SetModule},\
   {(int8_t *)"C ",  (int8_t *)"Select Channel",      CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_CHAN,                CAN_SetChan},\
   {(int8_t *)"P ",  (int8_t *)"Prescaler",           CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_PRESCALER,           CAN_SetPreScaler},\
   {(int8_t *)"S ",  (int8_t *)"Sync Jump Width",     CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SJW,                 CAN_SetSJW},\
   {(int8_t *)"AB ", (int8_t *)"Mode A/B",            CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_MODE_AB,             CAN_SetModeAB},\
   {(int8_t *)"O",   (int8_t *)"T-Seg 1",             CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TSEG1,               CAN_SetTseg1},\
   {(int8_t *)"T",   (int8_t *)"T-Seg 2",             CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TSEG2,               CAN_SetTseg2},\
   {(int8_t *)"CW",  (int8_t *)"Ctrl Word",           CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_CTRL_WORD,           CAN_SetCtrlWord},\
   {(int8_t *)"AM",  (int8_t *)"Acceptance Mask",     CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_ACC_MASK,            CAN_SetAccMask},\
   {(int8_t *)"AC",  (int8_t *)"Acceptance Code",     CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_ACC_CODE,            CAN_SetAccCode},\
   {(int8_t *)"D",   (int8_t *)"Data",                CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_DATA,                CAN_SetData},\
   {(int8_t *)"DP",  (int8_t *)"Data Pattern",        CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_DATA_PATTERN,        CAN_SetDataPattern},\
   {(int8_t *)"L",   (int8_t *)"Data Length",         CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_DATA_LENGTH,         CAN_SetDataLength},\
   {(int8_t *)"N",   (int8_t *)"Message Number",      CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_MSG_NUMBER,          CAN_SetMessageNumber},\
   {(int8_t *)"UDP", (int8_t *)"Use Data Pattern",    CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_USE_DATA_PATTERN,    CAN_SetDataPatternEnable},\
   {(int8_t *)"DLY", (int8_t *)"Delay Between Tx",    CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SET_DELAY,           CAN_SetDelay},\
   {(int8_t *)"LOOP",(int8_t *)"Enable Loop",        CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SET_LOOP_ENABLE,     CAN_SetLoopEnable},\
   {(int8_t *)"LC",  (int8_t *)"Loop Counts",         CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SET_LOOP_COUNT,      CAN_SetDataLoopCount},\
   {(int8_t *)"RX",  (int8_t *)"Listen",              CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_LISTEN,              CAN_Listen},\
   {(int8_t *)"RW",  (int8_t *)"Read/Write",          CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_RW,                  basicReadWrite},\
   {(int8_t *)"X",   (int8_t *)"Transmit",            CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TX,                  CAN_SingleXmitRun},\
   {(int8_t *)"ETH", (int8_t *)"Eth Tx",              CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_ETHERNET_TX,         testEthernetTx},\
   {(int8_t *)"XR",  (int8_t *)"Transmit and Receive",CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TX_RX,               testTxRx},\
   {(int8_t *)"XM",  (int8_t *)"Tx Multiple Chan ",   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TX_MULTI_CHAN,       testTxMultiChan},\
   {(int8_t *)"COPY",(int8_t *)"Copy To All Chan ",   CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_COPY_ALL_CHAN,       applyToAllCANChan},\
   {NULL,            NULL,                            0,                               NULL}
};

static struct canDemofunc_cmdtbl CAN_MultiXmitConfigSubMenuCmds[] = {
   {(int8_t *)"M",   (int8_t *)"Select Module",       CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_MODULE,        CAN_SetModule},\
   {(int8_t *)"C ",  (int8_t *)"Select Channel",      CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_CHAN,          CAN_SetChan},\
   {(int8_t *)"P ",  (int8_t *)"Prescaler",           CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_PRESCALER,     CAN_SetPreScaler},\
   {(int8_t *)"S ",  (int8_t *)"Sync Jump Width",     CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_SJW,           CAN_SetSJW},\
   {(int8_t *)"AB ", (int8_t *)"Mode A/B",            CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_MODE_AB,       CAN_SetModeAB},\
   {(int8_t *)"O",   (int8_t *)"T-Seg 1",             CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_TSEG1,         CAN_SetTseg1},\
   {(int8_t *)"T",   (int8_t *)"T-Seg 2",             CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_TSEG2,         CAN_SetTseg2},\
   {(int8_t *)"D",   (int8_t *)"Data",                CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_DATA,          CAN_SetData},\
   {(int8_t *)"DL",  (int8_t *)"Data Length",         CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_DATA_LENGTH,   CAN_SetDataLength},\
   {(int8_t *)"L",   (int8_t *)"Loop Counts",         CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_LOOP_COUNT,    CAN_SetDataLoopCount},\
   {(int8_t *)"I",   (int8_t *)"Increment Step",      CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_INCREMENT,     CAN_SetIncrement},\
   {(int8_t *)"N",   (int8_t *)"Message Number",      CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_MSG_NUMBER,    CAN_SetMessageNumber},\
   {NULL,            NULL,                            0,                               NULL}
};

/***** Global Variables *****/
static bool_t globalQuit = FALSE;
static int32_t g_moduleCount = 0;

/**************************************************************************************************************/
/**
<summary>
CAN_Transmit_Interactive illustrates the following:

</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t CAN_Transmit_Interactive(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = FALSE;
   int32_t cardIndex;
   int32_t moduleCnt;
   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);
         /* Set global var userInput.nCardIdx */
         userInput.nCardIdx = cardIndex;
         if (stop != TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
            /* Set global var g_moduleCount */
            g_moduleCount = moduleCnt;
            /* Query the user for the module number */
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &userInput.nModuleNumber);
            if (stop != TRUE)
            {
               Run_CAN_TransmitByChoice();
            }
         }

         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;
}

void Run_CAN_TransmitByChoice(void)
{
   bool_t bQuit = FALSE;
   int32_t cmdIdx;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   do
   {
      if (globalQuit)
         break;

      Show_CanDemoFunc_Commands();
      printf("\nType CAN command or %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (!bQuit)
      {
         for (cmdIdx = 0; cmdIdx < CAN_FUNC_CMD_COUNT; cmdIdx++)
         {
            if (0 == naiapp_strnicmp((const int8_t*)inputBuffer, (const int8_t*)CAN_DemoFuncMenuCmds[cmdIdx].cmdstr, inputResponseCnt))
               break;
         }
         switch (cmdIdx)
         {
            case CAN_FUNC_CMD_SINGLE_XMIT_MMENU:
               CAN_SetSingleXmit();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_MMENU:
               CAN_SetMultiXmit();
               break;

            default:
               break;
         }
      }
   } while (bQuit == FALSE);

   if (bQuit)
      globalQuit = TRUE;

   return;
}

static void Show_CanDemoFunc_Commands(void)
{
   int i;
   printf("\n\t\t Can Transmit Demo Program.");
   printf("\n\t\t ==========================\n");
   printf("\n\nCommands");
   printf("\n--------");
   for (i = 0; i < CAN_FUNC_CMD_COUNT && CAN_DemoFuncMenuCmds[i].cmdstr != NULL; i++)
      printf("\n%s\t%s", CAN_DemoFuncMenuCmds[i].cmdstr, CAN_DemoFuncMenuCmds[i].menustr);
   printf("\n");
}

static void Show_CanSingleXmitFunc_Commands(void)
{
   int i;
   printf("\n\t\t CAN Single Transmit Demo Program.");
   printf("\n\t\t =================================\n");
   printf("\n\nCommands");
   printf("\n--------");
   for (i = 0; i < CAN_FUNC_CMD_SINGLE_XMIT_MMENU_COUNT && CAN_SingleXmitFuncMenuCmds[i].cmdstr != NULL; i++)
      printf("\n%s\t%s", CAN_SingleXmitFuncMenuCmds[i].cmdstr, CAN_SingleXmitFuncMenuCmds[i].menustr);
   printf("\n");
}

static void Show_CanMultiXmitFunc_Commands(void)
{
   int i;
   printf("\n\t\t CAN Multi Transmit Demo Program.");
   printf("\n\t\t ================================\n");
   printf("\n\nCommands");
   printf("\n--------");
   for (i = 0; i < CAN_FUNC_CMD_MULTI_XMIT_MMENU_COUNT && CAN_MultiXmitFuncMenuCmds[i].cmdstr != NULL; i++)
      printf("\n%s\t%s", CAN_MultiXmitFuncMenuCmds[i].cmdstr, CAN_MultiXmitFuncMenuCmds[i].menustr);
   printf("\n");
}

static void Show_CanSingleXmitConfigSubMenuFunc_Commands(void)
{
   int i;
   printf("\n\t\t CAN Single Transmit Configuration Menu.");
   printf("\n\t\t =======================================\n");
   printf("\n\nCommands");
   printf("\n--------");
   for (i = 0; i < CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_COUNT && CAN_SingleXmitConfigSubMenuCmds[i].cmdstr != NULL; i++)
      printf("\n%s\t%s", CAN_SingleXmitConfigSubMenuCmds[i].cmdstr, CAN_SingleXmitConfigSubMenuCmds[i].menustr);
   printf("\n");
}

static void Show_CanMultiXmitConfigSubMenuFunc_Commands(void)
{
   int i;
   printf("\n\t\t CAN Multi Transmit Configuration Menu.");
   printf("\n\t\t ======================================\n");
   printf("\n\nCommands");
   printf("\n--------");
   for (i = 0; i < CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_COUNT && CAN_MultiXmitConfigSubMenuCmds[i].cmdstr != NULL; i++)
      printf("\n%s\t%s", CAN_MultiXmitConfigSubMenuCmds[i].cmdstr, CAN_MultiXmitConfigSubMenuCmds[i].menustr);
   printf("\n");
}

static void CAN_SetSingleXmit()
{
   bool_t bQuit = FALSE;
   int32_t cmdIdx;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   do
   {
      if (globalQuit)
         break;

      Show_CanSingleXmitFunc_Commands();
      printf("\nType CAN Single Transmit or %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (!bQuit)
      {
         for (cmdIdx = 0; cmdIdx < CAN_FUNC_CMD_SINGLE_XMIT_MMENU_COUNT; cmdIdx++)
         {
            if (0 == naiapp_strnicmp((const int8_t*)inputBuffer, (const int8_t*)CAN_SingleXmitFuncMenuCmds[cmdIdx].cmdstr, inputResponseCnt))
               break;
         }
         switch (cmdIdx)
         {
            case CAN_FUNC_CMD_SINGLE_XMIT_MMENU_CONFIG:
               CAN_SingleXmitConfig();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_MMENU_RUN:
               CAN_SingleXmitRun();
               break;

            default:
               break;
         }
      }
   } while (bQuit == FALSE);

   if (bQuit)
      globalQuit = TRUE;

   return;

}
static void CAN_SetMultiXmit()
{
   bool_t bQuit = FALSE;
   int32_t cmdIdx;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   do
   {
      Show_CanMultiXmitFunc_Commands();
      printf("\nType CAN Multi Transmit or %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (!bQuit)
      {
         for (cmdIdx = 0; cmdIdx < CAN_FUNC_CMD_MULTI_XMIT_MMENU_COUNT; cmdIdx++)
         {
            if (0 == naiapp_strnicmp((const int8_t*)inputBuffer, (const int8_t*)CAN_MultiXmitFuncMenuCmds[cmdIdx].cmdstr, inputResponseCnt))
               break;
         }
         switch (cmdIdx)
         {
            case CAN_FUNC_CMD_MULTI_XMIT_MMENU_CONFIG:
               CAN_MultiXmitConfig();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_MMENU_RUN:
               CAN_MulitXmitRun();
               break;

            default:
               break;
         }
      }
   } while (bQuit == FALSE);
   return;
}

static void CAN_SingleXmitConfig()
{
   bool_t bQuit = FALSE;
   int32_t cmdIdx;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   do
   {
      if (globalQuit)
         break;

      Show_CanSingleXmitConfigSubMenuFunc_Commands();
      printf("\nType CAN Single Transmit Configuration Selection or %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (!bQuit)
      {
         for (cmdIdx = 0; cmdIdx < CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_COUNT; cmdIdx++)
         {
            if (0 == naiapp_strnicmp((const int8_t*)inputBuffer, (const int8_t*)CAN_SingleXmitConfigSubMenuCmds[cmdIdx].cmdstr, inputResponseCnt))
               break;
         }
         switch (cmdIdx)
         {
            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_MODULE:
               CAN_SetModule();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_CHAN:
               CAN_SetChan();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_PRESCALER:
               CAN_SetPreScaler();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SJW:
               CAN_SetSJW();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_MODE_AB:
               CAN_SetModeAB();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TSEG1:
               CAN_SetTseg1();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TSEG2:
               CAN_SetTseg2();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_DATA:
               CAN_SetData();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_DATA_PATTERN:
               CAN_SetDataPattern();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_DATA_LENGTH:
               CAN_SetDataLength();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_MSG_NUMBER:
               CAN_SetMessageNumber();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_USE_DATA_PATTERN:
               CAN_SetDataPatternEnable();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SET_DELAY:
               CAN_SetDelay();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SET_LOOP_ENABLE:
               CAN_SetLoopEnable();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_SET_LOOP_COUNT:
               CAN_SetDataLoopCount();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_CTRL_WORD:
               CAN_SetCtrlWord();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_ACC_MASK:
               CAN_SetAccMask();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_ACC_CODE:
               CAN_SetAccCode();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_LISTEN:
               setCanBitTiming(); /*write user input to module*/
               CAN_Listen();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_RW:
               setCanBitTiming(); /*write user input to module*/
               basicReadWrite();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TX:
               setCanBitTiming(); /*write user input to module*/
               setCanControlRegister();
               CAN_SingleXmitRun();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_ETHERNET_TX:
               setCanBitTiming(); /*write user input to module*/
               setCanControlRegister();
               testEthernetTx();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TX_RX:
               setCanBitTiming(); /*write user input to module*/
               setCanControlRegister();
               testTxRx();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_TX_MULTI_CHAN:
               setCanBitTiming(); /*write user input to module*/
               setCanControlRegister();
               testTxMultiChan();
               break;

            case CAN_FUNC_CMD_SINGLE_XMIT_SUBMENU_COPY_ALL_CHAN:
               applyToAllCANChan();
               break;

            default:
               break;
         }

      }
   } while (bQuit == FALSE);

   if (bQuit)
      globalQuit = TRUE;

   return;
}

static void CAN_SingleXmitRun()
{
   int32_t nTestLoopCountIdx = 0;
   bool_t is_CAN_A = FALSE;
   uint8_t u8Buffer[8];
   int32_t msgid = 0;
   int32_t activeModuleNumber = CAN_DEFAULT_MODULE;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   Show_CanConfiguration();
   if (userInput.nModeAB == CAN_MODE_A)
      is_CAN_A = TRUE;

   memset(u8Buffer, 0x0, sizeof(u8Buffer));
   fillTxBuffer(u8Buffer);
   if (userInput.nRepeat == NO)
   {
      if (userInput.nMsgNumber == CAN_INCREMENT_AUTO)
         userInput.nRealTimeMsgNum++;
      msgid = userInput.nRealTimeMsgNum;

      if (IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1))
         fireMessage(activeModuleNumber, msgid, is_CAN_A, u8Buffer);
      else if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
         fireJ1939Message(activeModuleNumber, msgid, u8Buffer);
   }
   else
   {
      for (nTestLoopCountIdx = 0; nTestLoopCountIdx < userInput.nLoopCount; nTestLoopCountIdx++)
      {
         if (userInput.nMsgNumber == CAN_INCREMENT_AUTO)
         {
            msgid = userInput.nRealTimeMsgNum++;
         }

         if (IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1))
            fireMessage(activeModuleNumber, msgid, is_CAN_A, u8Buffer);
         else if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
            fireJ1939Message(activeModuleNumber, msgid, u8Buffer);

         printf("\nLoop Count:%d", nTestLoopCountIdx + 1);

#if defined(WIN32) || defined(__VXWORKS__)
         nai_msDelay(userInput.nDelay_Ms);
#else
         usleep(userInput.nDelay_Ms * 1000);
#endif
      }
   }
   return;
}

static void CAN_MultiXmitConfig()
{
   bool_t bQuit = FALSE;
   int32_t cmdIdx;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   do
   {
      if (globalQuit)
         break;

      Show_CanMultiXmitConfigSubMenuFunc_Commands();
      printf("\nType CAN Multi Transmit Configuration Selection or %c to quit : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (!bQuit)
      {
         for (cmdIdx = 0; cmdIdx < CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_COUNT; cmdIdx++)
         {
            if (0 == naiapp_strnicmp((const int8_t*)inputBuffer, (const int8_t*)CAN_MultiXmitConfigSubMenuCmds[cmdIdx].cmdstr, inputResponseCnt))
               break;
         }
         switch (cmdIdx)
         {
            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_MODULE:
               CAN_SetModule();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_CHAN:
               CAN_SetChan();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_PRESCALER:
               CAN_SetPreScaler();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_SJW:
               CAN_SetSJW();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_MODE_AB:
               CAN_SetModeAB();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_TSEG1:
               CAN_SetTseg1();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_TSEG2:
               CAN_SetTseg2();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_DATA:
               CAN_SetData();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_DATA_LENGTH:
               CAN_SetDataLength();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_LOOP_COUNT:
               CAN_SetDataLoopCount();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_INCREMENT:
               CAN_SetIncrement();
               break;

            case CAN_FUNC_CMD_MULTI_XMIT_CONFIG_SUBMENU_MSG_NUMBER:
               CAN_SetMessageNumber();
               break;

            default:
               break;
         }
      }
   } while (bQuit == FALSE);

   if (bQuit)
      globalQuit = TRUE;

   return;
}

static void CAN_MulitXmitRun()
{
   return;
}

static void CAN_SetModule()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter <<Module>> Number or %c to quit [[default = 1]] Use '0' to denote ALL CHANNELS : ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nModuleNumber = CAN_DEFAULT_MODULE;
      else
         userInput.nModuleNumber = atoi((const char *)inputBuffer);
   }
   return;
}
static void CAN_SetChan()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter <<Channel>> Number or %c to quit [[default = 1]]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nChannelNumber = 1;
      else
         userInput.nChannelNumber = atoi((const char *)inputBuffer);
   }
   userInput.nP6ChanNumber = userInput.nChannelNumber;
   return;
}
static void CAN_SetPreScaler()
{
   bool_t bQuit = FALSE;
   int32_t defaultPreScaler = PRESCALER_1MBit;
   int32_t activeModuleNumber = CAN_DEFAULT_MODULE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;


   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
      defaultPreScaler = PRESCALER_500K;

   printf("\nEnter CAN <<Pre-scaler>> or %c to quit [[default = 0x%02X]]: ", NAI_QUIT_CHAR, defaultPreScaler);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nPreScaler = defaultPreScaler;
      else
         userInput.nPreScaler = atoi((const char *)inputBuffer);
   }
   return;
}
static void CAN_SetSJW()
{
   bool_t bQuit = FALSE;
   int32_t defaultSJW = SJW_1MBit;
   int32_t activeModuleNumber = CAN_DEFAULT_MODULE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;


   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
      defaultSJW = SJW_500K;

   printf("\nEnter CAN <<SYNC Jump Width>> or %c to quit [[default = 0x%02X]]: ", NAI_QUIT_CHAR, defaultSJW);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nSJW = defaultSJW;
      else
         userInput.nSJW = atoi((const char *)inputBuffer);
   }
   return;
}
static void CAN_SetModeAB()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter CAN <<Mode A/B>> [A=0, B=1] or %c to quit [[default = A]]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nModeAB = 0;
      else
         userInput.nModeAB = atoi((const char *)inputBuffer);
   }
   return;
}
static void CAN_SetTseg1()
{
   bool_t bQuit = FALSE;
   int32_t defaultTSEG1 = TSEG1_1MBit;
   int32_t activeModuleNumber = CAN_DEFAULT_MODULE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
      defaultTSEG1 = TSEG1_500K;

   printf("\nEnter CAN Setup Time <<T-Seg1>> or %c to quit [[default = 0x%02X]]: ", NAI_QUIT_CHAR, defaultTSEG1);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nTseg1 = defaultTSEG1;
      else
         userInput.nTseg1 = atoi((const char *)inputBuffer);
   }
   return;
}
static void CAN_SetTseg2()
{
   bool_t bQuit = FALSE;
   int32_t defaultTSEG2 = TSEG2_1MBit;
   int32_t activeModuleNumber = CAN_DEFAULT_MODULE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
      defaultTSEG2 = TSEG2_500K;

   printf("\nEnter CAN Hold Time <<T-Seg2>> or %c to quit [[default =  0x%02X]]: ", NAI_QUIT_CHAR, defaultTSEG2);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nTseg2 = defaultTSEG2;
      else
         userInput.nTseg2 = atoi((const char *)inputBuffer);
   }
   return;
}

static void CAN_SetData()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter CAN Transmit <<Data>> in Hex (one byte only) or %c to quit [[default = 0x0]]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nData = 0;
      else
      {
         userInput.nData = naiapp_utils_HexStrToDecInt32((int8_t *)inputBuffer);
      }
   }
   return;
}

static void CAN_SetDataPattern()
{
   uint8_t uArrayCount = 0;
   uint8_t uCharDestCount = 0;
   uint8_t uCharSrcCount = 0;
   uint8_t uCharRemaining = 0;
   uint8_t u8SingleData[3];
   uint8_t u8Idx = 0;
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter CAN Transmit <<Data Pattern>> in Hex (8 Bytes Max.) or %c to quit.  Enter data as 0102 => 01 02: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);

   if (inputResponseCnt <= CAN_MAX_MODE_AB_DATA_LENGTH * 2)
   {
      uint16_t nActualData = 0;

      if (!bQuit)
      {
         if (inputResponseCnt == 0)
            userInput.nData = 0;
         else
         {
            uCharSrcCount = 0;
            for (u8Idx = 0; u8Idx < inputResponseCnt;)
            {
               uCharDestCount = 0;
               memset(u8SingleData, 0x0, sizeof(u8SingleData));
               uCharRemaining = (uint8_t)inputResponseCnt - u8Idx;
               uCharDestCount = 0;
               if (uCharRemaining >= 2)
               {
                  u8SingleData[uCharDestCount++] = inputBuffer[uCharSrcCount++];
                  u8SingleData[uCharDestCount++] = inputBuffer[uCharSrcCount++];
                  u8Idx += 2;
               }
               else
               {
                  u8SingleData[uCharDestCount++] = inputBuffer[uCharSrcCount++];
                  u8Idx++;
               }
               nActualData = (uint16_t)naiapp_utils_HexStrToDecInt32((int8_t *)u8SingleData);
               if (uArrayCount % 2 == 0)
                  userInput.nDataArray[uArrayCount / 2].nBytes.loByte = (uint8_t)nActualData;
               else
                  userInput.nDataArray[uArrayCount / 2].nBytes.hiByte = (uint8_t)nActualData;
               uArrayCount++;
            }
            userInput.nDataLength = uArrayCount;
         }
      }
   }
   else
      printf("\nCAN Transmit <<Data Pattern>> must be less than 8 Bytes");

   return;
}

static void CAN_SetDataLength()
{
   bool_t bQuit = FALSE;
   uint32_t nLength = 0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter CAN Transmit <<Data Length>> (Data Length must be 8 bytes or less!) or %c to quit [[default = 0x1]]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nDataLength = 1;
      else
      {
         nLength = atoi((const char *)inputBuffer);
         if ((nLength <= CAN_MAX_MODE_AB_DATA_LENGTH) && (nLength > CAN_DATA_LENGTH_ZERO))
         {
            userInput.nDataLength = nLength;
         }
         else
            printf("\nCAN Transmit <<Data Length>> Error.  Data Length Limit[1-8]");
      }
   }
   return;
}

static void CAN_SetDataLoopCount()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter CAN Transmit <<Loop Count>> or %c to quit [[default = 0x1]]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nLoopCount = 1;
      else
         userInput.nLoopCount = atoi((const char *)inputBuffer);
   }
   return;
}
static void CAN_SetIncrement()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter CAN Transmit Data <<Increment>> or %c to quit [[default = 0x1]]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nIncrement = 1;
      else
         userInput.nIncrement = atoi((const char *)inputBuffer);
   }
   return;
}

static void Show_CanConfiguration()
{
   nai_can_ctrl_t can_ctrl = 0;
   int32_t        nValue = 0;
   int32_t        nValue2 = 0;
   int32_t        nValue3 = 0;
   int32_t        nValue4 = 0;
   int32_t        activeModuleNumber = CAN_DEFAULT_MODULE;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   printf("\nModule      Channel     Mode A/B    Ctrl Word   Acceptance  Acceptance  Prescaler   SJW         TSeg1       TSeg2       Baud Rate   Tx FIFO     Rx FIFO     ");
   printf("\n                                                  Mask        Code                                                                   Count       Count      ");
   printf("\n----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------\n");
   /*Module*/
   printf("%-12d", activeModuleNumber);
   /*Channel*/
   printf("%-12d", userInput.nChannelNumber);
   /*Mode A/B*/
   if (userInput.nModeAB == 0)
      printf("%-12s", "A");
   else
      printf("%-12s", "B");
   /*Ctrl Word */
   check_status(naibrd_CAN_GetControlRaw(userInput.nCardIdx, activeModuleNumber, userInput.nChannelNumber, &can_ctrl));
   printf("0x%-10x", can_ctrl);
   /*Acceptance Mask */
   check_status(naibrd_CAN_GetAcceptMask(userInput.nCardIdx, activeModuleNumber, userInput.nChannelNumber, DEF_ACCEPTANCE_FILTER, &nValue));
   printf("0x%-10x", nValue);
   /*Acceptance Code */
   check_status(naibrd_CAN_GetAcceptCode(userInput.nCardIdx, activeModuleNumber, userInput.nChannelNumber, DEF_ACCEPTANCE_FILTER, &nValue));
   printf("0x%-10x", nValue);
   /*Prescaler */
   check_status(naibrd_CAN_GetBitTiming(userInput.nCardIdx, activeModuleNumber, userInput.nChannelNumber, &nValue, &nValue2, &nValue3, &nValue4));
   printf("0x%-10x", nValue);
   /*SJW */
   printf("0x%-10x", nValue2);
   /*Setup Time TSeg1 */
   printf("0x%-10x", nValue3);
   /*Hold Time TSeg2 */
   printf("0x%-10x", nValue4);
   /*Baud Rate */
   nValue = calcBaudRate(nValue, nValue2, nValue3, nValue4);
   printf("%-12d", nValue);
   /*Tx FIFO Count */
   check_status(naibrd_CAN_GetTxBufferCount(userInput.nCardIdx, activeModuleNumber, userInput.nChannelNumber, &nValue));
   printf("0x%-10d", nValue);
   /*Rx FIFO Count */
   check_status(naibrd_CAN_GetRxBufferCount(userInput.nCardIdx, activeModuleNumber, userInput.nChannelNumber, &nValue));
   printf("0x%-10d", nValue);
   printf("\n");
}

static void Show_TxResult()
{
   int32_t   moduleIdx = 0;
   uint8_t   u8ChanIdx = 0;
   uint8_t   u8Channel = 0;
   int32_t   nValue = 0;
   int32_t   nValue2 = 0;
   uint8_t   u8Value = 0;
   int32_t   startModuleIdx = 0;
   int32_t   endModuleIdx = g_moduleCount;
   int32_t   activeModuleNumber = 0;
   int32_t   maxChannels = 0;

   printf("\n\n\nSingle Data Transmission Result.\n");
   printf("=========================================================================================================================");
   printf("\nModule      Channel     Tx FIFO     Tx Frame    Rx FIFO     Rx Frame    Error       Error      Error       Error         ");
   printf("\n                        Count       Count       Count       Count       Code        Pass./Act. Cnt Tx      Cnt Rx        ");
   printf("\n----------  ----------  ----------  ----------  ----------  ----------  ----------  ---------- ----------  ----------  \n");

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
   {
      startModuleIdx = (userInput.nModuleNumber - 1);
      endModuleIdx = userInput.nModuleNumber;
   }

   for (moduleIdx = startModuleIdx; moduleIdx < endModuleIdx; moduleIdx++)
   {
      activeModuleNumber = (moduleIdx + 1);
      if (!IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1) &&
         !IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
         continue;

      maxChannels = naibrd_CAN_GetChannelCount(naibrd_GetModuleID(userInput.nCardIdx, activeModuleNumber));

      for (u8ChanIdx = 0; u8ChanIdx < maxChannels; u8ChanIdx++)
      {
         u8Channel = u8ChanIdx + 1;
         /*Module*/
         printf("%-12d", activeModuleNumber);
         /*Channel*/
         printf("%-12d", u8Channel);
         /*Tx FIFO Count*/
         check_status(naibrd_CAN_GetTxBufferCount(userInput.nCardIdx, activeModuleNumber, u8Channel, &nValue));
         printf("%-12d", nValue);
         /*Tx Frame Count*/
         check_status(naibrd_CAN_GetTxFrameCount(userInput.nCardIdx, activeModuleNumber, u8Channel, &nValue));
         printf("%-12d", nValue);
         /*Rx FIFO Count*/
         check_status(naibrd_CAN_GetRxBufferCount(userInput.nCardIdx, activeModuleNumber, u8Channel, &nValue));
         printf("%-12d", nValue);
         /*Rx Frame Count*/
         check_status(naibrd_CAN_GetRxFrameCount(userInput.nCardIdx, activeModuleNumber, u8Channel, &nValue));
         printf("%-12d", nValue);
         /*Last Error Code*/
         check_status(naibrd_CAN_GetLastError(userInput.nCardIdx, activeModuleNumber, u8Channel, &nValue));
         printf("0x%-10x", nValue);
         /*Error Count*/
         check_status(naibrd_CAN_GetErrorCount(userInput.nCardIdx, activeModuleNumber, u8Channel, &u8Value, &nValue, &nValue2));
         /*passive/active*/
         if (u8Value == CAN_ERROR_PASSIVE)
            printf("%-12s", u8PASSIVE);
         else
            printf("%-12s", u8ACTIVE);
         /*Tx Error Count*/
         printf("0x%-10x", nValue2);
         /*Rx Error Count*/
         printf("0x%-10x", nValue);
         printf("\n");
      }
   }
}

static uint32_t calcBaudRate(uint32_t unPreScaler, uint32_t unSJW, uint32_t unSetupTime, uint32_t unHoldTime)
{
   uint32_t  nBaudRate = 0;
   nBaudRate = (uint32_t)(CAN_MODULE_CLK / ((unPreScaler + 1) * (3 + unSJW + unSetupTime + unHoldTime)));
   return(nBaudRate);
}

static void CAN_SetMessageNumber()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter CAN Transmit Message Number <<Message Number>> in Hex or %c to quit [[default = 0x1(auto)]]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
      {
         userInput.nMsgNumber = CAN_INCREMENT_AUTO;
         userInput.nRealTimeMsgNum = 0;
      }
      else
      {
         userInput.nRealTimeMsgNum = userInput.nMsgNumber = naiapp_utils_HexStrToDecInt32((int8_t *)inputBuffer);
      }
   }
   return;

}

static void applyToAllCANChan()
{
   int32_t chanIdx;
   int32_t moduleIdx;
   int32_t startModuleIdx = 0;
   int32_t endModuleIdx = g_moduleCount;
   int32_t activeModuleNumber = 0;
   int32_t maxChannels = 0;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
   {
      startModuleIdx = (userInput.nModuleNumber - 1);
      endModuleIdx = userInput.nModuleNumber;
   }

   for (moduleIdx = startModuleIdx; moduleIdx < endModuleIdx; moduleIdx++)
   {
      activeModuleNumber = (moduleIdx + 1);
      if (!IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1) &&
         !IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
         continue;

      maxChannels = naibrd_CAN_GetChannelCount(naibrd_GetModuleID(userInput.nCardIdx, activeModuleNumber));

      for (chanIdx = 0; chanIdx < maxChannels; chanIdx++)
         check_status(naibrd_CAN_SetBitTiming(userInput.nCardIdx, activeModuleNumber, chanIdx + 1, userInput.nPreScaler, userInput.nSJW, userInput.nTseg1, userInput.nTseg2));
   }

   //Bit Timing must be set on all channels in use prior to enabling TX and RX (via the control register)
   for (moduleIdx = startModuleIdx; moduleIdx < endModuleIdx; moduleIdx++)
   {
      activeModuleNumber = (moduleIdx + 1);
      if (!IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1) &&
         !IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
         continue;

      maxChannels = naibrd_CAN_GetChannelCount(naibrd_GetModuleID(userInput.nCardIdx, activeModuleNumber));

      for (chanIdx = 0; chanIdx < maxChannels; chanIdx++)
         check_status(naibrd_CAN_SetControlRaw(userInput.nCardIdx, activeModuleNumber, chanIdx + 1, userInput.nCtrlWord));
   }
}

static void fillTxBuffer(uint8_t *u8Buffer)
{
   uint8_t uByteCount = 0;
   uint8_t u8Idx = 0;
   uint8_t *u8Ptr = u8Buffer;

   for (u8Idx = 0; u8Idx < userInput.nDataLength; u8Idx++)
   {
      if (userInput.nUseDataPattern == USE_DATA_PATTERN)
      {
         if (uByteCount % 2 == 0)
            *u8Ptr++ = userInput.nDataArray[uByteCount / 2].nBytes.loByte;
         else
            *u8Ptr++ = userInput.nDataArray[uByteCount / 2].nBytes.hiByte;
         uByteCount++;
      }
      else
         *u8Ptr++ = userInput.nData & 0xFF;
   }
}

static void setCanBitTiming()
{
   int32_t activeModuleNumber = CAN_DEFAULT_MODULE;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   check_status(naibrd_CAN_SetBitTiming(userInput.nCardIdx, activeModuleNumber, userInput.nChannelNumber, userInput.nPreScaler, userInput.nSJW, userInput.nTseg1, userInput.nTseg2));
   return;
}

static void setCanControlRegister()
{
   int32_t activeModuleNumber = CAN_DEFAULT_MODULE;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   check_status(naibrd_CAN_SetControlRaw(userInput.nCardIdx, activeModuleNumber, userInput.nChannelNumber, userInput.nCtrlWord));
   return;
}

static void CAN_SetDataPatternEnable()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter use Data Pattern <<DATA PATTERNS>> [0=No, 1=Yes] or %c to quit [[default = 0x1]]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nUseDataPattern = USE_DATA_PATTERN;
      else
         userInput.nUseDataPattern = (uint8_t)atoi((const char *)inputBuffer);
   }
   return;

}

static void CAN_SetDelay()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter Delay between Tx in mS. <<DELAY>> or %c to quit [[default = 1000ms]]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nDelay_Ms = DEFAULT_1000MS;
      else
         userInput.nDelay_Ms = atoi((const char *)inputBuffer);
   }
   return;

}

static void CAN_SetLoopEnable()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnable or Disable continue Tx. <<CONTINUE LOOP>> [0=No, 1=Yes] or %c to quit [[default = No(0)]]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nRepeat = NO;
      else
         userInput.nRepeat = (uint8_t)atoi((const char *)inputBuffer);
   }
   return;

}

static void fireMessage(int32_t moduleNumber, int32_t msgid, bool_t isCanA, uint8_t* u8Buffer)
{
   bool_t is_CAN_A = isCanA;

   userInput.nChannelNumber = userInput.nP6ChanNumber;
   check_status(naibrd_CAN_QueueTransmit(userInput.nCardIdx, moduleNumber, userInput.nChannelNumber, is_CAN_A, msgid, u8Buffer, userInput.nDataLength));
   check_status(naibrd_CAN_SetTxEnable(userInput.nCardIdx, moduleNumber, userInput.nChannelNumber, CAN_TX_ENABLE));
   Show_TxResult();
   return;
}

static void fireJ1939Message(int32_t moduleNumber, int32_t msgid, uint8_t* u8Buffer)
{
#if defined (WIN32)
   UNREFERENCED_PARAMETER(msgid);
#endif  /* WIN32 */

   userInput.nChannelNumber = userInput.nP6ChanNumber;
   check_status(naibrd_CAN_QueueTransmit_J1939(userInput.nCardIdx, moduleNumber, userInput.nChannelNumber, 0xFEBF, 0x7 /*Priority*/, 0xFF /*Destination*/, u8Buffer, userInput.nDataLength));
   check_status(naibrd_CAN_SetTxEnable(userInput.nCardIdx, moduleNumber, userInput.nChannelNumber, CAN_TX_ENABLE));
   Show_TxResult();
   return;
}

static void CAN_SetCtrlWord()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nSet CAN control word <<CONTROL WORD>> [Reset chan | Ebl std/ext | CAN A/B filter | Use Acceptance Code/Mask | Rx | Tx ] or %c to quit [[default = 000011]]: ", NAI_QUIT_CHAR);
   printf("\nReset chan(D15): Reset Channel [1=Clear Rx and Tx FIFO buffer]");
   printf("\nEbl std/ext(D5): Filter Std/Ext[0(and D4 is 1)=Only accept Ext Mode Msg, 1(and D4 is 1)=Only accept Std Mode Msg] ");
   printf("\nCAN A/B filter(D4): Use CAN-A/B filtering [0=Can't inhibit the acc filtering, 1=the filter Std/Ext bit D5 is used to filter receive msg]");
   printf("\nUse Acceptance Code/Mask(D3): Use Acceptance Mask/Code for Rx filtering [0=Don't use Acc Mask/Code, 1=Use Acc Mask/Code]");
   printf("\nRx(D2): Enable Rx[0=Disable, 1=Enable]");
   printf("\nTx(D0): Enable Tx[0=Disable, 1=Enable]\n");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nCtrlWord = 0x5;
      else
      {
         userInput.nCtrlWord = constructCanCtrlWord((const char *)inputBuffer, (uint8_t)inputResponseCnt);
      }
   }
   return;
}

static uint16_t constructCanCtrlWord(const char* userStr, uint8_t inputLength)
{
   uint8_t un8Idx = 0;
   uint16_t un16CtrlWord = 0;
   uint16_t un16Mask = 0x1;

   for (un8Idx = 0; un8Idx < inputLength; un8Idx++)
   {
      un16Mask = 0x1;
      if (*userStr > ASCII_1_HEX || *userStr < ASCII_0_HEX || inputLength != 6)
      {
         printf("Error Input String:%s", userStr);
      }
      else
      {
         switch (un8Idx)
         {
            case 0:
               un16Mask <<= ctrlWord_ResetChan_D15;
               if (*userStr == ASCII_1_HEX)
                  un16CtrlWord |= un16Mask;
               else
                  un16CtrlWord &= ~un16Mask;
               break;

            case 1:
               un16Mask <<= ctrlWord_Filter_STD_EXT_D5;
               if (*userStr == ASCII_1_HEX)
                  un16CtrlWord |= un16Mask;
               else
                  un16CtrlWord &= ~un16Mask;
               break;

            case 2:
               un16Mask <<= ctrlWord_UseCanA_B_Filter_D4;
               if (*userStr == ASCII_1_HEX)
                  un16CtrlWord |= un16Mask;
               else
                  un16CtrlWord &= ~un16Mask;
               break;

            case 3:
               un16Mask <<= ctrlWord_UseAcceptanceCode_D3;
               if (*userStr == ASCII_1_HEX)
                  un16CtrlWord |= un16Mask;
               else
                  un16CtrlWord &= ~un16Mask;
               break;

            case 4:
               un16Mask <<= ctrlWord_Rx_D2;
               if (*userStr == ASCII_1_HEX)
                  un16CtrlWord |= un16Mask;
               else
                  un16CtrlWord &= ~un16Mask;
               break;

            case 5:
               un16Mask <<= ctrlWord_Tx_D0;
               if (*userStr == ASCII_1_HEX)
                  un16CtrlWord |= un16Mask;
               else
                  un16CtrlWord &= ~un16Mask;
               break;
         }
         userStr++;
      }
   }
   return(un16CtrlWord);
}

static void CAN_SetAccMask()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nSet CAN acceptance mask <<ACC. MASK>> (32bit value) or %c to quit [default = 0x00000000]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nAcceptanceMask = 0x0;
      else
      {
         userInput.nAcceptanceMask = atoi((const char *)inputBuffer);
      }
   }
   return;
}

static void CAN_SetAccCode()
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nSet CAN acceptance code <<ACC. CODE>> (32bit value) or %c to quit [default = 0x00000000]: ", NAI_QUIT_CHAR);
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt == 0)
         userInput.nAcceptanceCode = 0x0;
      else
      {
         userInput.nAcceptanceCode = atoi((const char *)inputBuffer);
      }
   }
   return;
}

#if defined (WIN32)
DWORD WINAPI proc_MonitorRxBuffer(LPVOID param)
{
   bool_t bQuit = FALSE;
   (void)param;
   printf("\nBegin Monitoring Rx FIFO Buffer\n");

   do
   {
      if ((userInput.n8UserThreadEscapeKey == PROC_RX_BUFFER_ESCAPE_KEY_q) || (userInput.n8UserThreadEscapeKey == PROC_RX_BUFFER_ESCAPE_KEY_Q))
      {
         bQuit = TRUE;
         break;
      }
      else
      {
         showRxData();
      }
   } while (bQuit == FALSE);
   return(0);
}

#endif

#if defined (LINUX)
void proc_MonitorRxBuffer(void *ptr)
{
   bool_t bQuit = FALSE;
   printf("\nBegin Monitoring Rx FIFO Buffer\n");

   do
   {
      if ((userInput.n8UserThreadEscapeKey == PROC_RX_BUFFER_ESCAPE_KEY_q) || (userInput.n8UserThreadEscapeKey == PROC_RX_BUFFER_ESCAPE_KEY_Q))
      {
         bQuit = TRUE;
         break;
      }
      else
      {
         showRxData();
      }
   } while (bQuit == FALSE);
   pthread_exit(0); /* exit */
}
#endif

#if defined (__VXWORKS__)
void proc_MonitorRxBuffer(void)
{
   bool_t bQuit = FALSE;
   printf("\nBegin Monitoring Rx FIFO Buffer\n");

   do
   {
      if ((userInput.n8UserThreadEscapeKey == PROC_RX_BUFFER_ESCAPE_KEY_q) || (userInput.n8UserThreadEscapeKey == PROC_RX_BUFFER_ESCAPE_KEY_Q))
      {
         bQuit = TRUE;
         break;
      }
      else
      {
         nai_msDelay(userInput.nDelay_Ms);
         showRxData();
      }
   } while (bQuit == FALSE);
}

#endif
static void CAN_Listen()
{
#if defined (LINUX)
   pthread_t thread1;
#endif

   bool_t bQuit = FALSE;
   int32_t maxChannels = 0;
   int32_t activeModuleNumber = CAN_DEFAULT_MODULE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   maxChannels = naibrd_CAN_GetChannelCount(naibrd_GetModuleID(userInput.nCardIdx, activeModuleNumber));

   printf("\nCAN Rx <<RX>>.  Prints out what is in the RX FIFO buffer or %c to quit [[default = 0x00000000]]: ", NAI_QUIT_CHAR);
   printf("\nThis function will launch a thread to keep polling the FIFO RX buffer from channel 1-%d", maxChannels);
   userInput.n8UserThreadEscapeKey = 0;
   userInput.nRxMsgCounter = 0;
#if defined (WIN32)
   printf("\nCreated new thread!");
   CreateThread(NULL, 0, proc_MonitorRxBuffer, NULL, 0, NULL);
#elif defined (LINUX)
   pthread_create(&thread1, NULL, (void *)&proc_MonitorRxBuffer, NULL);
#elif defined (__VXWORKS__)
   taskSpawn("MonitorRxBuffer", 99, 0, 0x4000, (FUNCPTR)proc_MonitorRxBuffer, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
#endif

   do
   {
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (inputResponseCnt != 0)
      {
         userInput.n8UserThreadEscapeKey = inputBuffer[0];
#if defined (LINUX)
         pthread_join(thread1, NULL);
#endif
   }
} while (!bQuit);
return;
}

static void showRxData()
{

   int32_t nStatus = 0;
   int32_t nValue = 0;
   int32_t nValue2 = 0;
   bool_t bValue = 0;
   int32_t nChanIdx = 0;
   int32_t nChan = 0;
   bool_t  bIsModeA = TRUE;
   int32_t nMsgId = 0;
   int32_t nLength = 0;
   uint8_t unMsg[CAN_MAX_MSG_SIZE];
   int32_t nBufLength = CAN_MAX_MSG_SIZE;
   int32_t nRxFrameCnt = 0;
   int32_t moduleIdx = 0;
   int32_t nPGN = 0;
   int32_t nSource = 0;
   int32_t nDest = 0;
   uint8_t i = 0;
   int32_t   startModuleIdx = 0;
   int32_t   endModuleIdx = g_moduleCount;
   int32_t   activeModuleNumber = 0;
   int32_t   maxChannels = 0;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
   {
      startModuleIdx = (userInput.nModuleNumber - 1);
      endModuleIdx = userInput.nModuleNumber;
   }

   for (moduleIdx = startModuleIdx; moduleIdx < endModuleIdx; moduleIdx++)
   {
      activeModuleNumber = (moduleIdx + 1);
      if (!IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1) &&
         !IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
         continue;

      maxChannels = naibrd_CAN_GetChannelCount(naibrd_GetModuleID(userInput.nCardIdx, activeModuleNumber));
      for (nChanIdx = 0; nChanIdx < maxChannels; nChanIdx++)
      {
         nChan = nChanIdx + 1;

         nStatus = check_status(naibrd_CAN_GetRxFrameCount(userInput.nCardIdx, activeModuleNumber, nChan, &nRxFrameCnt));
         if (nStatus != 0)
            printf("\nerror!");

         if (nRxFrameCnt > 0)
         {
            memset(unMsg, 0x0, sizeof(unMsg));
            printf("\nCAN RX DATA\n");
            printf("=========================================================================================================================");
            printf("\nMsg Count   Module      Channel     Rx FIFO     Rx Frame    Error       Error      Error        Data                                 ");
            printf("\n                                    Count       Count       Code        Pass./Act. Cnt Rx                                            ");
            printf("\n----------  ----------  ----------  ----------  ----------  ----------  ---------- ----------   -------------------------------------  \n");
            /*Rx Msg Count*/
            printf("%-12d", ++userInput.nRxMsgCounter);
            /*Module*/
            printf("%-12d", activeModuleNumber);
            /*Channel*/
            printf("%-12d", nChan);
            /*Rx FIFO Count*/
            check_status(naibrd_CAN_GetRxBufferCount(userInput.nCardIdx, activeModuleNumber, nChan, &nValue));
            printf("%-12d", nValue);
            /*Rx Frame Count*/
            check_status(naibrd_CAN_GetRxFrameCount(userInput.nCardIdx, activeModuleNumber, nChan, &nValue));
            printf("%-12d", nValue);
            /*Last Error Code*/
            check_status(naibrd_CAN_GetLastError(userInput.nCardIdx, activeModuleNumber, nChan, &nValue));
            printf("0x%-10x", nValue);
            /*Error Count*/
            check_status(naibrd_CAN_GetErrorCount(userInput.nCardIdx, activeModuleNumber, nChan, &bValue, &nValue, &nValue2));
            /*passive/active*/
            if (bValue == CAN_ERROR_PASSIVE)
               printf("%-12s", u8PASSIVE);
            else
               printf("%-12s", u8ACTIVE);
            /*Rx Error Count*/
            printf("0x%-10x", nValue);

            /*Data*/
            if (IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1))
               check_status(naibrd_CAN_Receive(userInput.nCardIdx, activeModuleNumber, nChan, nBufLength, &bIsModeA, &nMsgId, unMsg, &nLength));
            else if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
               check_status(naibrd_CAN_Receive_J1939(userInput.nCardIdx, activeModuleNumber, nChan, nBufLength, &nPGN, &nSource, &nDest, unMsg, &nLength));

            for (i = 0; i < nLength; i++)
               printf("0x%-2x ", unMsg[i]);

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

static void basicReadWrite()
{
   int dataRegLength = 10;
   uint32_t address[] = { 0x1054, 0x1058, 0x105c, 0x1060, 0x1064, 0x1068, 0x106c, 0x1070, 0x1074, 0x1078 };
   uint32_t data = 0xa5a5a5a5;
   int32_t idx = 0;
   uint32_t result[10];
   uint32_t maxLoopCnt = 100000;
   uint32_t loopCntIdx = 0;
   uint32_t expectedValue = 0;
   int32_t  activeModuleNumber = CAN_DEFAULT_MODULE;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
      activeModuleNumber = userInput.nModuleNumber;

   for (loopCntIdx = 0; loopCntIdx < maxLoopCnt; loopCntIdx++)
   {
      for (idx = 0; idx < dataRegLength; idx++)
      {
         expectedValue = data + idx;
         naibrd_Write32(userInput.nCardIdx, activeModuleNumber, address[idx], 0, 1, 4, &expectedValue);
         naibrd_Read32(userInput.nCardIdx, activeModuleNumber, address[idx], 0, 1, 4, &result[idx]);
         if (expectedValue != result[idx])
         {
            printf("\nError: idx:%d, expected:%d, actual:%d", idx, expectedValue, result[idx]);
            break;
         }
      }
   }
   printf("\n***End***");
}

static void testEthernetTx()
{
   uint8_t testMsg[] = { "Hello" };
   int32_t testMsgLength = sizeof(testMsg);

   tcpTx(testMsg, testMsgLength);

}

static uint32_t tcpTx(uint8_t *MsgBuf, int32_t MsgLeg)
{
   (void)MsgBuf;
   (void)MsgLeg;

#if defined(LINUX) || defined(__VXWORKS__)
   int sd, rc, length = sizeof(int);
   struct sockaddr_in serveraddr;
   char buffer[CanBufferLength];
   char server[255];
   char temp;
   int totalcnt = 0;
   struct hostent *hostp;
   char data[100] = "This is a test string from client ";

   memset(data, 0x0, sizeof(data));
   strcpy(data, (char*)MsgBuf);
   if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
   {
      perror("Client-socket() error");
      exit(-1);
   }
   else
      printf("Client-socket() OK\n");
   strcpy(server, SERVER);
   memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
   serveraddr.sin_family = AF_INET;
   serveraddr.sin_port = htons(SERVPORT);
   if ((serveraddr.sin_addr.s_addr = inet_addr(server)) == (unsigned long)INADDR_NONE)
   {
      hostp = gethostbyname(server);
      if (hostp == (struct hostent *)NULL)
      {
         printf("HOST NOT FOUND --> ");
#if !defined (__VXWORKS__)
         printf("h_errno = %d\n", h_errno);
#else
         printf("h_errno = %d \n", errnoGet());
#endif
         printf("---This is a client program---\n");
         close(sd);
         exit(-1);
      }
      memcpy(&serveraddr.sin_addr, hostp->h_addr, sizeof(serveraddr.sin_addr));
   }
   if ((rc = connect(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0)
   {
      perror("Client-connect() error");
      close(sd);
      exit(-1);
   }
   else
      printf("Connection established...\n");
   printf("Sending some string to the server %s...\n", server);
   rc = write(sd, data, sizeof(data));
   if (rc < 0)
   {
      perror("Client-write() error");
      rc = getsockopt(sd, SOL_SOCKET, SO_ERROR, &temp, (socklen_t*)(&length));
      if (rc == 0)
      {
         errno = temp;
         perror("SO_ERROR was");
      }
      close(sd);
      exit(-1);
   }
   else
   {
      printf("Client-write() is OK\n");
      printf("String successfully sent \n");
      printf("Waiting the %s to echo back...\n", server);
   }
   totalcnt = 0;
   while (totalcnt < CanBufferLength)
   {
      rc = read(sd, &buffer[totalcnt], CanBufferLength - totalcnt);
      if (rc < 0)
      {
         perror("Client-read() error");
         close(sd);
         exit(-1);
      }
      else if (rc == 0)
      {
         printf("Server program has issued a close()\n");
         close(sd);
         exit(-1);
      }
      else
         totalcnt += rc;
   }
   printf("Client-read() is OK\n");
   printf("Echoed data from the server: %s\n", buffer);
   close(sd);
   exit(0);
#endif
   return 0;
}

static void testTxRx()
{
#if defined(LINUX) || defined(__VXWORKS__)
#if defined (LINUX)
   pthread_t thread_Tx;
#endif
   bool_t bQuit = FALSE;
   printf("\nCAN Transmit and Receive Threads <<TX RX>> or tyep %c to quit. ", NAI_QUIT_CHAR);
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   userInput.n8UserThreadEscapeKey = 0;
   userInput.nRxMsgCounter = 0;
#if defined (WIN32)
   printf("\nCreated new thread!");
   CreateThread(NULL, 0, proc_MonitorRxBuffer, NULL, 0, NULL);
#elif defined (LINUX)
   pthread_create(&thread_Tx, NULL, (void *)&proc_MonitorRxBuffer, NULL);
#elif defined (__VXWORKS__)
   taskSpawn("MonitorRxBuffer", 99, 0, 0x4000, (FUNCPTR)proc_MonitorRxBuffer, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
#endif

   do
   {
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (inputResponseCnt != 0)
      {
         userInput.n8UserThreadEscapeKey = inputBuffer[0];
#if defined (LINUX)
         pthread_join(thread_Tx, NULL);
#endif
      }
   } while (!bQuit);
#endif

   return;
}

static void testTxMultiChan()
{
   int32_t nTestLoopCountIdx = 0;
   bool_t is_CAN_A = FALSE;
   uint8_t u8Buffer[8];
   int32_t msgid = 0;
   uint8_t chanData[] = { '1','2','3','4','5','6','7','8' };
   int32_t chanIdx;
   int32_t moduleIdx;
   int32_t startModuleIdx = 0;
   int32_t endModuleIdx = g_moduleCount;
   int32_t activeModuleNumber = 0;
   int32_t maxChannels = 0;

   Show_CanConfiguration();
   if (userInput.nModeAB == CAN_MODE_A)
      is_CAN_A = TRUE;

   if (userInput.nMsgNumber == CAN_INCREMENT_AUTO)
      userInput.nRealTimeMsgNum++;
   msgid = userInput.nRealTimeMsgNum;

   if (userInput.nModuleNumber != CAN_ALL_MODULES_INDICATOR)
   {
      startModuleIdx = (userInput.nModuleNumber - 1);
      endModuleIdx = userInput.nModuleNumber;
   }

   for (nTestLoopCountIdx = 0; nTestLoopCountIdx < userInput.nLoopCount; nTestLoopCountIdx++)
   {
      for (moduleIdx = startModuleIdx; moduleIdx < endModuleIdx; moduleIdx++)
      {
         activeModuleNumber = (moduleIdx + 1);
         if (!IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1) &&
            !IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
            continue;

         maxChannels = naibrd_CAN_GetChannelCount(naibrd_GetModuleID(userInput.nCardIdx, activeModuleNumber));
         for (chanIdx = 0; chanIdx < maxChannels; chanIdx++)
         {
            userInput.nDataArray[0].nBytes.loByte = chanData[0];
            userInput.nDataArray[0].nBytes.hiByte = chanData[1];
            userInput.nDataArray[1].nBytes.loByte = chanData[2];
            userInput.nDataArray[1].nBytes.hiByte = chanData[3];
            userInput.nDataArray[2].nBytes.loByte = chanData[4];
            userInput.nDataArray[2].nBytes.hiByte = chanData[5];
            userInput.nDataArray[3].nBytes.loByte = chanData[6];
            userInput.nDataArray[3].nBytes.hiByte = chanData[7];
            userInput.nDataLength = 8;

            userInput.nChannelNumber = chanIdx + 1;
            userInput.nP6ChanNumber = chanIdx % 4 + 1;

            memset(u8Buffer, 0x0, sizeof(u8Buffer));
            fillTxBuffer(u8Buffer);
            if (userInput.nRepeat == NO)
            {
               if (userInput.nMsgNumber == CAN_INCREMENT_AUTO)
                  userInput.nRealTimeMsgNum++;
               msgid = userInput.nRealTimeMsgNum;

               if (IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1))
                  fireMessage(activeModuleNumber, msgid, is_CAN_A, u8Buffer);
               else if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
                  fireJ1939Message(activeModuleNumber, msgid, u8Buffer);
            }
            else
            {
               if (userInput.nMsgNumber == CAN_INCREMENT_AUTO)
                  msgid = userInput.nRealTimeMsgNum++;

               if (IsCAN_AB(userInput.nCardIdx, activeModuleNumber, 1))
                  fireMessage(activeModuleNumber, msgid, is_CAN_A, u8Buffer);
               else if (IsCAN_J1939(userInput.nCardIdx, activeModuleNumber, 1))
                  fireJ1939Message(activeModuleNumber, msgid, u8Buffer);

               printf("\nLoop Count:%d", nTestLoopCountIdx + 1);

#if defined(WIN32) || defined(__VXWORKS__)
               nai_msDelay(userInput.nDelay_Ms);
#else
               usleep(userInput.nDelay_Ms * 1000);
#endif
            }
         }
      }
   }

   return;
}

Help Bot

X