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

DIF EtherInterrupts

DIF EtherInterrupts

Explanation

About the Sample Application Code

This sample application code by North Atlantic Industries (NAI) demonstrates how to use the NAI Software Support Kit (SSK) to interact with their embedded function modules through Ethernet interrupts. The application configures a Differential (DIF) module on a NAI card to handle Ethernet interrupt responses and establishes communication between the host and the module.

Key Components:

Header Files: - Standard Libraries: - stdio.h, stdlib.h, string.h, time.h

  • NAI-Specific Libraries:

  • naiapp_interrupt.h, naiapp_interrupt_ether.h

  • naiapp_boardaccess_menu.h, naiapp_boardaccess_query.h

  • naiapp_boardaccess_access.h, naiapp_boardaccess_display.h

  • naiapp_boardaccess_utils.h

  • nai.h, naibrd.h, naibrd_dif.h

  • naibrd_ether.h, nai_ether_adv.h

  • Conditional OS-Specific Libraries:

  • For Windows: winsock2.h, ws2tcpip.h

  • For Linux and VxWorks: sys/errno.h, pthread.h

Function Prototypes: Defines a set of functions used within the application such as Run_DIF_EthInterrupt, QueryEthInterruptDIFIPAddr, and functions for handling commands, interrupt responses, server creation, and message parsing.

Global Variables: - Configuration File: Services configuration. - CONFIG_FILE set to "default_DIFEthInterrupts.txt" - Ethernet Command Details: - Constants defining IDs, command counts, port numbers, and IP addresses used. - Multi-Platform Support: - Different data definitions and macros for Windows/UNIX (Linux and VxWorks) compatibility.

Main Function: - The main function initiates the user interface, querying the card index and module number. - Calls Run_DIF_EthInterrupt to handle the module’s Ethernet activity when a valid configuration is provided. - Allows the user to restart the application or quit through console input.

Ethernet Interrupt Handling: Run_DIF_EthInterrupt function sets up and configures the DIF channel to process Ethernet interrupts: 1. Clears pending interrupts. 2. Sets the operational mode for the DIF channel. 3. Configures the Ethernet IDR (Interrupt Driven Response) with the necessary read/write commands. 4. Enables specific interrupts and sets up interrupt vectors 5. Creates a separate handler thread to manage incoming Ethernet messages.

Server Creation and Message Handling: - Methods like CreateDIFIDRTCPServer and CreateDIFIDRUDPServer manage TCP/UDP servers to listen for responses. - DecodeUPRDIFIDRMessages and ParseDIFIDRResponse parse received messages and pass them for further handling, while DisplayDecodedDIFIDRResponse provides detailed output of messages to the console.

Command Initialization: - InitDIFIDRCommands, MakeDIFReadRegsCommand, and MakeDIFWriteRegsCommand handle setting up the Ethernet commands for reading and writing registers.

Key Definitions and Constructs: - NAI Constants/Enums: - Command IDs and response formats specific to the NAI hardware generation. - Multi-Platform Structures and Macros: - Conditional code sections to handle different OS specifics.

Inferences: - This application primarily interacts with Ethernet-based DIF modules, configuring them to handle interrupts and process read/write operations. - It is designed to demonstrate how to set up, configure, and manage communication with DIF modules through Ethernet using the NAI libraries and SSK. - The application is structured to dynamically adjust based on the host OS, making it versatile across different platforms (Windows, Linux, VxWorks).

The code offers a comprehensive setup to understand how to implement Ethernet-based interrupt handling and communication with NAI modules. It showcases real-time response handling and system querying to manage DIF modules effectively.

#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>
/* Need to link with Ws2_32.lib */
#pragma comment (lib, "Ws2_32.lib")
/* The following eliminates the FD_SET warning C4127 associated with the do...while(0) construct in the Microsoft winsock2.h file */
#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;
/* Default Ethernet Command Count specified for the IDR Commands.
   Change this to match the Command Count specified in InitDIFIDRCommands() routine
*/
#define DEF_DIF_IDR_ID                           3
#define DEF_DIF_ETHER_CMD_COUNT                  3   /* Number of Ethernet Commands in IDR Configuration */
#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;

