DIF Interrupts
Edit this on GitLab
DIF Interrupts Sample Application (SSK 1.x)
Overview
The DIF Interrupts sample application demonstrates how to configure and handle hardware interrupts on Differential I/O (DIF) modules using the NAI Software Support Kit (SSK 1.x). The sample covers two interrupt delivery mechanisms: standard (onboard ISR with status polling) and Ethernet IDR (Interrupt Driven Response, network-based). Both variants configure the same underlying interrupt types — BIT status, Lo-Hi transition, and Hi-Lo transition — and share similar module-level configuration code. The difference is only in how the interrupt notification reaches your application.
This sample supports the following DIF module types: D8, DF1, DF2, DF3, and the CMH combination module.
The sample ships as two separate executables:
-
DIF_Interrupts— standard interrupt delivery. Configures the channel for input, enables BIT, Lo-Hi, and Hi-Lo transition interrupts, and monitors for status changes via polling (whenRUN_ISRis not defined) or via a hardware ISR (whenRUN_ISRis defined). This guide focuses on the Ethernet-connected polling path, which is the default build configuration. -
DIF_EtherInterrupts— Ethernet IDR variant. Delivers interrupt notifications over the network using IDR commands. The board automatically reads status registers and sends the results to your application as TCP or UDP messages.
For basic DIF channel configuration (operating mode, I/O format, thresholds), see the DIF BasicOps sample application guide. For background on interrupt concepts — including edge vs. level triggering, interrupt vector numbering, steering architecture, and latency measurement — see the Interrupts API Guide.
Prerequisites
Before running this sample, make sure you have:
-
An NAI board with a DIF module installed (D8, DF1, DF2, DF3, or CMH).
-
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.
-
For the Ethernet IDR variant: a Gen4 or later board with an Ethernet connection.
How to Run
Launch either executable from your build output directory. On startup the application looks for a configuration file (default_DIF_Interrupts.txt for the standard variant, default_DIFEthInterrupts.txt for the Ethernet variant). 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, the application prompts you for a channel number and begins monitoring for interrupt events.
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 DIF. For details on board connection configuration, see the First Time Setup Guide. |
Both variants follow the standard SSK 1.x startup flow:
-
Call
naiapp_RunBoardMenu()to load a saved configuration file or present the interactive board menu. The configuration file 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. -
Query the user for card index with
naiapp_query_CardIndex(). -
Query the user for module number with
naiapp_query_ModuleNumber(). -
Retrieve the module ID with
naibrd_GetModuleID()to verify a DIF module is installed at the selected slot.
#if defined (__VXWORKS__)
int32_t DIF_Interrupts(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
uint32_t moduleID = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
if (stop != TRUE)
{
moduleID = naibrd_GetModuleID(cardIndex, module);
if (moduleID != 0)
{
Run_DIF_Interrupts(cardIndex, module, moduleID);
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
naiapp_access_CloseAllOpenCards();
return 0;
}
After retrieving the module ID, the Run_DIF_Interrupts() function validates that the selected module is actually a DIF type by calling naibrd_DIF_GetChannelCount(). If the function returns 0, the module is not a supported DIF type and the application prints an error message.
|
Important
|
Common connection errors you may encounter at this stage:
|
Interrupt Status Types
DIF modules expose four interrupt status types relevant to interrupt-driven applications. Each monitors a different hardware condition at the channel level. The standard variant (DIF_Interrupts) enables three of these; the Ethernet variant (DIF_EtherInterrupts) monitors all four via register reads.
BIT Status
NAI_DIF_STATUS_BIT_LATCHED
Built-In Test (BIT) status indicates a hardware fault detected by the module’s self-test circuitry. When the module detects a BIT failure on a channel, it sets the BIT status bit and, if enabled, raises an interrupt. BIT failures typically indicate wiring faults, open circuits, or module hardware issues.
Use BIT interrupts for health monitoring in systems where early fault detection is critical. Your handler should log the fault and take appropriate corrective action (alert the operator, switch to a backup channel, etc.).
Lo-Hi Transition
NAI_DIF_STATUS_LO_HI_TRANS_LATCHED
The module detects that the channel’s input signal transitioned from a low state to a high state. This is the differential I/O equivalent of a rising-edge event. The module sets the Lo-Hi transition status bit and, if enabled, raises an interrupt.
Use Lo-Hi transition interrupts when you need immediate notification of signal activation — for example, detecting when an external switch closes, a sensor triggers, or a discrete control signal asserts.
Hi-Lo Transition
NAI_DIF_STATUS_HI_LO_TRANS_LATCHED
The module detects that the channel’s input signal transitioned from a high state to a low state. This is the differential I/O equivalent of a falling-edge event.
Use Hi-Lo transition interrupts when you need to detect signal deactivation — for example, when an external switch opens or a control signal de-asserts. Combined with Lo-Hi interrupts, you can track both edges of a discrete signal for timing or state-change monitoring.
Overcurrent
NAI_DIF_STATUS_OVERCURRENT_LATCHED
The module detects that the channel’s output current exceeds the safe operating threshold. This status type is monitored by the Ethernet IDR variant’s register reads but is not explicitly enabled as a separate interrupt in the standard variant.
Use overcurrent monitoring in systems that drive external loads through DIF output channels. If overcurrent is detected, your application should disable the affected output to prevent hardware damage.
Consult your module’s manual for the complete list of DIF interrupt status types, threshold configuration, and the specific register layout for your module generation.
Channel Configuration
Before enabling interrupts, the channel must be configured for input operation. The Setup_DIF_Interrupt() function in the standard variant sets the operating mode and I/O format:
/* Setup the DIF channel to Input */
check_status(naibrd_DIF_SetOpMode(cardIndex, module, channel, NAI_DIF_MODE_STD_INPUT_OUTPUT));
check_status(naibrd_DIF_SetIOFormat(cardIndex, module, channel, NAI_DIF_IOFORMAT_INPUT));
To configure a DIF channel for interrupt monitoring in your own application, call naibrd_DIF_SetOpMode() with NAI_DIF_MODE_STD_INPUT_OUTPUT to set the channel to standard I/O mode, then call naibrd_DIF_SetIOFormat() with NAI_DIF_IOFORMAT_INPUT to configure it as an input. The channel must be in input mode to detect Lo-Hi and Hi-Lo transitions on external signals.
For other operating modes and format options (enhanced mode, output mode, PWM, pattern generation), see the DIF BasicOps sample application guide.
Clearing Status Before Enabling Interrupts
Always clear all latched status registers before enabling interrupts. Stale latched status from a previous run or power-on state will trigger an immediate spurious interrupt if not cleared. The clearing method differs by module generation.
D8 Modules (Read-to-Clear)
On D8 modules, the latched status registers are cleared by reading them. The sample reads each status type in a retry loop because the status is latched and may require two reads to fully clear:
if (ModuleID == NAI_MODULE_ID_D8)
{
/* Clear Status Register by reading the status 2 times because the status is latched */
retryCnt = 0;
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED,
(nai_status_bit_t *)&chanStatus));
while ((chanStatus != 0) && (retryCnt < 2))
{
naibrd_Wait(1000);
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED,
(nai_status_bit_t *)&chanStatus));
retryCnt++;
}
if (chanStatus != 0)
printf("ERROR: DIF Bit Status is set\n");
}
The same pattern is repeated for NAI_DIF_STATUS_LO_HI_TRANS_LATCHED and NAI_DIF_STATUS_HI_LO_TRANS_LATCHED. If the status is still set after two retries, the application prints an error — this typically indicates an active fault or signal condition that must be resolved before interrupt monitoring can proceed reliably.
DF1, DF2, DF3, and CMH Modules (Write-to-Clear)
On newer module generations (DF1, DF2, DF3, CMH), latched status registers are cleared by writing to the status register using naibrd_DIF_ClearStatus():
else if (ModuleID == NAI_MODULE_ID_DF1 || ModuleID == NAI_MODULE_ID_CMH)
{
/* Clear Status Register by writing to the bit in the status register */
retryCnt = 0;
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED,
(nai_status_bit_t *)&chanStatus));
while ((chanStatus != 0) && (retryCnt < 2))
{
check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED));
naibrd_Wait(1000);
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED,
(nai_status_bit_t *)&chanStatus));
retryCnt++;
}
if (chanStatus != 0)
printf("ERROR: DIF BIT Status is set\n");
}
The same pattern is repeated for Lo-Hi and Hi-Lo transition status types. In your own application, check which module type you are working with and use the appropriate clearing method. Using naibrd_DIF_ClearStatus() on a D8 module or read-to-clear on a DF1/CMH module will not clear the status correctly.
|
Important
|
Common Errors
|
Interrupt Configuration (Standard Variant)
After clearing status, the standard variant configures three interrupt properties for each status type: trigger mode, interrupt vector, and interrupt steering.
Trigger Mode (Edge vs. Level)
The trigger mode determines when the interrupt fires relative to the status change. The sample configures all three status types for level-triggered interrupts:
/* Set the Interrupt Type (Edge/Level) */
naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED,
NAI_DIF_LEVEL_INTERRUPT);
naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED,
NAI_DIF_LEVEL_INTERRUPT);
naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED,
NAI_DIF_LEVEL_INTERRUPT);
Level-triggered mode means the interrupt continues to assert as long as the status condition remains active. This ensures your application does not miss events, but it also means the interrupt will keep firing until you clear the status register. Edge-triggered mode fires once when the status bit transitions from 0 to 1, which is useful when you want a single notification per event.
For DIF transition interrupts, level-triggered mode is appropriate because the sample’s polling loop reads and clears the group status register on each iteration, which de-asserts the interrupt condition. For detailed theory on edge vs. level triggering, see the Interrupts API Guide.
Interrupt Vectors
Each status type is assigned a unique interrupt vector so the handler can identify which condition triggered the event:
#define DIF_BIT_INTERRUPT_VECTOR 0x20
#define DIF_LO_HI_TRANS_INTERRUPT_VECTOR 0x21
#define DIF_HI_LO_TRANS_INTERRUPT_VECTOR 0x22
/* Set the Interrupt Vectors for BIT, Lo-Hi and Hi-Lo Transition */
naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED,
DIF_BIT_INTERRUPT_VECTOR);
naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED,
DIF_LO_HI_TRANS_INTERRUPT_VECTOR);
naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED,
DIF_HI_LO_TRANS_INTERRUPT_VECTOR);
Note that naibrd_DIF_SetGroupInterruptVector() operates on a group basis (group 1 in this sample), not per-channel. All channels in the group share the same vector for a given status type. The group parameter is 1 for the first group of channels. If your module has more channels than fit in one group, consult your module’s manual for the group-to-channel mapping.
In the Ethernet IDR variant, all three status types share a single vector (NAI_DIF_INTERRUPT_VECTOR) because all are handled by one IDR definition.
Interrupt Steering
Interrupt steering determines how the interrupt signal is delivered from the module to your application:
/* Set the Interrupt Steering */
naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED,
NAIBRD_INT_STEERING_ON_BOARD_0);
naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED,
NAIBRD_INT_STEERING_ON_BOARD_0);
naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED,
NAIBRD_INT_STEERING_ON_BOARD_0);
The standard variant uses NAIBRD_INT_STEERING_ON_BOARD_0 for onboard interrupt delivery. The Ethernet IDR variant allows the user to choose between onboard (NAIBRD_INT_STEERING_ON_BOARD_1 for IDR) and offboard (NAIBRD_INT_STEERING_CPCI_APP).
The steering options are:
-
Onboard (
NAIBRD_INT_STEERING_ON_BOARD_0) — handled locally on the board’s processor. The ISR or polling loop runs directly on the board. -
Ethernet IDR (
NAIBRD_INT_STEERING_ON_BOARD_1) — triggers an Ethernet IDR response. The board’s onboard processor intercepts the interrupt and sends a notification over Ethernet. -
cPCI offboard (
NAIBRD_INT_STEERING_CPCI_APP) — routes the interrupt to the CompactPCI backplane host. -
PCIe offboard (
NAIBRD_INT_STEERING_PCIE_APP) — routes the interrupt to the PCIe host.
Enable Interrupts
After configuration, enable interrupt generation for each status type on the selected channel:
/* Enable BIT, Lo-Hi and Hi-Lo Transition Interrupts */
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel,
NAI_DIF_STATUS_BIT_LATCHED, TRUE));
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel,
NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, TRUE));
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel,
NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, TRUE));
naibrd_DIF_SetInterruptEnable() operates per-channel, unlike the vector and steering functions which operate per-group. This allows you to selectively enable interrupts on specific channels while sharing the same vector and steering configuration across the group.
|
Important
|
Common Errors
|
Status Polling (Standard Variant)
In the default build configuration (without RUN_ISR defined), the standard variant monitors for interrupts by polling the group status registers. The checkForStatusChange() function reads the raw group status for each status type and sets boolean flags when a change is detected:
static void checkForStatusChange(int cardIndex, int module)
{
uint32_t groupStatus;
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, (int32_t)1,
NAI_DIF_STATUS_BIT_LATCHED, (uint32_t *)&groupStatus));
if (groupStatus != 0)
{
irqDIFCount++;
receivedVector = DIF_BIT_INTERRUPT_VECTOR;
bReceivedBITInterrupt = TRUE;
}
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, (int32_t)1,
NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, (uint32_t *)&groupStatus));
if (groupStatus != 0)
{
irqDIFCount++;
receivedVector = DIF_LO_HI_TRANS_INTERRUPT_VECTOR;
bReceivedLoHiTransInterrupt = TRUE;
}
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, (int32_t)1,
NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, (uint32_t *)&groupStatus));
if (groupStatus != 0)
{
irqDIFCount++;
receivedVector = DIF_HI_LO_TRANS_INTERRUPT_VECTOR;
bReceivedHiLoTransInterrupt = TRUE;
}
}
naibrd_DIF_GetGroupStatusRaw() reads the raw group status register for the specified status type. The groupStatus value is a bitmask where each bit corresponds to a channel in the group. A non-zero value means one or more channels have the status condition active.
The main loop then checks the boolean flags and processes each interrupt type:
while (bContinue)
{
checkForStatusChange(cardIndex, module);
if (bReceivedBITInterrupt)
{
printf("DIF BIT Interrupt, Vector:0x%02X, DIF irqCount:%d\n", receivedVector, irqDIFCount);
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, (int32_t)1,
NAI_DIF_STATUS_BIT_LATCHED, (uint32_t *)&groupStatus));
printf("BIT Status = 0x%0X\n", groupStatus);
check_status(naibrd_DIF_ClearGroupStatusRaw(cardIndex, module, 1,
NAI_DIF_STATUS_BIT_LATCHED, groupStatus));
bReceivedBITInterrupt = FALSE;
}
if (bReceivedLoHiTransInterrupt)
{
printf("DIF Lo-Hi Transition Interrupt, Vector:0x%02X, DIF irqCount:%d\n",
receivedVector, irqDIFCount);
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, 1,
NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, (uint32_t *)&groupStatus));
printf("Lo-Hi Transition Status = 0x%0X\n", groupStatus);
check_status(naibrd_DIF_ClearGroupStatusRaw(cardIndex, module, 1,
NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, groupStatus));
bReceivedLoHiTransInterrupt = FALSE;
}
if (bReceivedHiLoTransInterrupt)
{
printf("DIF Hi-Lo Transition Interrupt, Vector:0x%02X, DIF irqCount:%d\n",
receivedVector, irqDIFCount);
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, 1,
NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, (uint32_t *)&groupStatus));
printf("Hi-Lo Transition Status = 0x%0X\n", groupStatus);
check_status(naibrd_DIF_ClearGroupStatusRaw(cardIndex, module, 1,
NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, groupStatus));
bReceivedHiLoTransInterrupt = FALSE;
}
}
The handler pattern for each status type is: read the group status to identify which channels are affected, display the status bitmask, and then clear the status using naibrd_DIF_ClearGroupStatusRaw() with the same bitmask. This write-back approach clears only the bits that were set, leaving other channels' status untouched.
In your own application, you would examine individual bits of the groupStatus value to determine which specific channels triggered the event. For example, if groupStatus is 0x05, channels 1 and 3 (bits 0 and 2) have the status condition active.
|
Important
|
Common Errors
|
Ethernet IDR Interrupt Handling
The Ethernet IDR (Interrupt Driven Response) variant (DIF_EtherInterrupts) delivers interrupt notifications over the network instead of through a local polling loop or hardware ISR. Use this approach when your application runs on a remote host connected via Ethernet, when a hardware ISR is not available or practical for your deployment, or when you want the board to automatically read status registers and package the results into TCP or UDP messages.
How the Ethernet IDR Mechanism Works
The Ethernet IDR mechanism works as follows:
-
Your application configures an IDR definition on the board that specifies: a trigger vector, a response IP address and port, a transport protocol (TCP or UDP), and a set of Ethernet commands (register reads/writes) to execute when the interrupt fires.
-
When the specified interrupt vector fires on the board, the board’s onboard processor automatically executes the pre-configured Ethernet commands — typically reading status registers and optionally clearing them.
-
The board packages the results of those commands into Ethernet messages and sends them to the configured IP address and port.
-
Your application runs a listener thread (TCP or UDP server) that receives and decodes these messages.
This approach eliminates the need for your host application to poll registers over the network. The board does the register reads locally (fast) and sends only the results over the network, reducing round-trips and latency.
Prerequisites
Ethernet IDR requires a Generation 4 or later board with Ethernet support. The application verifies this at startup before proceeding with IDR configuration:
bGen4DIFIDRCommands = SupportsGen4Ether(cardIndex);
If the check fails, the board’s firmware does not support the Gen4 Ethernet protocol and IDR commands will not work. You may need to update the board firmware.
IDR Configuration
The Ethernet variant prompts the user for the IDR response IP address and port (defaults: 192.168.1.100:52801), then builds and registers the IDR commands.
The InitDIFIDRCommands() function constructs three Ethernet commands that will be executed by the board when the interrupt fires:
static nai_status_t InitDIFIDRCommands(int32_t cardIndex, int32_t module, uint8_t commands[],
uint16_t *cmdcount, uint16_t *cmdlen, nai_intf_t boardInterface)
{
nai_status_t status = NAI_SUCCESS;
uint16_t msgIndex = 0;
uint16_t ethcmdlen = 0;
uint32_t moduleOffset;
status = check_status(naibrd_GetModuleOffset(cardIndex, module, &moduleOffset));
if (status == NAI_SUCCESS)
{
if (bGen4DIFIDRCommands)
{
/* First command: Read status registers */
MakeDIFReadRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, ðcmdlen, boardInterface);
msgIndex += ethcmdlen;
/* Second command: Write to clear status registers */
MakeDIFWriteRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, ðcmdlen, boardInterface);
msgIndex += ethcmdlen;
/* Third command: Read status registers again (verify clear) */
MakeDIFReadRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, ðcmdlen, boardInterface);
msgIndex += ethcmdlen;
}
}
return status;
}
The three commands form a read-clear-read sequence:
-
Read status registers —
MakeDIFReadRegsCommand()reads four consecutive status registers starting atNAI_DIF_GEN5_REG_BIT_LATCHED_STATUS_ADDwith a stride of0x10. This reads the BIT, Lo-Hi transition, Hi-Lo transition, and overcurrent latched status registers in a single operation. -
Write to clear status —
MakeDIFWriteRegsCommand()writes0x00FFFFFFto all four status registers, clearing all latched bits across all channels. -
Read status again — a second read confirms the status was successfully cleared.
The IDR is then registered and started:
/* Register the IDR configuration */
status = check_status(naibrd_Ether_SetIDRConfig(IDRcardIndex, (uint16_t)DEF_DIF_IDR_ID,
protocol, iplen, ip, port, NAI_DIF_INTERRUPT_VECTOR, cmdcount, cmdlength, commands));
/* Start the IDR */
status = check_status(naibrd_Ether_StartIDR(IDRcardIndex, (uint16_t)DEF_DIF_IDR_ID));
naibrd_Ether_SetIDRConfig() programs the board with the complete IDR definition: response IP address, port, protocol, interrupt vector, and the command payload. naibrd_Ether_StartIDR() activates the IDR so the board begins sending notifications when the configured vector fires.
Listener Thread
After starting the IDR and enabling interrupts, the Ethernet variant spawns a listener thread to receive the unprompted reply messages:
#if defined (__VXWORKS__)
taskSpawn("uprDIFHandler", 100, 0, 10000, (FUNCPTR)UPR_DIFEthInt_Handler, NULL, ...);
#elif defined (LINUX)
pthread_create(&interruptDIFThread, NULL, (void*)UPR_DIFEthInt_Handler, NULL);
#else /* Default Windows */
CreateThread(NULL, 0, UPR_DIFEthInt_Handler, NULL, 0, NULL);
#endif
The UPR_DIFEthInt_Handler thread creates either a TCP or UDP server socket (based on DEF_DIF_RESPONSE_PROTOCOL) bound to the configured response port. It then blocks on recv() or recvfrom(), waiting for incoming IDR messages from the board.
When a message arrives, the thread calls DecodeUPRDIFIDRMessages() to parse the raw bytes into individual Ethernet command responses, and DisplayDecodedDIFIDRResponse() to display each response’s sequence number, typecode, and data values.
Decoding IDR Responses
Each IDR message from the board contains one or more Ethernet command responses, delimited by Gen4 preamble/postamble markers. The ParseDIFIDRResponse() function extracts individual responses:
preamble = (response[startIndex] << 8) | response[startIndex+1];
if (preamble == ETHER_GEN4_PREAMBLE)
{
/* Copy bytes until postamble is found */
while (bContinueCopy)
{
postamble = (response[rspIndex] << 8) | response[rspIndex+1];
if (postamble == ETHER_GEN4_POSTAMBLE)
{
/* End of this response */
bContinueCopy = FALSE;
}
idr_response[idrIndex++] = response[rspIndex++];
}
}
The DisplayDecodedDIFIDRResponse() function then decodes each response header using nai_ether_DecodeMessageHeader() and displays:
-
Sequence number — contains the IDR ID and command index, allowing you to identify which IDR triggered the response and which command within the IDR this response corresponds to.
-
Typecode — identifies the response type (read register, write register, read block, etc.).
-
Data — for read responses, the register values are displayed as 32-bit hex values.
For the DIF IDR, you will see three responses per interrupt event: the initial status read (showing which channels have active status), the write acknowledgment (confirming the clear), and the verification read (confirming the status was cleared).
Stopping the IDR
When the user exits the application, the IDR must be stopped before closing the connection:
status = check_status(naibrd_Ether_StopIDR(cardIndex, (uint16_t)DEF_DIF_IDR_ID));
Always stop the IDR before closing the connection. If you close the connection without stopping the IDR, the board will continue sending messages to an address that is no longer listening.
|
Important
|
Common Ethernet IDR Errors
|
Troubleshooting Reference
This table summarizes common errors and symptoms covered in the sections above. For detailed context, refer to the relevant section. Consult your module’s manual for hardware-specific diagnostic procedures.
Debugging Interrupts That Are Not Firing
When interrupts are not being delivered, use this two-step approach to isolate the problem:
-
Check whether the status registers are changing. Call
naibrd_DIF_GetGroupStatusRaw()with the appropriate status type to read the latched group status. If the status bits are changing when the external signal transitions, the module is detecting events correctly — the issue is in your interrupt delivery path (steering, polling loop, or IDR configuration). -
If the status registers are NOT changing, the issue is at the hardware or channel configuration level. Verify that the channel is configured as an input (
NAI_DIF_IOFORMAT_INPUT), that the operating mode is set correctly (NAI_DIF_MODE_STD_INPUT_OUTPUT), and that a valid differential signal is present on the channel. For transition events, the signal must actually change state. Consult your module’s manual for signal level thresholds and wiring requirements.
| Error / Symptom | Possible Causes | Suggested Resolution |
|---|---|---|
No board found or connection timeout |
Board not powered, incorrect or missing configuration file, network issue |
Verify hardware is powered and connected. If the configuration file exists, check that it lists the correct interface and address. If it does not exist, the board menu will appear — configure and save your connection settings. |
Module not detected or channel count is 0 |
No DIF module installed at the selected slot, incorrect module number, or a non-DIF module is present |
Verify hardware configuration. |
Status not clearing on D8 modules |
Using write-to-clear on a D8 module, or active fault/signal condition |
D8 modules use read-to-clear. Read the status register twice with a delay. If status persists, resolve the underlying hardware condition. |
Status not clearing on DF1/CMH modules |
Using read-to-clear on a DF1/DF2/DF3/CMH module |
Use |
Spurious interrupts immediately after enable |
Stale latched status from previous run or power-on state |
Always clear all status registers before enabling interrupts. Use the retry loop pattern shown in the sample. |
No transition interrupts despite signal changes |
Channel not configured as input, wrong operating mode, signal below threshold |
Verify |
Ethernet IDR: no messages received |
Wrong response IP/port, firewall blocking, IDR not started |
Verify IP address and port match your listener. Confirm |
Ethernet IDR: "Gen4 not supported" |
Board firmware predates Generation 4 |
Update board firmware to Gen4 or later. |
Steering mismatch |
Steering set to wrong destination for the chosen delivery mechanism |
Match steering to where your application executes. Standard onboard: |
Full Source
The complete source for this sample is provided below for reference. The sections above explain each part in detail. This sample consists of two source files: the standard interrupt application and the Ethernet IDR variant.
Full Source — DIF_Interrupts.c (SSK 1.x)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_dif.h"
#include "advanced/nai_ether_adv.h"
static const int8_t *CONFIG_FILE = (int8_t *)"default_DIF_Interrupts.txt";
/* Function prototypes */
void Run_DIF_Interrupts(int32_t cardIndex, int32_t module, int32_t ModuleID);
void Cfg_DIF_Interrupt_Channel(int32_t cardIndex, int32_t module, uint32_t ModuleID, int32_t MaxChannel);
void Setup_DIF_Interrupt(int32_t cardIndex, int32_t module, uint32_t channel, uint32_t ModuleID);
#if !defined (RUN_ISR)
static void checkForStatusChange(int cardIndex, int module);
#endif
void MyDIFIsr(void* param,uint32_t vector);
uint32_t irqDIFCount = 0;
static uint32_t receivedVector = 0;
static bool_t bReceivedBITInterrupt = FALSE;
static bool_t bReceivedLoHiTransInterrupt = FALSE;
static bool_t bReceivedHiLoTransInterrupt = FALSE;
static const int32_t DEF_DIF_CHANNEL = 1;
#define DIF_BIT_INTERRUPT_VECTOR 0x20
#define DIF_LO_HI_TRANS_INTERRUPT_VECTOR 0x21
#define DIF_HI_LO_TRANS_INTERRUPT_VECTOR 0x22
/**************************************************************************************************************/
/**
<summary>
The purpose of the DIF_Interrupts is to illustrate the methods to call in the naibrd library to perform configuration
and handle DIF Interrupts.
The following system configuration routines from the nai_sys_cfg.c file are called to assist with the configuration
setup for this program prior to calling the naibrd DIF routines.
- ClearDeviceCfg
- QuerySystemCfg
- DisplayDeviceCfg
- GetBoardSNModCfg
- SaveDeviceCfg
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t DIF_Interrupts(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
uint32_t moduleID = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
if (stop != TRUE)
{
moduleID = naibrd_GetModuleID(cardIndex, module);
if (moduleID != 0)
{
Run_DIF_Interrupts(cardIndex, module, moduleID);
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
/**************************************************************************************************************/
/**
<summary>
Run_DIF_Interrupts prompts the user for the card, module and channel to use for the application and calls
Cfg_DIF_Interrupt_Channel if the card, module, channel is valid for as a discrete module.
</summary>
*/
/**************************************************************************************************************/
void Run_DIF_Interrupts(int32_t cardIndex, int32_t module, int32_t ModuleID)
{
int32_t MaxChannel;
MaxChannel = naibrd_DIF_GetChannelCount(ModuleID);
if (MaxChannel == 0)
{
printf(" *** Module selection not recognized as DIF module. ***\n\n");
}
else
{
Cfg_DIF_Interrupt_Channel(cardIndex, module, ModuleID, MaxChannel);
}
}
/**************************************************************************************************************/
/**
<summary>
Cfg_DIF_Interrupt_Channel querying the user for the channel to generate and handle DIF interrupts.
</summary>
*/
/**************************************************************************************************************/
void Cfg_DIF_Interrupt_Channel(int32_t cardIndex, int32_t module, uint32_t ModuleID, int32_t MaxChannel)
{
bool_t bQuit = FALSE;
bool_t bContinue = TRUE;
int32_t chan, defaultchan = 1;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
while (bContinue)
{
printf(" \r\n\r\n");
printf("Channel selection \r\n");
printf("================= \r\n");
defaultchan = DEF_DIF_CHANNEL;
bQuit = naiapp_query_ChannelNumber(MaxChannel, defaultchan, &chan);
printf("\nPress Enter to set up interrupts, Type %c to quit : ", NAI_QUIT_CHAR);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
Setup_DIF_Interrupt(cardIndex, module, chan, ModuleID);
}
else
bContinue = FALSE;
}
}
void Setup_DIF_Interrupt(int32_t cardIndex, int32_t module, uint32_t channel, uint32_t ModuleID)
{
bool_t bContinue = TRUE;
uint8_t chanStatus;
uint32_t groupStatus;
int32_t retryCnt = 0;
/* Setup the DIF channel to Input */
check_status(naibrd_DIF_SetOpMode(cardIndex, module, channel, NAI_DIF_MODE_STD_INPUT_OUTPUT));
check_status(naibrd_DIF_SetIOFormat(cardIndex, module, channel, NAI_DIF_IOFORMAT_INPUT));
/* Clear the Status register */
if (ModuleID == NAI_MODULE_ID_D8)
{
/* Clear Status Register by reading the status 2 times because the status is latched */
retryCnt = 0;
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, (nai_status_bit_t *)&chanStatus));
while ((chanStatus != 0) && (retryCnt < 2))
{
naibrd_Wait(1000);
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, (nai_status_bit_t *)&chanStatus));
retryCnt++;
}
if (chanStatus != 0)
printf("ERROR: DIF Bit Status is set\n");
retryCnt = 0;
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, (nai_status_bit_t *)&chanStatus));
while ((chanStatus != 0) && (retryCnt < 2))
{
naibrd_Wait(1000);
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, (nai_status_bit_t *)&chanStatus));
retryCnt++;
}
if (chanStatus != 0)
printf("ERROR: DIF Lo-Hi Transition Status is set\n");
retryCnt = 0;
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, (nai_status_bit_t *)&chanStatus));
while ((chanStatus != 0) && (retryCnt < 2))
{
naibrd_Wait(1000);
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, (nai_status_bit_t *)&chanStatus));
retryCnt++;
}
if (chanStatus != 0)
printf("ERROR: DIF Hi-Lo Transition Status is set\n");
}
else if (ModuleID == NAI_MODULE_ID_DF1 || ModuleID == NAI_MODULE_ID_CMH)
{
/* Clear Status Register by writing to the bit in the status register */
retryCnt = 0;
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, (nai_status_bit_t *)&chanStatus));
while ((chanStatus != 0) && (retryCnt < 2))
{
check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED));
naibrd_Wait(1000);
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, (nai_status_bit_t *)&chanStatus));
retryCnt++;
}
if (chanStatus != 0)
printf("ERROR: DIF BIT Status is set\n");
retryCnt = 0;
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, (nai_status_bit_t *)&chanStatus));
while ((chanStatus != 0) && (retryCnt < 2))
{
check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED));
naibrd_Wait(1000);
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, (nai_status_bit_t *)&chanStatus));
retryCnt++;
}
if (chanStatus != 0)
printf("ERROR: DIF Lo-Hi Transition Status is set\n");
retryCnt = 0;
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, (nai_status_bit_t *)&chanStatus));
while ((chanStatus != 0) && (retryCnt < 2))
{
check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED));
naibrd_Wait(1000);
check_status(naibrd_DIF_GetStatus(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, (nai_status_bit_t *)&chanStatus));
retryCnt++;
}
if (chanStatus != 0)
printf("ERROR: DIF Hi-Lo Transition Status is set\n");
}
#if defined (RUN_ISR)
/* Install the ISR */
naibrd_InstallISR(cardIndex, NAIBRD_IRQ_ID_ON_BOARD_0, (nai_isr_t)MyDIFIsr, NULL);
#endif
/* Set the Interrupt Type (Edge/Level) */
naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_LEVEL_INTERRUPT);
naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, NAI_DIF_LEVEL_INTERRUPT);
naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, NAI_DIF_LEVEL_INTERRUPT);
/* Set the Interrupt Vectors for BIT, Lo-Hi and Hi-Lo Transition */
naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED, DIF_BIT_INTERRUPT_VECTOR);
naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, DIF_LO_HI_TRANS_INTERRUPT_VECTOR);
naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, DIF_HI_LO_TRANS_INTERRUPT_VECTOR);
/* Set the Interrupt Steering */
naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0);
naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0);
naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0);
/* Enable BIT, Lo-Hi and Hi-Lo Transition Interrupts */
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, TRUE));
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, TRUE));
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, TRUE));
printf("\nType %c to quit : ", NAI_QUIT_CHAR);
while (bContinue)
{
#if !defined (RUN_ISR)
checkForStatusChange(cardIndex, module);
#endif
if (bReceivedBITInterrupt)
{
printf("DIF BIT Interrupt, Vector:0x%02X, DIF irqCount:%d\n", receivedVector, irqDIFCount);
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, (int32_t)1, NAI_DIF_STATUS_BIT_LATCHED, (uint32_t *)&groupStatus));
printf("BIT Status = 0x%0X\n", groupStatus);
check_status(naibrd_DIF_ClearGroupStatusRaw(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED, groupStatus));
bReceivedBITInterrupt = FALSE;
}
if (bReceivedLoHiTransInterrupt)
{
printf("DIF Lo-Hi Transition Interrupt, Vector:0x%02X, DIF irqCount:%d\n", receivedVector, irqDIFCount);
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, (uint32_t *)&groupStatus));
printf("Lo-Hi Transition Status = 0x%0X\n", groupStatus);
check_status(naibrd_DIF_ClearGroupStatusRaw(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, groupStatus));
bReceivedLoHiTransInterrupt = FALSE;
}
if (bReceivedHiLoTransInterrupt)
{
printf("DIF Hi-Lo Transition Interrupt, Vector:0x%02X, DIF irqCount:%d\n", receivedVector, irqDIFCount);
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, (uint32_t *)&groupStatus));
printf("Hi-Lo Transition Status = 0x%0X\n", groupStatus);
check_status(naibrd_DIF_ClearGroupStatusRaw(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, groupStatus));
bReceivedHiLoTransInterrupt = FALSE;
}
/*bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (bQuit)
{
bContinue = FALSE;*/
#if defined (RUN_ISR)
/* naibrd_UninstallISR(cardIndex); */
#endif
/*}*/
}
}
#if defined(WIN32) || defined(LINUX) || defined(__VXWORKS__)
#if defined (RUN_ISR)
/*****************************/
/* Interrupt Service Routine */
/*****************************/
void MyDIFIsr(void* param, uint32_t vector)
{
irqDIFCount++;
/* Determine what interrupt was received */
receivedVector = vector;
switch (vector)
{
case DIF_BIT_INTERRUPT_VECTOR:
bReceivedBITInterrupt = TRUE;
break;
case DIF_LO_HI_TRANS_INTERRUPT_VECTOR:
bReceivedLoHiTransInterrupt = TRUE;
break;
case DIF_HI_LO_TRANS_INTERRUPT_VECTOR:
bReceivedHiLoTransInterrupt = TRUE;
break;
default:
printf("Unknown Interrupt, Vector:0x%02X, DIF irqCount:%d\n", vector, irqDIFCount);
break;
}
}
#else
static void checkForStatusChange(int cardIndex, int module)
{
uint32_t groupStatus;
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, (int32_t)1, NAI_DIF_STATUS_BIT_LATCHED, (uint32_t *)&groupStatus));
if (groupStatus != 0)
{
irqDIFCount++;
receivedVector = DIF_BIT_INTERRUPT_VECTOR;
bReceivedBITInterrupt = TRUE;
}
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, (int32_t)1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, (uint32_t *)&groupStatus));
if (groupStatus != 0)
{
irqDIFCount++;
receivedVector = DIF_LO_HI_TRANS_INTERRUPT_VECTOR;
bReceivedLoHiTransInterrupt = TRUE;
}
check_status(naibrd_DIF_GetGroupStatusRaw(cardIndex, module, (int32_t)1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, (uint32_t *)&groupStatus));
if (groupStatus != 0)
{
irqDIFCount++;
receivedVector = DIF_HI_LO_TRANS_INTERRUPT_VECTOR;
bReceivedHiLoTransInterrupt = TRUE;
}
}
#endif
#endif
Full Source — DIF_EtherInterrupts.c (SSK 1.x)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_dif.h"
#include "naibrd_ether.h"
#include "advanced/nai_ether_adv.h"
#if defined (WIN32)
#include "maps/nai_map_dif.h"
#else
#include "nai_map_dif.h"
#endif
#if defined (WIN32)
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "Ws2_32.lib")
#pragma warning (disable:4127)
#elif (LINUX)
#include <sys/errno.h>
#include <pthread.h>
typedef int32_t SOCKET;
#define ZeroMemory(S, N) memset((S), 0, (N))
#define closesocket(SD) close(SD)
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define SD_RECEIVE 0
#define SD_SEND 1
#define SD_BOTH 2
#elif (__VXWORKS__)
#include <netinet/ip.h>
#define ZeroMemory(S, N) memset((S), 0, (N))
#define closesocket(SD) close(SD)
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define SD_RECEIVE 0
#define SD_SEND 1
#define SD_BOTH 2
#endif
static const int8_t *CONFIG_FILE = (int8_t *)"default_DIFEthInterrupts.txt";
/* Function prototypes */
static bool_t Run_DIF_EthInterrupt(int32_t cardIndex, int32_t module, uint32_t modid);
static bool_t QueryEthInterruptDIFIPAddr(void);
static nai_status_t InitDIFIDRCommands(int32_t cardIndex, int32_t module, uint8_t commands[], uint16_t *cmdcount, uint16_t *cmdlen, nai_intf_t boardInterface);
static void MakeDIFReadRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, uint8_t commands[], uint16_t *cmdlen, nai_intf_t boardInterface);
static void MakeDIFWriteRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, uint8_t commands[], uint16_t *cmdlen, nai_intf_t boardInterface);
static void CreateDIFIDRTCPServer(void);
static void CreateDIFIDRUDPServer(void);
static void DecodeUPRDIFIDRMessages(const uint8_t msg[], int32_t msgsize);
static bool_t ParseDIFIDRResponse(int32_t startIndex, int32_t rsparraysize, uint8_t response[], uint16_t *idrrsplen, int32_t idrrsparraysize, uint8_t idr_response[]);
static void DisplayDecodedDIFIDRResponse(uint16_t responselen, uint8_t response[]);
static bool_t bGen4DIFIDRCommands = FALSE;
#define DEF_DIF_IDR_ID 3
#define DEF_DIF_ETHER_CMD_COUNT 3
#define DEF_DIF_RESPONSE_PROTOCOL ETHER_GEN4_TCP_PROTOCOL
#define DEF_DIF_RESPONSE_IP_LEN ETHER_GEN4_IPv4_ADDR_LEN
static uint16_t DEF_DIF_RESPONSE_PORT = 52801;
static uint8_t DEF_DIF_RESPONSE_IP_ADDR[] = {192,168,1,100};
#if defined (__VXWORKS__)
int UPR_DIFEthInt_Handler( int Param );
#elif LINUX
pthread_t interruptDIFThread;
static void* UPR_DIFEthInt_Handler(void* lpParam );
#else /* Default Windows */
DWORD WINAPI UPR_DIFEthInt_Handler( LPVOID lpParam );
#endif
static int terminateDIFThread;
/*****************************************************************************/
#if defined (__VXWORKS__)
int32_t DIF_EtherInterrupts(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
uint32_t moduleID = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
if (stop != TRUE)
{
moduleID = naibrd_GetModuleID(cardIndex, module);
if (moduleID != 0)
{
Run_DIF_EthInterrupt(cardIndex, module, moduleID);
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
static bool_t Run_DIF_EthInterrupt(int32_t cardIndex, int32_t module, uint32_t modid)
{
bool_t bQuit = FALSE;
nai_status_t status;
int32_t MAX_CHANNELS = naibrd_DIF_GetChannelCount(modid);
int32_t channel;
uint8_t commands[MAX_ETHER_IDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT];
uint16_t cmdcount = 0;
uint16_t cmdlength = 0;
uint16_t protocol = DEF_DIF_RESPONSE_PROTOCOL;
uint16_t iplen = DEF_DIF_RESPONSE_IP_LEN;
uint16_t port;
uint8_t ip[DEF_DIF_RESPONSE_IP_LEN];
int32_t i;
nai_intf_t boardInterface=0;
naibrd_int_steering_t steering=0;
bool_t Query_steering= FALSE;
int32_t IDRcardIndex=0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
bGen4DIFIDRCommands = SupportsGen4Ether(cardIndex);
printf("Differential Channel Selection:");
bQuit = naiapp_query_ChannelNumber(MAX_CHANNELS, 1, &channel);
if (!bQuit)
bQuit = QueryEthInterruptDIFIPAddr();
if(!bQuit){
bQuit = QueryUserForOnboardOffboardInterrupts(&Query_steering);
}
if(Query_steering == TRUE)
{
IDRcardIndex = 0;
boardInterface = NAI_INTF_ONBOARD;
steering = NAIBRD_INT_STEERING_ON_BOARD_1;
}
else
{
IDRcardIndex = 0;
boardInterface = NAI_INTF_PCI;
steering = NAIBRD_INT_STEERING_CPCI_APP;
}
if (!bQuit)
{
if (bGen4DIFIDRCommands)
{
check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED));
check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED));
check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED));
check_status(naibrd_DIF_SetOpMode(cardIndex, module, channel, NAI_DIF_MODE_STD_INPUT_OUTPUT));
check_status(naibrd_DIF_SetIOFormat(cardIndex, module, channel, NAI_DIF_IOFORMAT_INPUT));
status = check_status(naibrd_Ether_ClearIDRConfig(IDRcardIndex,(uint16_t)DEF_DIF_IDR_ID));
InitDIFIDRCommands(IDRcardIndex, module, commands, &cmdcount, &cmdlength,boardInterface);
for (i = 0; i < DEF_DIF_RESPONSE_IP_LEN; i++)
ip[i] = DEF_DIF_RESPONSE_IP_ADDR[i];
port = DEF_DIF_RESPONSE_PORT;
status = check_status(naibrd_Ether_SetIDRConfig(IDRcardIndex,(uint16_t)DEF_DIF_IDR_ID,protocol,iplen,ip,port,NAI_DIF_INTERRUPT_VECTOR,cmdcount,cmdlength,commands));
if (status == NAI_SUCCESS)
{
printf("IDR ID = %d configured.\n", DEF_DIF_IDR_ID);
}
status = check_status(naibrd_Ether_StartIDR(IDRcardIndex, (uint16_t)DEF_DIF_IDR_ID));
if (status == NAI_SUCCESS)
{
printf("IDR ID = %d Started\n", DEF_DIF_IDR_ID);
}
check_status(naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_LEVEL_INTERRUPT));
check_status(naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, NAI_DIF_LEVEL_INTERRUPT));
check_status(naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, NAI_DIF_LEVEL_INTERRUPT));
check_status(naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_INTERRUPT_VECTOR));
check_status(naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, NAI_DIF_INTERRUPT_VECTOR));
check_status(naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, NAI_DIF_INTERRUPT_VECTOR));
check_status(naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED, steering));
check_status(naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, steering));
check_status(naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, steering));
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, TRUE));
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, TRUE));
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, TRUE));
terminateDIFThread = FALSE;
#if defined (__VXWORKS__)
taskSpawn("uprDIFHandler", 100, 0, 10000, (FUNCPTR)UPR_DIFEthInt_Handler, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
#elif defined (LINUX)
pthread_create(&interruptDIFThread, NULL, (void*)UPR_DIFEthInt_Handler, NULL);
#else /* Default Windows */
CreateThread( NULL, 0, UPR_DIFEthInt_Handler, NULL, 0, NULL );
#endif
while (!bQuit)
{
printf("Type %c to exit program : ", NAI_QUIT_CHAR);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (bQuit)
{
terminateDIFThread = TRUE;
status = check_status(naibrd_Ether_StopIDR(cardIndex, (uint16_t)DEF_DIF_IDR_ID));
if (status == NAI_SUCCESS)
{
printf("IDR ID = %d Stopped\n", DEF_DIF_IDR_ID);
}
}
}
}
else
{
printf("DIF Ethernet Interrupt Support Prior to Generation 4 Ethernet commands currently not supported\n");
bQuit = TRUE;
}
}
return bQuit;
}
static bool_t QueryEthInterruptDIFIPAddr(void)
{
bool_t bQuit = FALSE;
bool_t bContinue = TRUE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (!bQuit)
{
bContinue = TRUE;
while (bContinue)
{
printf("Please Enter IDR Response IP Address: [default=%d.%d.%d.%d]): ",
DEF_DIF_RESPONSE_IP_ADDR[0],DEF_DIF_RESPONSE_IP_ADDR[1],DEF_DIF_RESPONSE_IP_ADDR[2],DEF_DIF_RESPONSE_IP_ADDR[3]);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (bQuit)
bContinue = FALSE;
else
{
if (inputResponseCnt > NAI_MAX_IP_LEN)
printf("ERROR: Invalid IP Address.\n");
else
{
if (inputResponseCnt > 0)
ParseIPv4Address((char *)inputBuffer, DEF_DIF_RESPONSE_IP_ADDR);
}
}
if (!bQuit)
{
printf("Please Enter IDR Response Port: [default=%d]): ", DEF_DIF_RESPONSE_PORT);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (bQuit)
bContinue = FALSE;
else
{
if (inputResponseCnt > 0)
DEF_DIF_RESPONSE_PORT = (uint16_t)atol((const char *)inputBuffer);
bContinue = FALSE;
}
}
}
}
return bQuit;
}
static nai_status_t InitDIFIDRCommands(int32_t cardIndex, int32_t module, uint8_t commands[], uint16_t *cmdcount, uint16_t *cmdlen, nai_intf_t boardInterface)
{
nai_status_t status = NAI_SUCCESS;
uint16_t msgIndex = 0;
uint16_t idrcmdcnt = 0;
uint16_t ethcmdlen = 0;
uint16_t idrcmdlen = 0;
uint32_t moduleOffset;
status = check_status(naibrd_GetModuleOffset(cardIndex, module, &moduleOffset));
if (status == NAI_SUCCESS)
{
if (bGen4DIFIDRCommands)
{
MakeDIFReadRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, ðcmdlen, boardInterface);
msgIndex += ethcmdlen;
idrcmdlen += ethcmdlen;
idrcmdcnt++;
MakeDIFWriteRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, ðcmdlen, boardInterface);
msgIndex += ethcmdlen;
idrcmdlen += ethcmdlen;
idrcmdcnt++;
MakeDIFReadRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, ðcmdlen, boardInterface);
msgIndex += ethcmdlen;
idrcmdlen += ethcmdlen;
idrcmdcnt++;
*cmdcount = idrcmdcnt;
*cmdlen = msgIndex;
}
else
{
printf("DIF Ethernet Interrupt Support Prior to Generation 4 Ethernet commands currently not supported\n");
status = NAI_ERROR_NOT_SUPPORTED;
}
}
return status;
}
static void MakeDIFReadRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, uint8_t commands[], uint16_t *cmdlen, nai_intf_t boardInterface)
{
uint16_t msgIndex = startIndex;
uint16_t seqno;
uint32_t count, stride;
uint32_t regaddr;
if (bGen4Ether)
{
seqno = 0;
regaddr = moduleOffset + NAI_DIF_GEN5_REG_BIT_LATCHED_STATUS_ADD;
count = 4;
stride = 0x10;
msgIndex = (uint16_t)nai_ether_MakeReadMessage(&commands[startIndex],seqno,NAI_ETHER_GEN4,boardInterface,regaddr,stride,count,NAI_REG32);
*cmdlen = msgIndex;
}
}
static void MakeDIFWriteRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, uint8_t commands[], uint16_t *cmdlen, nai_intf_t boardInterface)
{
uint16_t msgIndex = startIndex;
uint16_t seqno;
uint32_t count, stride;
uint32_t regaddr;
uint32_t data[4] = {0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF};
if (bGen4Ether)
{
seqno = 0;
regaddr = moduleOffset + NAI_DIF_GEN5_REG_BIT_LATCHED_STATUS_ADD;
count = 4;
stride = 0x10;
msgIndex = (uint16_t)nai_ether_BeginWriteMessage(&commands[startIndex],seqno,NAI_ETHER_GEN4,boardInterface,regaddr,stride,count,NAI_REG32);
if (msgIndex >= 0)
{
msgIndex = (uint16_t)nai_ether_WriteMessageData(&commands[startIndex],msgIndex,NAI_REG32,&data,NAI_REG32,count);
if (msgIndex >= 0)
{
msgIndex = (uint16_t)nai_ether_FinishMessage(&commands[startIndex],msgIndex,NAI_ETHER_GEN4);
}
}
*cmdlen = msgIndex;
}
}
#if defined (__VXWORKS__)
int UPR_DIFEthInt_Handler( int32_t nParam )
{
#elif LINUX
static void* UPR_DIFEthInt_Handler(void *lpParam )
{
#else /* Default Windows */
DWORD WINAPI UPR_DIFEthInt_Handler( LPVOID lpParam )
{
#endif
uint16_t protocol = DEF_DIF_RESPONSE_PROTOCOL;
#if defined (WIN32)
UNREFERENCED_PARAMETER(lpParam);
#endif
printf("\nUnprompted Reply Thread Started....\n");
if (protocol == ETHER_GEN4_TCP_PROTOCOL)
CreateDIFIDRTCPServer();
else
CreateDIFIDRUDPServer();
printf("\nUnprompted Reply Thread Terminated\n");
return 0;
}
static void CreateDIFIDRTCPServer(void)
{
nai_socket_t listensock = INVALID_SOCKET, clientsock = INVALID_SOCKET;
struct addrinfo hints;
struct addrinfo *info;
char_t portbuf[10];
uint8_t recvbuf[NAI_ETHER_MAX_PACKET_SIZE_BYTES];
int32_t recvbuflen = NAI_ETHER_MAX_PACKET_SIZE_BYTES;
int32_t result;
#if defined (WIN32)
WSADATA wsaData;
result = WSAStartup(MAKEWORD(2,2), &wsaData);
if (result != 0)
{
printf("WSAStartup failed with error: %d\n", result);
return;
}
#endif
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
sprintf((char *)portbuf, "%d", DEF_DIF_RESPONSE_PORT);
#if defined (WIN32)
result = getaddrinfo(NULL, (PCSTR)portbuf, &hints, &info);
#elif defined(LINUX) || defined(__VXWORKS__)
result = getaddrinfo(NULL, portbuf, &hints, &info);
#endif
if ( result != 0 )
{
printf("getaddrinfo failed with error: %d\n", result);
#if defined (WIN32)
WSACleanup();
#endif
return;
}
listensock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
if (listensock == INVALID_SOCKET)
{
#if defined (WIN32)
printf("socket failed with error: %ld\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
printf("socket failed with error: %s\n", strerror(errno));
#endif
freeaddrinfo(info);
#if defined (WIN32)
WSACleanup();
#endif
return;
}
result = bind( listensock, info->ai_addr, (int)info->ai_addrlen);
if (result == SOCKET_ERROR)
{
#if defined (WIN32)
printf("bind failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
printf("bind failed with error: %s\n", strerror(errno));
#endif
freeaddrinfo(info);
closesocket(listensock);
#if defined (WIN32)
WSACleanup();
#endif
return;
}
freeaddrinfo(info);
result = listen(listensock, SOMAXCONN);
if (result == SOCKET_ERROR)
{
#if defined (WIN32)
printf("listen failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
printf("listen failed with error: %s\n", strerror(errno));
#endif
closesocket(listensock);
#if defined (WIN32)
WSACleanup();
#endif
return;
}
clientsock = accept(listensock, NULL, NULL);
if (clientsock == INVALID_SOCKET)
{
#if defined (WIN32)
printf("accept failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
printf("accept failed with error: %s\n", strerror(errno));
#endif
closesocket(listensock);
#if defined (WIN32)
WSACleanup();
#endif
return;
}
closesocket(listensock);
printf("Ready to receive a TCP messages...\n");
do
{
result = recv(clientsock, (char *)recvbuf, recvbuflen, 0);
if (result > 0)
{
printf("\n\nTCP Server: Bytes received: %d\n", result);
DecodeUPRDIFIDRMessages(recvbuf, result);
}
else if (result == 0)
printf("Connection closing...\n");
else
{
#if defined (WIN32)
printf("recv failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
printf("recv failed with error: %s\n", strerror(errno));
#endif
closesocket(clientsock);
#if defined (WIN32)
WSACleanup();
#endif
return;
}
} while ((result > 0) && (terminateDIFThread == FALSE));
result = shutdown(clientsock, SD_SEND);
if (result == SOCKET_ERROR)
{
#if defined (WIN32)
printf("shutdown failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
printf("shutdown failed with error: %s\n", strerror(errno));
#endif
closesocket(clientsock);
#if defined (WIN32)
WSACleanup();
#endif
return;
}
closesocket(clientsock);
#if defined (WIN32)
WSACleanup();
#endif
}
static void CreateDIFIDRUDPServer()
{
nai_socket_t recvsock;
uint8_t recvbuf[NAI_ETHER_MAX_PACKET_SIZE_BYTES];
int32_t recvbuflen = NAI_ETHER_MAX_PACKET_SIZE_BYTES;
#if defined (WIN32)
SOCKADDR_IN recvaddr;
SOCKADDR_IN sendaddr;
#elif defined(LINUX) || defined(__VXWORKS__)
struct sockaddr_in recvaddr;
struct sockaddr_in sendaddr;
#endif
socklen_t sendaddrsize = sizeof(sendaddr);
int32_t result;
#if defined (WIN32)
WSADATA wsaData;
result = WSAStartup(MAKEWORD(2,2), &wsaData);
if (result != 0)
{
printf("WSAStartup failed with error: %d\n", result);
return;
}
#endif
recvsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (recvsock == INVALID_SOCKET)
{
#if defined (WIN32)
printf("socket failed with error: %ld\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
printf("socket failed with error: %s\n", strerror(errno));
#endif
#if defined (WIN32)
WSACleanup();
#endif
return;
}
recvaddr.sin_family = AF_INET;
recvaddr.sin_port = htons(DEF_DIF_RESPONSE_PORT);
recvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
#if defined (WIN32)
result = bind(recvsock, (SOCKADDR *)&recvaddr, sizeof(recvaddr));
#elif defined(LINUX) || defined(__VXWORKS__)
result = bind(recvsock, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
#endif
if (result == SOCKET_ERROR)
{
#if defined (WIN32)
printf("bind failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
printf("bind failed with error: %s\n", strerror(errno));
#endif
closesocket(recvsock);
#if defined (WIN32)
WSACleanup();
#endif
return;
}
printf("Ready to receive UDP messages...\n");
while (terminateDIFThread == FALSE)
{
#if defined (WIN32)
result = recvfrom(recvsock, (char *)recvbuf, recvbuflen,
0, (SOCKADDR *)&sendaddr, &sendaddrsize);
#elif defined(LINUX) || defined(__VXWORKS__)
result = recvfrom(recvsock, (char *)recvbuf, recvbuflen, 0, (struct sockaddr *)&sendaddr, &sendaddrsize);
#endif
if ( result > 0 )
{
printf("\n\nUDP Server: Bytes received: %d\n", result);
DecodeUPRDIFIDRMessages(recvbuf, result);
}
else if ( result <= 0 )
#if defined (WIN32)
printf("Connection closed with error code: %ld\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
printf("Connection closed with error code: %s\n", strerror(errno));
#endif
else
#if defined (WIN32)
printf("recvfrom() failed with error code: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
printf("recvfrom() failed with error code: %s\n", strerror(errno));
#endif
}
printf("Server: Finished receiving. Closing the listening socket...\n");
closesocket(recvsock);
#if defined (WIN32)
WSACleanup();
#endif
return;
}
static void DecodeUPRDIFIDRMessages(const uint8_t msg[], int32_t msgsize)
{
uint32_t arraysize = MAX_ETHER_IDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT;
uint16_t responselen;
uint8_t response[MAX_ETHER_BLOCK_REG_CNT];
int32_t startIndex;
startIndex = 0;
while (startIndex < msgsize)
{
if (ParseDIFIDRResponse(startIndex, arraysize, (uint8_t *)msg, &responselen, MAX_ETHER_BLOCK_REG_CNT, response))
{
startIndex += responselen;
DisplayDecodedDIFIDRResponse(responselen, response);
}
}
}
static bool_t ParseDIFIDRResponse(int32_t startIndex, int32_t rsparraysize, uint8_t response[], uint16_t *idrrsplen, int32_t idrrsparraysize, uint8_t idr_response[])
{
bool_t bParsed = FALSE;
bool_t bContinueCopy = TRUE;
uint16_t preamble, postamble;
int32_t rspIndex = startIndex;
int32_t idrIndex = 0;
preamble = (response[startIndex] << 8) | response[startIndex+1];
if (bGen4DIFIDRCommands)
{
if (preamble == ETHER_GEN4_PREAMBLE)
{
while ((bContinueCopy) && (idrIndex < idrrsparraysize) && (rspIndex < rsparraysize-1))
{
postamble = (response[rspIndex] << 8) | response[rspIndex+1];
if (postamble == ETHER_GEN4_POSTAMBLE)
{
idr_response[idrIndex++] = response[rspIndex++];
idr_response[idrIndex++] = response[rspIndex++];
bContinueCopy = FALSE;
}
else
{
idr_response[idrIndex++] = response[rspIndex++];
}
}
bParsed = TRUE;
*idrrsplen = (uint16_t)idrIndex;
}
}
else
{
printf("DIF Ethernet Interrupt Support Prior to Generation 4 Ethernet commands currently not supported\n");
}
return bParsed;
}
static void DisplayDecodedDIFIDRResponse(uint16_t responselen, uint8_t response[])
{
uint16_t seq;
nai_ether_typecode_t tc;
nai_ether_gen_t gen;
int32_t size;
int32_t offset;
uint16_t seqrsptype;
uint16_t seqrspidindex;
uint16_t seqcmdindex;
uint16_t datacnt;
uint32_t data;
int32_t i;
if (bGen4DIFIDRCommands)
gen = NAI_ETHER_GEN4;
else
gen = NAI_ETHER_GEN3;
offset = nai_ether_DecodeMessageHeader(response, responselen, &seq, &tc, gen, &size);
printf("Size=%d ", size);
seqrsptype = seq & ETHER_GEN4_SEQ_UPR_MASK;
seqrspidindex = (seq & (ETHER_GEN4_SEQ_ID_MASK)) >> ETHER_GEN4_SEQ_ID_SHIFT;
seqcmdindex = (seq & (ETHER_GEN4_SEQ_CMD_MASK)) >> ETHER_GEN4_SEQ_CMD_SHIFT;
printf("seq:0x%04X (", seq);
if (seqrsptype == ETHER_GEN4_SEQ_UPR_TDR)
printf("Type=Unprompted TDR ");
else if (seqrsptype == ETHER_GEN4_SEQ_UPR_IDR)
printf("Type=Unprompted IDR ");
else
printf("Type=UNKNOWN(0x%X) ", seqrsptype);
printf("ID=%d Cmd=%d) ", seqrspidindex+1, seqcmdindex+1);
switch (tc)
{
case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_4:
printf("Typecode: Read Regs (0x%4X)\n", tc);
datacnt = (responselen - 10)/NAI_REG32;
printf(" Data (Count=%d): ", datacnt);
for (i = 0; i < datacnt; i++)
{
if (i != 0)
printf(",");
data = 0;
data = response[offset++] << 24;
data |= response[offset++] << 16;
data |= response[offset++] << 8;
data |= response[offset++];
printf("0x%08X",data);
}
printf("\n");
break;
case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_WRITE_4:
printf("Typecode: Write Regs (0x%4X)\n", tc);
break;
case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_BLOCK_4:
printf("Typecode: Read Block (0x%4X)\n", tc);
datacnt = (responselen - 10)/NAI_REG32;
printf(" Data (Count=%d): ", datacnt);
for (i = 0; i < datacnt; i++)
{
if (i != 0)
printf(",");
data = 0;
data = response[offset++] << 24;
data |= response[offset++] << 16;
data |= response[offset++] << 8;
data |= response[offset++];
printf("0x%08X",data);
}
printf("\n");
break;
case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_WRITE_BLOCK_4:
printf("Typecode: Write Block (0x%4X)\n", tc);
break;
case NAI_ETHER_TYPECODE_RSP_ERROR_BLOCK_NOT_CONFIG_4:
printf("Typecode: Block Error (Not Configured) (0x%4X)\n", tc);
break;
default:
printf("Typecode: Unknown (0x%4X)\n", tc);
break;
}
}
Common File — naiapp_interrupt_ether.h (SSK 1.x)
#ifndef NAIAPP_INTERRUPR_ETHER_H
#define NAIAPP_INTERRUPR_ETHER_H
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_menu.h"
/* naibrd include files */
#include "nai.h"
#include "naiapp_interrupt.h"
#include "naibrd_ether.h"
/* These global function pointer to point to the routine that will handle
Interrupt messages associated with the Default Interrupt Vector specified
in the naiapp_interrupt_common.h file.
*/
/*Ethernet Interrupt User Configuration*/
typedef struct
{
int32_t cardIndex;
int32_t boardInterface;
uint16_t protocol;
uint16_t port;
uint8_t ipAddress[4];
uint8_t ipLength;
uint8_t commands[MAX_ETHER_IDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT];
uint16_t cmdcount;
uint16_t cmdlength;
int32_t idrID;
}IDRConfig;
typedef void(*etherIntFuncDef)(uint16_t msglen, uint8_t msg[], uint16_t tdr_idr_id);
/* Functions that prompts user to clear interrupt */
typedef void(*ClearInterrupt)();
/* Ethernet Interrupt Common Routines */
NAIAPPFUNC bool_t CheckNaiEtherProtocolVersion(int32_t cardIndex);
NAIAPPFUNC bool_t CreateEthernetInterruptProcessingThread(int32_t threadIdx, uint16_t etherProtocol);
NAIAPPFUNC bool_t runIDRServer(IDRConfig inputIDRConfig);
NAIAPPFUNC void initializeIDRConfigurations(int32_t cardIndex, int32_t boardInteface, uint16_t protocol, uint16_t port, uint8_t ipAddress[4], uint8_t ipLength, uint8_t commands[MAX_ETHER_IDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT], uint8_t cmdcount, uint16_t cmdlength, int32_t idrID);
/* Utilities to make the on-board IDR Read/Write Register commands */
NAIAPPFUNC void MakeIDROnboardReadRegsCommand(uint16_t startIndex, uint32_t moduleOffset, uint32_t regAddr, uint32_t count, uint32_t stride, uint8_t commands[], uint16_t *cmdlen);
NAIAPPFUNC void MakeIDROnboardWriteRegsCommand(uint16_t startIndex, uint32_t moduleOffset, uint32_t regAddr, uint32_t count, uint32_t stride, uint32_t datavalues[], uint8_t commands[], uint16_t *cmdlen);
NAIAPPFUNC void MakeIDROnboardReadRegs16Command(uint16_t startIndex, uint32_t moduleOffset, uint32_t regAddr, uint32_t count, uint32_t stride, uint8_t commands[], uint16_t *cmdlen);
/* Ethernet Interrupt User Configuration Routines */
NAIAPPFUNC bool_t QueryUnpromptedEtherResponseIP4Addr(uint8_t defIP[4], uint16_t defPort, uint16_t defProtocol, uint8_t etherIP[4], uint16_t *etherPort, uint16_t *etherProtocol);
NAIAPPFUNC bool_t QueryUserForEtherIDRMsgDisplay(bool_t* bDisplayEtherUPR);
NAIAPPFUNC bool_t QueryIDRConfigInformation(IDRConfig* inputIDRConfig);
#endif /* NAIAPP_INTERRUPR_ETHER_H */