RTD EtherInterrupts OpenDetect
Edit this on GitLab
RTD EtherInterrupts OpenDetect
Explanation
About the Sample Application Code
This sample application code, written in C, demonstrates how to interact with North Atlantic Industries' (NAI) embedded function modules using the Software Support Kit (SSK). Specifically, it provides methods for configuring and handling Ethernet interrupts on RTD (Resistance Temperature Detector) channels.
Included Headers The code begins by including various headers necessary for functionality:
-
Standard C libraries:
-
stdio.h
-
stdlib.h
-
string.h
-
time.h
-
-
NAI specific headers:
-
naiapp_boardaccess_menu.h
-
naiapp_boardaccess_query.h
-
naiapp_boardaccess_access.h
-
naiapp_boardaccess_display.h
-
naiapp_boardaccess_utils.h
-
-
Headers for NAI boards and functionalities:
-
nai.h
-
naibrd.h
-
naibrd_rtd.h
-
naibrd_ether.h
-
nai_ether_adv.h
-
nai_map_rtd.h
-
-
Platform-specific headers:
-
Windows (
WIN32
):winsock2.h
,ws2tcpip.h
-
Linux or VxWorks: corresponding platform includes for socket programming.
-
Platform Abstraction
The code includes conditional compilation to handle different platforms (Windows, Linux, VxWorks) for socket programming. This includes definitions for SOCKET
, ZeroMemory
, and closesocket
.
Constants and Static Variables
- CONFIG_FILE
: Configuration file name.
- bGen4IDRCommands
: Indicates if Generation 4 Ethernet Commands are supported (default is FALSE).
- Various defines related to RTD Ethernet commands (e.g., port, protocol, IP length, etc.).
Function Prototypes Functions are prototyped for: - Running the main RTD Ethernet interrupt logic. - Query Ethernet Interrupt configurations. - Initializing RTD Interrupt Driven Response (IDR) commands. - Creating and handling TCP/UDP servers for IDR messages. - Parsing and displaying IDR responses.
Main Function
On Linux (LINUX
) or Windows (WIN32
), the main
function initializes and runs the application:
1. Set up a loop to handle board and module configuration using NAI’s library functions.
2. Calls Run_RTD_EthInterrupt_OpenDetect
to configure RTD channels for Ethernet interrupts.
3. Handles user input to exit the loop (NAI_QUIT_CHAR
).
Main Execution Routine
- Run_RTD_EthInterrupt_OpenDetect
: Configures an RTD channel to receive Ethernet interrupts. It sets RTD wire mode, resistance, and IDR commands.
- Checks platform support for Gen4 Ethernet.
- Queries user for necessary configurations like channel and IP address.
- Configures the RTD channels and sets up Ethernet IDR commands.
- Starts a thread to handle unprompted IDR messages.
Socket Server Functions
- CreateRtdOpenDetectIDRTCPServer
and CreateRtdOpenDetectIDRUDPServer
create TCP or UDP listener sockets to handle incoming IDR messages.
IDR Message Handling
- DecodeUPRRtdOpenDetectIDRMessages
: Parses incoming Ethernet messages.
- ParseRtdOpenDetectIDRResponse
: Breaks down messages into individual Ethernet commands.
- DisplayDecodedRtdOpenDetectIDRResponse
: Displays the content of the Ethernet message.
Main Actions of the Sample Application Code - Set Up and Initialize: Preparing the RTD for monitoring, querying user configurations. - Ethernet Command Management: Configuring commands to handle interrupt-driven responses. - Socket Management: Setting up TCP or UDP servers to handle communication. - Message Handling: Parsing and displaying received Ethernet data.
Note
Ensure compatibility with your platform by setting the appropriate defines (WIN32
, LINUX
, VXWORKS
) during compilation.
This detailed walkthrough should aid in understanding the overall structure and purpose of the provided sample code, providing a solid base for further development or customization as per your use case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* Common Sample Program include files */
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_rtd.h"
#include "naibrd_ether.h"
#include "advanced/nai_ether_adv.h"
#include "maps/nai_map_rtd.h"
#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>
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 = "default_RtdEthInterruptsOpenDetect.txt";
/* Function prototypes */
static bool_t Run_RTD_EthInterrupt_OpenDetect(int32_t cardIndex, int32_t module, uint32_t modid);
static bool_t QueryEthInterruptRxIPAddr(void);
static nai_status_t InitRtdOpenDetectIDRCommands(int32_t cardIndex, int32_t module, int32_t channel, uint8_t commands[], uint16_t *cmdcount, uint16_t *cmdlen);
static void MakeRtdOpenDetectReadRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, uint8_t commands[], uint16_t *cmdlen);
static void MakeRtdOpenDetectWriteRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, int32_t channel, uint8_t commands[], uint16_t *cmdlen);
static void CreateRtdOpenDetectIDRTCPServer(void);
static void CreateRtdOpenDetectIDRUDPServer(void);
static void DecodeUPRRtdOpenDetectIDRMessages(const uint8_t msg[], int32_t msgsize);
static bool_t ParseRtdOpenDetectIDRResponse(int32_t startIndex, int32_t rsparraysize, uint8_t response[], uint16_t *idrrsplen, int32_t idrrsparraysize, uint8_t idr_response[]);
static void DisplayDecodedRtdOpenDetectIDRResponse(uint16_t responselen, uint8_t response[]);
static bool_t bGen4IDRCommands = FALSE;
/* Default Ethernet Command Count specified for the IDR Commands.
Change this to match the Command Count specified in InitRtdOpenDetectIDRCommands() routine
*/
#define DEF_RTD_IDR_ID 2
#define DEF_RTD_ETHER_CMD_COUNT 2 /* Number of Ethernet Commands in IDR Configuration */
#define DEF_RTD_RESPONSE_PROTOCOL ETHER_GEN4_UDP_PROTOCOL
#define DEF_RTD_RESPONSE_IP_LEN ETHER_GEN4_IPv4_ADDR_LEN
#define DEF_RTD_OPEN_INT_TYPE NAI_RTD_STATUS_OPEN_LATCHED
#define DEF_RTD_OPEN_INT_VECTOR 0x0A
static uint16_t DEF_RTD_RESPONSE_PORT = 52802;
static uint8_t DEF_RTD_RESPONSE_IP_ADDR[] = { 192,168,1,25 };
#if defined (__VXWORKS__)
int UPR_RtdOpenDetectEthInt_Handler(int Param);
#elif LINUX
pthread_t interruptRtdOpenDetectThread;
static void* UPR_RtdOpenDetectEthInt_Handler(void* lpParam);
#else /* Default Windows */
DWORD WINAPI UPR_RtdOpenDetectEthInt_Handler(LPVOID lpParam);
#endif
static int terminateRtdOpenDetectThread;
/*****************************************************************************/
/**
<summary>
The purpose of the RTD_EtherInterrupts_OpenDetect is to demonstrate the methods to call in the
naibrd library to perform Ethernet interrupt operations with the RTD 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 RTD_EtherInterrupts_OpenDetect(void)
#else
int32_t main(void)
#endif
{
bool_t bQuit = FALSE;
int32_t cardIndex = -1;
int32_t module = 0;
uint32_t modId = 0u;
int32_t moduleCount;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (!bQuit)
{
naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
naibrd_GetModuleCount(cardIndex, &moduleCount);
naiapp_query_ModuleNumber(moduleCount, 1, &module);
modId = naibrd_GetModuleID(cardIndex, module);
bQuit = Run_RTD_EthInterrupt_OpenDetect(cardIndex, module, modId);
printf("Type %c to exit program : ", NAI_QUIT_CHAR);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
naiapp_access_CloseAllOpenCards();
return 0;
}
/**************************************************************************************************************/
/**
<summary>
This function runs handles configuring a RTD channel to receive NAI_RTD_STATUS_OPEN_LATCHED Ethernet
Interrupt commands. This routine will create a thread to wait to receive the unprompted interrupt ethernet
messages.
</summary>
*/
/**************************************************************************************************************/
static bool_t Run_RTD_EthInterrupt_OpenDetect(int32_t cardIndex, int32_t module, uint32_t modid)
{
bool_t bQuit = FALSE;
nai_status_t status;
int32_t MAX_CHANNELS = naibrd_RTD_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_RTD_RESPONSE_PROTOCOL;
uint16_t iplen = DEF_RTD_RESPONSE_IP_LEN;
uint16_t port;
uint8_t ip[DEF_RTD_RESPONSE_IP_LEN];
int32_t i;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
/* Determine if the board selected supports the Generation 4 Ethernet Commands */
bGen4IDRCommands = SupportsGen4Ether(cardIndex);
/* Get the RTD channel to configure for Ethernet interrupts */
printf("RTD Channel Selection:");
bQuit = naiapp_query_ChannelNumber(MAX_CHANNELS, 1, &channel);
if (!bQuit)
bQuit = QueryEthInterruptRxIPAddr();
if (!bQuit)
{
if (bGen4IDRCommands)
{
/* Configure the RTD channel */
check_status(naibrd_RTD_SetWireMode(cardIndex, module, channel, NAI_RTD_GEN5_WIRE_MODE_3));
check_status(naibrd_RTD_SetZeroTempResistance(cardIndex, module, channel, NAI_RTD_ZERO_TEMP_RESISTANCE_100));
check_status(naibrd_RTD_SetBitOpenInterval(cardIndex, module, 100));
/* Configure the Interrupt Driven Response Ethernet Command */
status = check_status(naibrd_Ether_ClearIDRConfig(cardIndex, (uint16_t)DEF_RTD_IDR_ID));
InitRtdOpenDetectIDRCommands(cardIndex, module, channel, commands, &cmdcount, &cmdlength);
for (i = 0; i < DEF_RTD_RESPONSE_IP_LEN; i++)
ip[i] = DEF_RTD_RESPONSE_IP_ADDR[i];
port = DEF_RTD_RESPONSE_PORT;
status = check_status(naibrd_Ether_SetIDRConfig(cardIndex, (uint16_t)DEF_RTD_IDR_ID, protocol, iplen, ip, port,
DEF_RTD_OPEN_INT_VECTOR, cmdcount, cmdlength, commands));
if (status == NAI_SUCCESS)
{
printf("IDR ID = %d configured.\n", DEF_RTD_IDR_ID);
}
/* Configure to generate interrupts on OPEN DETECT */
check_status(naibrd_RTD_SetInterruptEdgeLevel(cardIndex, module, channel, DEF_RTD_OPEN_INT_TYPE, NAI_RTD_EDGE_INTERRUPT)); /* Edge triggered */
check_status(naibrd_RTD_SetInterruptVector(cardIndex, module, DEF_RTD_OPEN_INT_TYPE, DEF_RTD_OPEN_INT_VECTOR));
check_status(naibrd_RTD_SetInterruptSteering(cardIndex, module, DEF_RTD_OPEN_INT_TYPE, NAIBRD_INT_STEERING_ON_BOARD_1));
check_status(naibrd_RTD_SetInterruptEnable(cardIndex, module, channel, DEF_RTD_OPEN_INT_TYPE, 1));
/* Clear NAI_RTD_STATUS_OPEN_LATCHED channel status */
check_status(naibrd_RTD_ClearStatus(cardIndex, module, channel, DEF_RTD_OPEN_INT_TYPE));
/* Start the IDR */
status = check_status(naibrd_Ether_StartIDR(cardIndex, (uint16_t)DEF_RTD_IDR_ID));
if (status == NAI_SUCCESS)
{
printf("IDR ID = %d Started\n", DEF_RTD_IDR_ID);
}
/* Create a thread that will receive Unprompted Reply interrupt messages */
terminateRtdOpenDetectThread = FALSE;
#if defined (__VXWORKS__)
taskSpawn("uprRtdOpenDetectHandler", 100, 0, 10000, (FUNCPTR)UPR_RtdOpenDetectEthInt_Handler, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0);
#elif defined (LINUX)
pthread_create(&interruptRtdOpenDetectThread, NULL, (void*)UPR_RtdOpenDetectEthInt_Handler, NULL);
#else /* Default Windows */
CreateThread(NULL, 0, UPR_RtdOpenDetectEthInt_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)
{
terminateRtdOpenDetectThread = TRUE;
/* Stop the IDR */
status = check_status(naibrd_Ether_StopIDR(cardIndex, (uint16_t)DEF_RTD_IDR_ID));
if (status == NAI_SUCCESS)
{
printf("IDR ID = %d Stopped\n", DEF_RTD_IDR_ID);
}
}
}
}
else
{
printf("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 RTD Interrupt commands.
</summary>
*/
/**************************************************************************************************************/
static bool_t QueryEthInterruptRxIPAddr(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_RTD_RESPONSE_IP_ADDR[0], DEF_RTD_RESPONSE_IP_ADDR[1], DEF_RTD_RESPONSE_IP_ADDR[2], DEF_RTD_RESPONSE_IP_ADDR[3]);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (bQuit)
bContinue = FALSE;
else
{
if (inputResponseCnt > MAX_ETHER_IP_LEN)
printf("ERROR: Invalid IP Address.\n");
else
{
if (inputResponseCnt > 0)
ParseIPv4Address((char *)inputBuffer, DEF_RTD_RESPONSE_IP_ADDR);
}
}
if (!bQuit)
{
/* Get the Response Port */
printf("Please Enter IDR Response Port: [default=%d]): ", DEF_RTD_RESPONSE_PORT);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (bQuit)
bContinue = FALSE;
else
{
if (inputResponseCnt > 0)
DEF_RTD_RESPONSE_PORT = (uint16_t)atol((const char *)inputBuffer);
bContinue = FALSE;
}
}
}
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
This function configures the IDR (Interrupt Driven Response) commands when a RTD OPEN interrupt occurs.
There are two Ethernet commands that will be processed by the board when a RTD OPEN interrupt occurs. This
routine calls the MakeRtdOpenDetectReadRegsCommand() and MakeRtdOpenDetectWriteRegsCommand() to configure the two
Ethernet commands to include when setting the IDR.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t InitRtdOpenDetectIDRCommands(int32_t cardIndex, int32_t module, int32_t channel, uint8_t commands[], uint16_t *cmdcount, uint16_t *cmdlen)
{
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 (bGen4IDRCommands)
{
/* First command */
MakeRtdOpenDetectReadRegsCommand(bGen4IDRCommands, msgIndex, moduleOffset, commands, ðcmdlen);
msgIndex += ethcmdlen;
idrcmdlen += ethcmdlen;
idrcmdcnt++;
/* Next command */
MakeRtdOpenDetectWriteRegsCommand(bGen4IDRCommands, msgIndex, moduleOffset, channel, commands, ðcmdlen);
msgIndex += ethcmdlen;
idrcmdlen += ethcmdlen;
idrcmdcnt++;
*cmdcount = idrcmdcnt;
*cmdlen = msgIndex;
}
else
{
printf("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 MakeRtdOpenDetectReadRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, uint8_t commands[], uint16_t *cmdlen)
{
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_RTD_GEN5_REG_OPEN_STATUS_LATCHED_ADD (to read the open status)
Count: 1, Stride 4
*/
seqno = 0;
regaddr = moduleOffset + NAI_RTD_GEN5_REG_OPEN_STATUS_LATCHED_ADD;
count = 1;
stride = 4;
msgIndex = (uint16_t)nai_ether_MakeReadMessage(&commands[startIndex], seqno, NAI_ETHER_GEN4, NAI_INTF_ONBOARD, regaddr, stride, count, NAI_REG32);
*cmdlen = msgIndex;
}
}
/**************************************************************************************************************/
/**
<summary>
This function formats the buffer for the Ethernet Write Registers command.
</summary>
*/
/**************************************************************************************************************/
static void MakeRtdOpenDetectWriteRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, int32_t channel,
uint8_t commands[], uint16_t *cmdlen)
{
uint16_t msgIndex = startIndex;
uint16_t seqno;
uint32_t count, stride;
uint32_t regaddr;
uint32_t data = (0x000000001 << (channel - 1)); /* Clear interrupt bits */
if (bGen4Ether)
{
/* Create a WriteRegs command with the following attributes:
Onboard Access, 32-bit Register Size,
Reg Address: NAI_RTD_GEN5_REG_OPEN_STATUS_LATCHED_ADD, Count: 1, Stride 4,
Data: 0xFFFFFFFF (to clear the interrupts)
*/
seqno = 0;
regaddr = moduleOffset + NAI_RTD_GEN5_REG_OPEN_STATUS_LATCHED_ADD;
count = 1;
stride = 4;
msgIndex = (uint16_t)nai_ether_BeginWriteMessage(&commands[startIndex], seqno, NAI_ETHER_GEN4, NAI_INTF_ONBOARD, 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 CreateRtdOpenDetectIDRTCPServer or CreateRtdOpenDetectIDRUDPServer depending on the
DEF_RTD_RESPONSE_PROTOCOL to receive the Interrupt Driven Response (IDR) Unprompted Ethernet Replies.
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int UPR_RtdOpenDetectEthInt_Handler(int32_t nParam)
{
#elif LINUX
static void* UPR_RtdOpenDetectEthInt_Handler(void *lpParam)
{
#else /* Default Windows */
DWORD WINAPI UPR_RtdOpenDetectEthInt_Handler(LPVOID lpParam)
{
#endif
uint16_t protocol = DEF_RTD_RESPONSE_PROTOCOL;
#if defined (WIN32)
UNREFERENCED_PARAMETER(lpParam);
#endif
printf("\nUnprompted Reply Thread Started....\n");
if (protocol == ETHER_GEN4_TCP_PROTOCOL)
CreateRtdOpenDetectIDRTCPServer();
else
CreateRtdOpenDetectIDRUDPServer();
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 CreateRtdOpenDetectIDRTCPServer(void)
{
nai_socket_t listensock = INVALID_SOCKET, clientsock = INVALID_SOCKET;
struct addrinfo hints;
struct addrinfo *info;
uint8_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_RTD_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);
DecodeUPRRtdOpenDetectIDRMessages(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) && (terminateRtdOpenDetectThread == 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 CreateRtdOpenDetectIDRUDPServer()
{
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
int32_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_RTD_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 (terminateRtdOpenDetectThread == FALSE)
{
/* Call recvfrom() to get it then display the received data. */
#if defined (WIN32)
result = recvfrom(recvsock, (char *)recvbuf, recvbuflen,
0, (SOCKADDR *)&sendaddrsize, &sendaddrsize);
#elif defined(LINUX) || defined(__VXWORKS__)
result = recvfrom(recvsock, (char *)recvbuf, recvbuflen,
0, (struct sockaddr *)&sendaddrsize, &sendaddrsize);
#endif
if (result > 0)
{
printf("\n\nUDP Server: Bytes received: %d\n", result);
DecodeUPRRtdOpenDetectIDRMessages(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 ParseRtdOpenDetectIDRResponse() to break down the IDR message received to individual Ethernet messages
and calls DisplayDecodedRtdOpenDetectIDRResponse() to display the data in the Ethernet message.
</summary>
*/
/**************************************************************************************************************/
static void DecodeUPRRtdOpenDetectIDRMessages(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 (ParseRtdOpenDetectIDRResponse(startIndex, arraysize, (uint8_t *)msg, &responselen, MAX_ETHER_BLOCK_REG_CNT, response))
{
startIndex += responselen;
DisplayDecodedRtdOpenDetectIDRResponse(responselen, response);
}
}
}
/**************************************************************************************************************/
/**
<summary>
This function break downs the IDR message received to individual Ethernet messages.
</summary>
*/
/**************************************************************************************************************/
static bool_t ParseRtdOpenDetectIDRResponse(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 (bGen4IDRCommands)
{
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("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 DisplayDecodedRtdOpenDetectIDRResponse(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 (bGen4IDRCommands)
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;
}
}