/*****************************************************************************/
/**
<summary>
The purpose of the DIF_EtherInterrupts is to demonstrate the methods to call in the
naibrd library to perform Ethernet interrupt operations with the Differential modules.

The following system configuration routines from the nai_sys_cfg.c file are
called to assist with the configuration setup for this program prior to
calling the naibrd AD routines.
 - ConfigDevice
 - DisplayDeviceCfg
 - GetBoardSNModCfg
 - CheckModule
</summary>
*/
/*****************************************************************************/
#if defined (__VXWORKS__)
int32_t 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)
      {
         /* 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_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;
}

/**************************************************************************************************************/
/**
<summary>
This function runs handles configuring a DIF channel to receive Differential BIT, Low-to-High and
High-to-Low Ethernet Interrupt commands. This routine will create a thread to wait to
receive the unprompted interrupt ethernet messages.
</summary>
*/
/**************************************************************************************************************/
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;

   /* Determine if the board selected supports the Generation 4 Ethernet Commands */
   bGen4DIFIDRCommands = SupportsGen4Ether(cardIndex);

   /* Get the Differential channel to configure for Ethernet interrupts */
   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 /*OffBoard Interrupt*/
      {
         IDRcardIndex = 0;
         boardInterface = NAI_INTF_PCI;
         steering =  NAIBRD_INT_STEERING_CPCI_APP;
      }

   if (!bQuit)
   {
      if (bGen4DIFIDRCommands)
      {
         /* Make sure there are no pending interrupts before interrupts are enabled */
         /* Clear NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED
            and NAI_DIF_STATUS_HI_LO_TRANS_LATCHED channel status */
         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));

         /* Configure the Differential 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));

         /* Configure the Interrupt Driven Response Ethernet Command */
         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);
         }

       /* Start the IDR */
         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);
         }

         /* Configure to generate interrupts on NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED and
            NAI_DIF_STATUS_HI_LO_TRANS_LATCHED */

         /* Set the Interrupt Type (Edge/Level) */
         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));

         /* Set the Interrupt Vectors for BIT, Lo-Hi and Hi-Lo Transition */
         /* Note, set to same vector since one IDR will handle all the interrupts */
         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));

         /* Set the Interrupt Steering */
         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));

         /* 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));

         /* Create a thread that will receive Unprompted Reply interrupt messages */
         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;

               /* Stop the IDR */
               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;
}

/**************************************************************************************************************/
/**
<summary>
This function queries the user to enter the IP address associated with receiving DIF Interrupt commands.
</summary>
*/
/**************************************************************************************************************/
static bool_t QueryEthInterruptDIFIPAddr(void)
{
   bool_t bQuit = FALSE;
   bool_t bContinue = TRUE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   /* Get the IP Address */
   if (!bQuit)
   {
      bContinue = TRUE;
      while (bContinue)
      {
         /* Get the Response IP Address */
         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)
         {
            /* Get the Response Port */
            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;
}

/**************************************************************************************************************/
/**
<summary>
This function configures the IDR (Interrupt Driven Response) commands when a DIF interrupt occurs.
There are two Ethernet commands that will be processed by the board when a DIF interrupt occurs. This
routine calls the MakeDIFReadRegsCommand() and MakeDIFWriteRegsCommand() to configure the two
Ethernet commands to include when setting the IDR.
</summary>
*/
/**************************************************************************************************************/
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)
      {
         /* First command */
         MakeDIFReadRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, &ethcmdlen,boardInterface);
         msgIndex += ethcmdlen;
         idrcmdlen += ethcmdlen;
         idrcmdcnt++;

         /* Next command */
         MakeDIFWriteRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, &ethcmdlen,boardInterface);
         msgIndex += ethcmdlen;
         idrcmdlen += ethcmdlen;
         idrcmdcnt++;

         /* Next command */
         MakeDIFReadRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, &ethcmdlen,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;
}

/**************************************************************************************************************/
/**
<summary>
This function formats the buffer for the Ethernet Read Registers command.
</summary>
*/
/**************************************************************************************************************/
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)
   {
      /* Create a ReadRegs command with the following attributes:
            Onboard Access, 32-bit Register Size,
            Reg Address: NAI_DIF_GEN5_REG_BIT_LATCHED_STATUS_ADD (to read the BIT, Lo-Hi, Hi-Lo and Overcurrent statuses)
            Count: 4, Stride 0x10
      */
      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;
   }
}

