EtherTDRCommands
Edit this on GitLab
EtherTDRCommands
Explanation
About the Sample Application Code
This repository provides a comprehensive sample application in C, developed by North Atlantic Industries (NAI), to facilitate interaction with their embedded function modules via their Software Support Kit (SSK). This specific application focuses on Ethernet Time Driven Response (TDR) commands. Below is an explanation of the key elements and structure of the code, alongside some helpful definitions and further elaborations to better understand the application’s functionality.
1. Header Files and Libraries Included
-
Standard Libraries:
-
stdio.h
: Standard input/output functions. -
stdlib.h
: Standard library functions (e.g., dynamic memory allocation, process control). -
string.h
: String manipulation functions. -
time.h
: Time functions. -
ctype.h
: Character handling functions. -
Common Sample Program Includes:
-
naiapp_boardaccess_menu.h
-
naiapp_boardaccess_query.h
-
naiapp_boardaccess_access.h
-
naiapp_boardaccess_display.h
-
naiapp_boardaccess_utils.h
-
NAI-specific Includes:
-
nai.h
,naibrd.h
,naibrd_ether.h
-
advanced/nai_ether_adv.h
-
Platform-Specific Includes: These handle differences in network programming between Windows, Linux, and VxWorks.
2. Global Constants and Types
-
Configuration File:
CONFIG_FILE
- This represents the configuration file name with default settings. -
Ethernet Command Enums: Enum elements represent various Ethernet TDR commands.
-
Command Parameters: An array (
ETH_TDRcmdMenuCmds
) of command structure, each associating a command string with a command function.
3. Main Function
int32_t main(void) {
// Variables for control flow and user input
bool_t stop = FALSE;
int32_t cardIndex;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
// Run the board menu configuration
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE) {
while (stop != TRUE) {
// Query card index from the user
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != TRUE) {
// Run the Ethernet TDR commands
Run_EtherTDRCommands(cardIndex);
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
// Cleanup and close connections
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
-
Initialization: The program starts by initializing necessary variables and configuration from a file.
-
User Interaction: It queries the user to select the card index, runs the specified Ethernet TDR operations, and allows restarting or quitting the program based on user input.
4. Core Functions
-
Run_EtherTDRCommands: This function handles querying and executing specific TDR commands based on user input.
-
Query Functions:
-
QueryEthTDRIPAddr
: Queries the IP address for TDR. -
QueryEthTDRid
: Queries the TDR ID. -
Command Creation Functions:
-
Setup functions for various Ethernet commands such as reading and writing registers.
-
Set/Get/Clear/Run/Halt TDR Functions:
-
SetEthTDRConfig
: Configures TDR settings and sends them to the device. -
GetEthTDRConfig
: Retrieves the current TDR configuration and displays it. -
ClearEthTDRConfig
: Clears the TDR configuration on the device. -
RunEthTDR
andHaltEthTDR
: Starts and stops TDR operations.
5. Network Handling
These sections implement network-related functionalities, abstracting platform differences for network socket creation and handling:
-
TCP and UDP Servers:
-
CreateTDRTCPServer
: Sets up a server to listen for TCP messages. -
CreateTDRUDPServer
: Sets up a server to listen for UDP messages. -
Response Handling: Functions to decode and handle responses received from TDR operations.
Definitions and Key Types
-
Functions:
-
nai_status_t: A type representing the status returned by NAI library functions (e.g., NAI_SUCCESS, NAI_ERROR_UNKNOWN).
-
bool_t: Custom boolean type used in the sample code.
-
int32_t, uint8_t, uint16_t: Fixed-width integer types for portability.
-
Enums and Constants:
-
Ethernet TDR command types.
-
Configuration and default settings constants (e.g., IP address, port).
This code follows a structured approach to facilitate robust functionality and user interaction for operating and testing Ethernet TDR commands. It includes necessary error handling, cross-platform considerations, and detailed processing functions to assist users in managing NAI embedded function modules effectively.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
/* Common Sample Program include files */
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "naibrd_ether.h"
#include "advanced/nai_ether_adv.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>
#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_Ether_TDR.txt";
/* Function prototypes */
static bool_t Run_EtherTDRCommands(int32_t cardIndex);
static bool_t QueryEthTDRIPAddr(void);
static bool_t QueryEthTDRid(int32_t *tdrid);
static void InitTDRCommands(uint8_t commands[], uint16_t *cmdcount, uint16_t *cmdlen);
static void MakeReadRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint8_t commands[], uint16_t *cmdlen);
static void MakeWriteRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint8_t commands[], uint16_t *cmdlen);
static void MakeReadBlockCommand(bool_t bGen4Ether, uint16_t startIndex, uint8_t commands[], uint16_t *cmdlen);
static void MakeWriteBlockCommand(bool_t bGen4Ether, uint16_t startIndex, uint8_t commands[], uint16_t *cmdlen);
static nai_status_t SetEthTDRConfig(int32_t paramCount, int32_t* p_params);
static nai_status_t GetEthTDRConfig(int32_t paramCount, int32_t* p_params);
static bool_t ParseTDRCommand(int32_t startIndex, int32_t cmdarraysize, uint8_t command[], uint16_t *tdrcmdlen, int32_t tdrcmdarraysize, uint8_t tdr_command[]);
static void DisplayDecodedEthCommand(uint16_t cmdcount, uint16_t cmdlen, uint8_t tdr_command[]);
static void DecodedEthFlags(uint16_t flags, uint8_t *onoffbrd, uint8_t *regsize);
static nai_status_t ClearEthTDRConfig(int32_t paramCount, int32_t* p_params);
static nai_status_t RunEthTDR(int32_t paramCount, int32_t* p_params);
static nai_status_t HaltEthTDR(int32_t paramCount, int32_t* p_params);
static void CreateTDRTCPServer(void);
static void CreateTDRUDPServer(void);
static void DecodeUPRTDRMessages(const uint8_t msg[], int32_t msgsize);
static bool_t ParseTDRResponse(int32_t startIndex, int32_t rsparraysize, uint8_t response[], uint16_t *tdrrsplen, int32_t tdrrsparraysize, uint8_t tdr_response[]);
static void DisplayDecodedResponse(uint16_t responselen, uint8_t response[]);
static bool_t bGen4TDRCommands = FALSE;
static uint32_t UNUSED_REG_ADDR_FOR_TEST = 0x0190; /* 0x0190 is an unused register in the Motherboard Common area */
#if defined (__VXWORKS__)
int UPR_Handler( int Param );
#elif LINUX
pthread_t interruptThread;
static void* UPR_Handler(void* lpParam );
#else /* Default Windows */
DWORD WINAPI UPR_Handler( LPVOID lpParam );
#endif
static int terminateThread;
/****** Command Table *******/
enum eth_tdr_commands
{
ETH_TDR_CMD_SET,
ETH_TDR_CMD_GET,
ETH_TDR_CMD_CLEAR,
ETH_TDR_CMD_RUN,
ETH_TDR_CMD_HALT,
ETH_TDR_CMD_COUNT
};
/****** Command Tables *******/
naiapp_cmdtbl_params_t ETH_TDRcmdMenuCmds[] = {
{"Set", "Set TDR Configuration", ETH_TDR_CMD_SET, SetEthTDRConfig},
{"Get", "Get TDR Configuration", ETH_TDR_CMD_GET, GetEthTDRConfig},
{"Clear", "Clear TDR Configuration", ETH_TDR_CMD_CLEAR, ClearEthTDRConfig},
{"Run", "Run TDR", ETH_TDR_CMD_RUN, RunEthTDR},
{"Halt", "Halt TDR", ETH_TDR_CMD_HALT, HaltEthTDR},
};
/* Default Ethernet Command Count specified for the TDR Commands.
Change this to match the Command Count specified in InitTDRCommands() routine
*/
#define DEF_ETHER_CMD_COUNT 4 /* Number of Ethernet Commands in TDR Configuration */
#define DEF_ETHER_TDR_PERIOD 5000
#define DEF_RESPONSE_PROTOCOL ETHER_GEN4_UDP_PROTOCOL
#define DEF_RESPONSE_IP_LEN ETHER_GEN4_IPv4_ADDR_LEN
static uint16_t DEF_TDR_RESPONSE_PORT = 52801;
static uint8_t DEF_TDR_RESPONSE_IP_ADDR[] = {192,168,1,100};
/**************************************************************************************************************/
/**
<summary>
The purpose of the EtherTDRCommands is to illustrate the methods to call in the naibrd library to handle the
Ethernet Time Driven Response (TDR) Commands.
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 Ethernet routines.
- ConfigDevice
- DisplayDeviceCfg
- GetBoardSNModCfg
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t EtherTDRCommands(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
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)
{
Run_EtherTDRCommands(cardIndex);
}
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 the Ethernet TDR Commands program.
</summary>
*/
/**************************************************************************************************************/
static bool_t Run_EtherTDRCommands(int32_t cardIndex)
{
bool_t bQuit = FALSE;
bool_t bContinue = TRUE;
bool_t bCmdFound = FALSE;
int32_t cmd;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
naiapp_AppParameters_t tdr_params;
p_naiapp_AppParameters_t tdrcommands_params = &tdr_params;
tdrcommands_params->cardIndex = cardIndex;
/* Determine if the board selected supports the Generation 4 Ethernet Commands */
bGen4TDRCommands = SupportsGen4Ether(cardIndex);
while (bContinue)
{
naiapp_utils_LoadParamMenuCommands(ETH_TDR_CMD_COUNT, ETH_TDRcmdMenuCmds);
naiapp_display_ParamMenuCommands((int8_t *)"Ethernet Time Driven Response (TDR) Command Menu");
printf("\nType Ethernet TDR command or %c to quit : ", NAI_QUIT_CHAR);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
bCmdFound = naiapp_utils_GetParamMenuCmdNum(inputResponseCnt, inputBuffer, &cmd);
if (bCmdFound)
{
switch (cmd)
{
case ETH_TDR_CMD_SET:
case ETH_TDR_CMD_GET:
case ETH_TDR_CMD_CLEAR:
case ETH_TDR_CMD_RUN:
case ETH_TDR_CMD_HALT:
ETH_TDRcmdMenuCmds[cmd].func(APP_PARAM_COUNT, (int32_t*)tdrcommands_params);
break;
default:
printf("Invalid command entered\n");
break;
}
}
else
printf("Invalid command entered\n");
}
}
else
bContinue = FALSE;
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
This function queries the user to enter the IP address associated with receiving TDR commands.
</summary>
*/
/**************************************************************************************************************/
static bool_t QueryEthTDRIPAddr(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 TDR Response IP Address: [default=%d.%d.%d.%d]): ",
DEF_TDR_RESPONSE_IP_ADDR[0],DEF_TDR_RESPONSE_IP_ADDR[1],DEF_TDR_RESPONSE_IP_ADDR[2],DEF_TDR_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_TDR_RESPONSE_IP_ADDR);
}
}
if (!bQuit)
{
/* Get the Response Port */
printf("Please Enter TDR Response Port: [default=%d]): ", DEF_TDR_RESPONSE_PORT);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (bQuit)
bContinue = FALSE;
else
{
if (inputResponseCnt > 0)
DEF_TDR_RESPONSE_PORT = (uint16_t)atol((const char *)inputBuffer);
bContinue = FALSE;
}
}
}
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
This function queries the user to enter the TDR id to apply the Set, Get, Clear, Start and Stop TDR
commands.
</summary>
*/
/**************************************************************************************************************/
static bool_t QueryEthTDRid(int32_t *tdrid)
{
bool_t bQuit = FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
printf("Enter the TDR ID: (default: 1) > ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt == 0)
*tdrid = 1;
else
{
*tdrid = atol((const char *)inputBuffer);
}
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
This function sets up the list of register addresses to included for the Set TDR command.
</summary>
*/
/**************************************************************************************************************/
static void InitTDRCommands(uint8_t commands[], uint16_t *cmdcount, uint16_t *cmdlen)
{
uint16_t msgIndex = 0;
uint16_t tdrcmdcnt = 0;
uint16_t ethcmdlen = 0;
uint16_t tdrcmdlen = 0;
if (bGen4TDRCommands)
{
/* First command */
MakeReadRegsCommand(bGen4TDRCommands, msgIndex, commands, ðcmdlen);
msgIndex += ethcmdlen;
tdrcmdlen += ethcmdlen;
tdrcmdcnt++;
/* Next command */
MakeWriteRegsCommand(bGen4TDRCommands, msgIndex, commands, ðcmdlen);
msgIndex += ethcmdlen;
tdrcmdlen += ethcmdlen;
tdrcmdcnt++;
/* Next command */
MakeReadBlockCommand(bGen4TDRCommands, msgIndex, commands, ðcmdlen);
msgIndex += ethcmdlen;
tdrcmdlen += ethcmdlen;
tdrcmdcnt++;
/* Next command */
MakeWriteBlockCommand(bGen4TDRCommands, msgIndex, commands, ðcmdlen);
msgIndex += ethcmdlen;
tdrcmdlen += ethcmdlen;
tdrcmdcnt++;
*cmdlen = tdrcmdlen;
*cmdcount = tdrcmdcnt;
}
else
{
printf("Ethernet TDR Command Support Prior to Generation 4 Ethernet commands currently not supported\n");
}
}
/**************************************************************************************************************/
/**
<summary>
This function formats the buffer for the Ethernet Read Registers command.
</summary>
*/
/**************************************************************************************************************/
static void MakeReadRegsCommand(bool_t bGen4Ether, uint16_t startIndex, 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: UNUSED_REG_ADDR_FOR_TEST, Count: 4, Stride 4
*/
seqno = 0;
regaddr = UNUSED_REG_ADDR_FOR_TEST;
count = 4;
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 MakeWriteRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint8_t commands[], uint16_t *cmdlen)
{
uint16_t msgIndex = startIndex;
uint16_t seqno;
uint32_t count, stride;
uint32_t regaddr;
uint32_t data[] = {0x12345678, 0xAAAAAAAA, 0x55555555, 0xABCDEF01};
if (bGen4Ether)
{
/* Create a WriteRegs command with the following attributes:
Onboard Access, 32-bit Register Size,
Reg Address: UNUSED_REG_ADDR_FOR_TEST, Count: 4, Stride 4
Data - 0x12345678, 0xAAAAAAAA, 0x55555555, 0xABCDEF01
*/
seqno = 0;
regaddr = UNUSED_REG_ADDR_FOR_TEST;
count = 4;
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 function formats the buffer for the Ethernet Read Block command. Note, the Block should be configured
using the naibrd_Ether_SetBlock().
</summary>
*/
/**************************************************************************************************************/
static void MakeReadBlockCommand(bool_t bGen4Ether, uint16_t startIndex, uint8_t commands[], uint16_t *cmdlen)
{
uint16_t msgIndex, seqno;
uint16_t blockid;
if (bGen4Ether)
{
/* Create a ReadBlock command for Block ID = 1.
Note, Block should be configured using the naibrd_Ether_SetBlock().
*/
seqno = 0;
blockid = 1;
msgIndex = (uint16_t)nai_ether_MakeReadBlockMessage(&commands[startIndex],seqno,NAI_ETHER_GEN4,blockid);
*cmdlen = msgIndex;
}
}
/**************************************************************************************************************/
/**
<summary>
This function formats the buffer for the Ethernet Write Block command. Note, the Block should be configured
using the naibrd_Ether_SetBlock().
</summary>
*/
/**************************************************************************************************************/
static void MakeWriteBlockCommand(bool_t bGen4Ether, uint16_t startIndex, uint8_t commands[], uint16_t *cmdlen)
{
uint16_t msgIndex = startIndex;
uint16_t blockid;
uint16_t seqno;
uint16_t blkregcount = 18; /* Refer to SetEthBlockConfig() routine in EtherBlockCommands() sample code */
uint32_t data[] = {
0x11111111, 0x12222222, 0x13333333, 0x14444444, 0x15555555, 0x16666666,
0x1AAAAAAA, 0x1BBBBBBB, 0xCCCCCCCC, 0x1DDDDDDD, 0x1EEEEEEE, 0x1FFFFFFF,
0x12345678, 0x1ABCDEF0, 0x1AAAA555, 0x15555AAA, 0x00000000, 0xFFFFFFFF,
};
if (bGen4Ether)
{
/* Create a WriteBlock command for Block ID = 1.
Note, Block should be configured using the naibrd_Ether_SetBlock().
Use the EtherBlockCommands() sample application to configure
the Block configuration used here.
*/
seqno = 0;
blockid = 1;
msgIndex = (uint16_t)nai_ether_MakeWriteBlockMessage(&commands[startIndex],seqno,NAI_ETHER_GEN4,blockid,NAI_REG32,blkregcount,data);
*cmdlen = msgIndex;
}
}
/**************************************************************************************************************/
/**
<summary>
This function calls InitTDRCommands() to sets up the list of Ethernet commands for the Set TDR command
and calls naibrd_Ether_SetTDRConfig() to send the SetTDR command to the board for the TDR ID specified.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t SetEthTDRConfig(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_tdr_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_tdr_params->cardIndex;
int32_t tdrid;
bool_t bQuit = FALSE;
nai_status_t status;
uint8_t commands[MAX_ETHER_TDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT];
uint16_t cmdcount = 0;
uint16_t cmdlength = 0;
int32_t i;
uint16_t protocol = DEF_RESPONSE_PROTOCOL;
uint16_t iplen = DEF_RESPONSE_IP_LEN;
uint16_t period = DEF_ETHER_TDR_PERIOD;
uint8_t ip[DEF_RESPONSE_IP_LEN];
uint16_t port;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
bQuit = QueryEthTDRIPAddr();
if (!bQuit)
{
bQuit = QueryEthTDRid(&tdrid);
if (!bQuit)
{
InitTDRCommands(commands, &cmdcount, &cmdlength);
for (i = 0; i < DEF_RESPONSE_IP_LEN; i++)
ip[i] = DEF_TDR_RESPONSE_IP_ADDR[i];
port = DEF_TDR_RESPONSE_PORT;
status = check_status(naibrd_Ether_SetTDRConfig(cardIndex,(uint16_t)tdrid,protocol,iplen,ip,port,period,cmdcount,cmdlength,commands));
if (status == NAI_SUCCESS)
{
printf("TDR ID = %d configured.\n", tdrid);
}
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
This function calls naibrd_Ether_GetTDRConfig() to send the GetTDR command to the board to retrieve the list of
Ethernet commands specified for the TDR ID specified and ParseTDRCommand() to parse the list of Ethernet
commands into individual commands. The DisplayDecodedEthCommand() routine is called for each individual
command to decode the Ethernet command.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t GetEthTDRConfig(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_tdr_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_tdr_params->cardIndex;
int32_t tdrid;
bool_t bQuit = FALSE;
nai_status_t status;
uint16_t protocol, iplen, port, period;
uint8_t ip[MAX_ETHER_IP_LEN];
uint32_t arraysize = MAX_ETHER_TDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT;
uint8_t commands[MAX_ETHER_TDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT];
uint16_t tdrcmdlen;
uint8_t tdr_command[MAX_ETHER_BLOCK_REG_CNT];
uint16_t cmdcount;
int32_t i, startIndex;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
bQuit = QueryEthTDRid(&tdrid);
if (!bQuit)
{
status = check_status(naibrd_Ether_GetTDRConfig(cardIndex,(uint16_t)tdrid,&protocol,&iplen,ip,&port,&period,&cmdcount,arraysize,commands));
if (status == NAI_SUCCESS)
{
printf("\n\n TDR ID = %d Configuration:\n", tdrid);
printf("--------------------------------\n");
printf("Response Protocol : ");
if (protocol == 0)
printf("TCP (%d)\n", protocol);
else if (protocol == 1)
printf("UDP (%d)\n", protocol);
else
printf("UKNOWN (%d)\n", protocol);
printf("Response IP Address : ");
if (iplen == 4)
{
printf("IPv4 : ");
printf("%d:%d:%d:%d\n",ip[0], ip[1], ip[2], ip[3]);
}
else if (iplen == 6)
{
printf("IPv6 : ");
/* TODO */
printf("\n");
}
else
{
printf("Unknown (%d)\n", iplen);
}
printf("Response Port : %d\n", port);
printf("Period : %d (ms)\n", period);
if (cmdcount > 0)
{
startIndex = 0;
for (i = 0; i < (int32_t)cmdcount; i++)
{
if (ParseTDRCommand(startIndex, arraysize, commands, &tdrcmdlen, MAX_ETHER_BLOCK_REG_CNT, tdr_command))
{
startIndex += tdrcmdlen;
DisplayDecodedEthCommand((uint16_t)i+1, tdrcmdlen, tdr_command);
}
}
}
else
printf("\n\nNo Ethernet Commands configured for TDR ID = %d\n", tdrid);
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
This function handles parsing the list of Ethernet commands for the next Ethenet command.
</summary>
*/
/**************************************************************************************************************/
static bool_t ParseTDRCommand(int32_t startIndex, int32_t cmdarraysize, uint8_t command[], uint16_t *tdrcmdlen, int32_t tdrcmdarraysize, uint8_t tdr_command[])
{
bool_t bParsed = FALSE;
bool_t bContinueCopy = TRUE;
uint16_t preamble, postamble;
int32_t cmdIndex = startIndex;
int32_t tdrIndex = 0;
preamble = (command[startIndex] << 8) | command[startIndex+1];
if (bGen4TDRCommands)
{
if (preamble == ETHER_GEN4_PREAMBLE)
{
while ((bContinueCopy) && (tdrIndex < tdrcmdarraysize) && (cmdIndex < cmdarraysize-1))
{
postamble = (command[cmdIndex] << 8) | command[cmdIndex+1];
if (postamble == ETHER_GEN4_POSTAMBLE)
{
tdr_command[tdrIndex++] = command[cmdIndex++];
tdr_command[tdrIndex++] = command[cmdIndex++];
bContinueCopy = FALSE;
}
else
{
tdr_command[tdrIndex++] = command[cmdIndex++];
}
}
bParsed = TRUE;
*tdrcmdlen = (uint16_t)tdrIndex;
}
}
else
{
printf("Ethernet TDR Command Support Prior to Generation 4 Ethernet commands currently not supported\n");
}
return bParsed;
}
/**************************************************************************************************************/
/**
<summary>
This function handles decoding the Ethenet command and calling DecodedEthFlags() to decode the flags in the
command.
</summary>
*/
/**************************************************************************************************************/
static void DisplayDecodedEthCommand(uint16_t cmdcount, uint16_t cmdlen, uint8_t tdr_command[])
{
uint16_t typecode = 0;
uint16_t msglen = 0;
uint16_t flags = 0;
uint32_t regaddr = 0;
uint16_t regcount = 0;
uint16_t regstride = 0;
uint16_t blockid = 0;
uint8_t onoffbrd = 0;
uint8_t regsize = 0;
int32_t i, j;
int32_t cmdIndex, valuelen;
if (bGen4TDRCommands)
{
/* The Command must have at least 8 bytes in order to retrieve the TypeCode and MsgLen */
if (cmdlen < 8)
return;
printf("TDR Command %d:\n", cmdcount);
/* Get the TypeCode */
typecode = (tdr_command[4] << 8) | tdr_command[5];
/* Get the Message Length */
msglen = (tdr_command[6] << 8) | tdr_command[7];
switch(typecode)
{
case NAI_ETHER_TYPECODE_OP_READ_4:
case NAI_ETHER_TYPECODE_OP_WRITE_4:
/* Read/Write Reg Command must have at least 20 bytes */
if (cmdlen < 20)
return;
flags = (tdr_command[8] << 8) | tdr_command[9];
regaddr = (tdr_command[10] << 24) | (tdr_command[11] << 16) | (tdr_command[12] << 8) | tdr_command[13];
regcount = (tdr_command[14] << 8) | tdr_command[15];
regstride = (tdr_command[16] << 8) | tdr_command[17];
break;
case NAI_ETHER_TYPECODE_OP_READ_BLOCK_4:
case NAI_ETHER_TYPECODE_OP_WRITE_BLOCK_4:
/* Read/Write Block command must have at least 12 bytes */
if (cmdlen < 12)
return;
blockid = (tdr_command[8] << 8) | tdr_command[9];
break;
}
switch(typecode)
{
case NAI_ETHER_TYPECODE_OP_READ_4:
printf(" Typecode (0x%04X) : Read Registers\n", typecode);
DecodedEthFlags(flags, &onoffbrd, ®size);
if (onoffbrd == ETHER_GEN4_ONBOARD)
printf(" Onboard,");
else
printf(" Offboard,");
if (regsize == ETHER_GEN4_32_BIT_REG_SIZE)
printf(" Reg Size: 32-bit,");
else
printf(" Reg Size: 16-bit,");
printf(" Addr: 0x%08X, Count: %d, Stride: %d\n", regaddr, regcount, regstride);
break;
case NAI_ETHER_TYPECODE_OP_WRITE_4:
printf(" Typecode (0x%04X) : Write Registers\n", typecode);
DecodedEthFlags(flags, &onoffbrd, ®size);
if (onoffbrd == ETHER_GEN4_ONBOARD)
printf(" Onboard,");
else
printf(" Offboard,");
if (regsize == ETHER_GEN4_32_BIT_REG_SIZE)
printf(" Reg Size: 32-bit,");
else
printf(" Reg Size: 16-bit,");
printf(" Addr: 0x%08X, Count: %d, Stride: %d\n", regaddr, regcount, regstride);
if (regsize == ETHER_GEN4_32_BIT_REG_SIZE)
valuelen = 4;
else
valuelen = 2;
/* Check to make sure that the tdr_command is at least 20 + regcount * valuelen elements */
if (cmdlen < (20 + (regcount * valuelen)))
return;
printf(" Data to write: ");
cmdIndex = 18;
for (i = 0; i < regcount; i++)
{
if (i != 0)
printf(",");
printf("0x");
for (j = 0; j < valuelen; j++)
printf("%02X", tdr_command[cmdIndex++]);
}
printf("\n");
break;
case NAI_ETHER_TYPECODE_OP_READ_BLOCK_4:
printf(" Typecode (0x%04X) : Read Block\n", typecode);
printf(" Block ID: %d\n", blockid);
break;
case NAI_ETHER_TYPECODE_OP_WRITE_BLOCK_4:
printf(" Typecode (0x%04X) : Write Block\n", typecode);
printf(" Block ID: %d\n", blockid);
/* The Block Write Command does not specify the register size or
the write count.
A call to naibrd_Ether_GetBlock() will retrieve this information.
For the purpose of this example, we will assume 32-bit data.
*/
valuelen = 4;
regcount = (uint16_t)((msglen - 12)/valuelen);
/* Check to make sure that the tdr_command is at least 12 + regcount * valuelen elements */
if (cmdlen < (12 + (regcount * valuelen)))
return;
printf(" Data to write: ");
cmdIndex = 10;
for (i = 0; i < regcount; i++)
{
if (i != 0)
printf(",");
printf("0x");
for (j = 0; j < valuelen; j++)
printf("%02X", tdr_command[cmdIndex++]);
}
printf("\n");
break;
}
}
else
{
printf("Ethernet TDR Command Support Prior to Generation 4 Ethernet commands currently not supported\n");
}
}
/**************************************************************************************************************/
/**
<summary>
This function handles decoding the flags in the Ethernet command.
</summary>
*/
/**************************************************************************************************************/
static void DecodedEthFlags(uint16_t flags, uint8_t *onoffbrd, uint8_t *regsize)
{
if ((flags & ETHER_GEN4_ONOFFBOARD_MASK) > 0)
*onoffbrd = ETHER_GEN4_OFFBOARD;
else
*onoffbrd = ETHER_GEN4_ONBOARD;
if ((flags & ETHER_GEN4_16_32_REG_SIZE_MASK) > 0)
*regsize = ETHER_GEN4_16_BIT_REG_SIZE;
else
*regsize = ETHER_GEN4_32_BIT_REG_SIZE;
}
/**************************************************************************************************************/
/**
<summary>
This function calls naibrd_Ether_ClearTDRConfig() to send the ClearTDR command to the board to remove the list of
Ethernet commands specified for the TDR ID specified.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t ClearEthTDRConfig(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_tdr_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_tdr_params->cardIndex;
int32_t tdrid;
bool_t bQuit = FALSE;
nai_status_t status;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
bQuit = QueryEthTDRid(&tdrid);
if (!bQuit)
{
status = check_status(naibrd_Ether_ClearTDRConfig(cardIndex, (uint16_t)tdrid));
if (status == NAI_SUCCESS)
{
printf("TDR ID = %d cleared\n", tdrid);
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
This function calls naibrd_Ether_StartTDR() to send the Start TDR command to the board to start the
Time Driven Response Ethernet commands specified for the TDR ID specified. It then creates a thread to create
a listener socket to handle the Ethernet responses.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t RunEthTDR(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_tdr_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_tdr_params->cardIndex;
int32_t tdrid;
bool_t bQuit = FALSE;
nai_status_t status;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
bQuit = QueryEthTDRid(&tdrid);
if (!bQuit)
{
status = check_status(naibrd_Ether_StartTDR(cardIndex, (uint16_t)tdrid));
if (status == NAI_SUCCESS)
{
printf("TDR ID = %d Started\n", tdrid);
}
/* Create a thread that will receive Unprompted Reply interrupt messages */
terminateThread = FALSE;
#if defined (__VXWORKS__)
taskSpawn("uprHandler", 100, 0, 10000, (FUNCPTR)UPR_Handler, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
#elif defined (LINUX)
pthread_create(&interruptThread, NULL, (void*)UPR_Handler, NULL);
#else /* Default Windows */
CreateThread( NULL, 0, UPR_Handler, NULL, 0, NULL );
#endif
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
This function calls naibrd_Ether_StopTDR() to send the Stop TDR command to the board to stop the
Time Driven Response Ethernet commands specified for the TDR ID specified.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t HaltEthTDR(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_tdr_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_tdr_params->cardIndex;
int32_t tdrid;
bool_t bQuit = FALSE;
nai_status_t status;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
bQuit = QueryEthTDRid(&tdrid);
if (!bQuit)
{
status = check_status(naibrd_Ether_StopTDR(cardIndex, (uint16_t)tdrid));
if (status == NAI_SUCCESS)
{
printf("TDR ID = %d Stopped\n", tdrid);
/* Terminate the thread that receives Unprompted Reply interrupt messages */
terminateThread = TRUE;
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
This thread calls CreateTDRTCPServer or CreateTDRUDPServer depending on the DEF_RESPONSE_PROTOCOL to receive
the Time Driven Response (TDR) Unprompted Ethernet Replies.
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int UPR_Handler( int32_t nParam )
{
#elif LINUX
static void* UPR_Handler(void *lpParam )
{
#else /* Default Windows */
DWORD WINAPI UPR_Handler( LPVOID lpParam )
{
#endif
uint16_t protocol = DEF_RESPONSE_PROTOCOL;
#if defined (WIN32)
UNREFERENCED_PARAMETER(lpParam);
#endif
printf("\nUnprompted Reply Thread Started....\n");
if (protocol == ETHER_GEN4_TCP_PROTOCOL)
CreateTDRTCPServer();
else
CreateTDRUDPServer();
printf("\nUnprompted Reply Thread Terminated\n");
return 0;
}
/**************************************************************************************************************/
/**
<summary>
This function creates a TCP Listener socket to receive the Time Driven Response (TDR) Unprompted Ethernet Replies
and waits for the Ethernet messages.
</summary>
*/
/**************************************************************************************************************/
static void CreateTDRTCPServer(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_TDR_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("Bytes received: %d\n", result);
DecodeUPRTDRMessages(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) && (terminateThread == 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 Time Driven Response (TDR) Unprompted Ethernet Replies
and waits for the Ethernet messages.
</summary>
*/
/**************************************************************************************************************/
static void CreateTDRUDPServer()
{
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_TDR_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 (terminateThread == FALSE)
{
/* Call recvfrom() to get it then display the received data. */
#if defined (WIN32)
/* result = recvfrom(recvsock, (char *)recvbuf, recvbuflen,
0, (SOCKADDR *)&sendaddrsize, &sendaddrsize); */
result = recvfrom(recvsock, (char *)recvbuf, recvbuflen,
0, (SOCKADDR *)&sendaddr, &sendaddrsize);
#elif defined(LINUX) || defined(__VXWORKS__)
/* result = recvfrom(recvsock, (char *)recvbuf, recvbuflen,
0, (struct sockaddr *)&sendaddrsize, &sendaddrsize); */
result = recvfrom(recvsock, (char *)recvbuf, recvbuflen,
0, (struct sockaddr *)&sendaddr, &sendaddrsize);
#endif
if ( result > 0 )
{
printf("Bytes received: %d\n", result);
DecodeUPRTDRMessages(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 ParseTDRResponse() to break down the TDR message received to individual Ethernet messages
and calls DisplayDecodedResponse() to display the data in the Ethernet message.
</summary>
*/
/**************************************************************************************************************/
static void DecodeUPRTDRMessages(const uint8_t msg[], int32_t msgsize)
{
uint32_t arraysize = MAX_ETHER_TDR_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 (ParseTDRResponse(startIndex, arraysize, (uint8_t *)msg, &responselen, MAX_ETHER_BLOCK_REG_CNT, response))
{
startIndex += responselen;
DisplayDecodedResponse(responselen, response);
}
}
}
/**************************************************************************************************************/
/**
<summary>
This function break downs the TDR message received to individual Ethernet messages.
</summary>
*/
/**************************************************************************************************************/
static bool_t ParseTDRResponse(int32_t startIndex, int32_t rsparraysize, uint8_t response[], uint16_t *tdrrsplen, int32_t tdrrsparraysize, uint8_t tdr_response[])
{
bool_t bParsed = FALSE;
bool_t bContinueCopy = TRUE;
uint16_t preamble, postamble;
int32_t rspIndex = startIndex;
int32_t tdrIndex = 0;
preamble = (response[startIndex] << 8) | response[startIndex+1];
if (bGen4TDRCommands)
{
if (preamble == ETHER_GEN4_PREAMBLE)
{
while ((bContinueCopy) && (tdrIndex < tdrrsparraysize) && (rspIndex < rsparraysize-1))
{
postamble = (response[rspIndex] << 8) | response[rspIndex+1];
if (postamble == ETHER_GEN4_POSTAMBLE)
{
tdr_response[tdrIndex++] = response[rspIndex++];
tdr_response[tdrIndex++] = response[rspIndex++];
bContinueCopy = FALSE;
}
else
{
tdr_response[tdrIndex++] = response[rspIndex++];
}
}
bParsed = TRUE;
*tdrrsplen = (uint16_t)tdrIndex;
}
}
else
{
printf("Ethernet TDR Command 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 DisplayDecodedResponse(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 (bGen4TDRCommands)
gen = NAI_ETHER_GEN4;
else
gen = NAI_ETHER_GEN3;
offset = nai_ether_DecodeMessageHeader(response, responselen, &seq, &tc, gen, &size);
printf("Size=%d ", size);
/* Parse TDR 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;
}
}