/**************************************************************************************************************/
/**
<summary>
This function formats the buffer for the Ethernet Write Registers command.
</summary>
*/
/**************************************************************************************************************/
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};  /* Clear all interrupt bits */

   if (bGen4Ether)
   {
      /* Create a WriteRegs command with the following attributes:
            Onboard Access, 32-bit Register Size,
            Reg Address: NAI_DIF_GEN5_REG_BIT_LATCHED_STATUS_ADD (to read the BIT, Lo-Hi, Hi-Lo and Overcurrent statuses)
            Count: 4, Stride 0x10
            Data: 0xFFFFFFFF (clear all interrupts)
      */
      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;
   }
}

/**************************************************************************************************************/
/**
<summary>
This thread calls CreateDIFIDRTCPServer or CreateDIFIDRUDPServer depending on the
DEF_SER_RESPONSE_PROTOCOL to receive the Interrupt Driven Response (IDR) Unprompted Ethernet Replies.
</summary>
*/
/**************************************************************************************************************/
#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;
}

/**************************************************************************************************************/
/**
<summary>
This function creates a TCP Listener socket to receive the Interrupt Driven Response (IDR) Unprompted Ethernet Replies
and waits for the Ethernet messages.
</summary>
*/
/**************************************************************************************************************/
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;

   /* Resolve the server address and port */
   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;
   }

   /* Create a SOCKET for connecting to server */
   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;
   }

   /* Setup the TCP listening socket */
   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;
   }

   /* Accept a client socket */
   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;
   }

   /* No longer need server socket */
   closesocket(listensock);

   printf("Ready to receive a TCP messages...\n");

   /* Receive until the peer shuts down the connection */
   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));

    /* shutdown the connection when done */
    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;
    }

    /*cleanup */
    closesocket(clientsock);
#if defined (WIN32)
    WSACleanup();
#endif
}

/**************************************************************************************************************/
/**
<summary>
This function creates a UDP Listener socket to receive the Interrupt Driven Response (IDR) Unprompted Ethernet Replies
and waits for the Ethernet messages.
</summary>
*/
/**************************************************************************************************************/
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

   /* Create a new socket to receive datagrams on. */
   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;
   }

   /* Set up a SOCKADDR_IN structure that will tell bind that we
      want to receive datagrams from all interfaces using port DEF_RESPONSE_PORT.
   */
   /* The IPv4 family */
   recvaddr.sin_family = AF_INET;
   recvaddr.sin_port = htons(DEF_DIF_RESPONSE_PORT);
   /* From all interface (0.0.0.0) */
   recvaddr.sin_addr.s_addr = htonl(INADDR_ANY);

   /* Associate the address information with the socket using bind.
      At this point you can receive datagrams on your bound socket.
   */
#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)
   {
      /* Call recvfrom() to get it then display the received data. */
#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
   }

   /* When application is finished receiving datagrams close the socket. */
   printf("Server: Finished receiving. Closing the listening socket...\n");
   closesocket(recvsock);
#if defined (WIN32)
   WSACleanup();
#endif
   return;
}

/**************************************************************************************************************/
/**
<summary>
This function calls ParseDIFIDRResponse() to break down the IDR message received to individual Ethernet messages
and calls DisplayDecodedDIFIDRResponse() to display the data in the Ethernet message.
</summary>
*/
/**************************************************************************************************************/
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);
      }
   }
}

/**************************************************************************************************************/
/**
<summary>
This function break downs the IDR message received to individual Ethernet messages.
</summary>
*/
/**************************************************************************************************************/
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;
}

/**************************************************************************************************************/
/**
<summary>
This function displays the data in the Ethernet message.
</summary>
*/
/**************************************************************************************************************/
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);

   /* Parse IDR Response Sequence Value */
   seqrsptype = seq & ETHER_GEN4_SEQ_UPR_MASK;                                     /* Bit 15: Unprompted Response  Bit 14: TDR(0)/IDR(1) Response */
   seqrspidindex = (seq & (ETHER_GEN4_SEQ_ID_MASK)) >> ETHER_GEN4_SEQ_ID_SHIFT;    /* Bits 13-10: TDR/IDR ID Index (Note, value is ID-1) */
   seqcmdindex = (seq & (ETHER_GEN4_SEQ_CMD_MASK)) >> ETHER_GEN4_SEQ_CMD_SHIFT;    /* Bits 9-6: Command Index */
   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;
   }
}

Help Bot

X