DA PatternGenerator
Edit this on GitLab
DA PatternGenerator
Explanation
About the Application Code for North Atlantic Industries' Embedded Function Modules
This C sample application code illustrates the usage of North Atlantic Industries' Standard Software Kit (SSK) to interact with their embedded function modules. It focuses on configuring and operating a Digital-to-Analog (D/A) Pattern Generator.
Overview and Dependencies
Required Libraries and Headers
- Standard Libraries: stdio.h
, ctype.h
, stdlib.h
, string.h
, time.h
, math.h
.
- Platform-specific Headers: On Windows (WIN32
), io.h
is included. On other platforms, dirent.h
is used.
- NAI Specific Include Files:
- 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_da.h
, nai_ether_adv.h
, naibrd_gen5.h
Constants and Data Structures
- Constants:
- CONFIG_FILE
: The path to the default configuration file.
- MAX_NUM_PATTERN_FILES
, MAX_FILE_NAME_SIZE
, MAX_LINE_SIZE
: Various limits for handling files and data.
-
Structures:
PatternInfo
contains details about the pattern to be generated, including: -
patternFileName
: Name of the pattern file. -
sampleRate
: Sample rate for the pattern. -
range
: Voltage range. -
polarity
: Voltage polarity. -
dataLength
: Length of the data. -
data
: Pointer to the data array.
Function Prototypes
- Main application function and helper functions:
- Run_DA_PatternGenerator()
, GeneratePattern()
, GetPatternFileList()
, LoadPatternFile()
, GetParamFromLine()
, GetDataFromPatternFile()
, SupportsDAFuncGeneration()
Detailed Code Walkthrough
Main Function
The main()
function initializes the D/A Pattern Generator application. Under both VxWorks and other environments:
1. Run Board Menu: Calls naiapp_RunBoardMenu()
.
2. User Queries: Utilizes naiapp_query_*
functions to get user inputs for card index, module number, etc.
3. Module Identification: Fetches and verifies module information using naibrd_GetModuleID()
.
4. Pattern Generation: If the module ID is valid, it executes Run_DA_PatternGenerator()
for pattern generation.
Run_DA_PatternGenerator Function
This function sets up and runs the D/A Pattern Generator:
1. User Inputs: Queries the user for card and module details.
2. Validation: Checks if the selected module supports floating point mode and queries the user for enabling it.
3. Pattern Files: Lists available pattern files (GetPatternFileList()
) and prompts the user to select one.
4. Load and Generate Pattern: Loads the selected pattern file (LoadPatternFile()
) and generates the pattern (GeneratePattern()
).
GeneratePattern Function
Handles the actual loading of the pattern into the D/A module and setting various parameters:
1. Sample Rate: Sets using naibrd_DA_SetFIFORate()
.
2. Operation Mode: Configures using naibrd_DA_SetOpMode()
.
3. Polarity and Range: Sets using naibrd_DA_SetRange()
.
4. Addresses: Configures start and end addresses using naibrd_DA_SetPatternGenStartAddr()
and naibrd_DA_SetPatternGenEndAddr()
.
5. Writing Data: Loads the data using naibrd_DA_SetPatternGenData()
.
6. Toggle Output: Enables or disables the pattern output based on user input.
Helper Functions for Pattern File Handling
Functions like GetPatternFileList()
, LoadPatternFile()
, GetParamFromLine()
, and GetDataFromPatternFile()
handle pattern file processing:
- Pattern File Listing: Searches for files with .ptrn
extension.
- Loading and Parsing: Reads parameters and data from the pattern file, checks formats, and allocates memory for the data.
Support Check for DA Functionality
- SupportsDAFuncGeneration()
: Checks if the module supports the DA functionality based on its module ID.
Explanation of Enumerations and Key Variables
- Enumerations: Used for indicating enabling/disabling states and operation modes.
- Key Variables:
- cardIndex
, module
, channel
: Indices selected by the user.
- patternInfo
: Structure holding pattern information.
This application provides a comprehensive example of setting up and using the D/A Pattern Generator provided by North Atlantic Industries, incorporating user interactions, configuration, pattern file handling, and actual pattern generation on supported modules.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#if WIN32
#include <io.h>
#else
#include <dirent.h>
#endif
/* 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_da.h"
#include "advanced/nai_ether_adv.h"
#include "boards/naibrd_gen5.h"
static const int8_t *CONFIG_FILE = (const int8_t *)"default_DAPatternGen.txt";
#define MAX_NUM_PATTERN_FILES 20
#define MAX_FILE_NAME_SIZE 100
#define MAX_LINE_SIZE 256
typedef struct _PatternInfo
{
char patternFileName[MAX_FILE_NAME_SIZE];
uint32_t sampleRate;
uint32_t range;
uint32_t polarity;
uint32_t dataLength;
float64_t *data;
} PatternInfo;
/* Function prototypes */
static int32_t Run_DA_PatternGenerator(void);
static int32_t GeneratePattern( int32_t cardIndex, int32_t module, int32_t channel, PatternInfo *patternInfo );
static int32_t GetPatternFileList( char patternFileNames[][MAX_FILE_NAME_SIZE], int32_t *numPatternFiles );
static int32_t LoadPatternFile( char patternFileName[], PatternInfo *patternInfo );
static int32_t GetParamFromLine( char line[], char paramName[], char paramValue[] );
static int32_t GetDataFromPatternFile( FILE *file, uint32_t *dataLength, float64_t **patternData );
static bool_t SupportsDAFuncGeneration(uint32_t moduleID);
/************************************************************************
GEN 5
-----
The DA Fifo Size is 26,213
The DA Fifo Output Data Rate is 2.50 usec.
Thus the DA Fifo Output Frequency is (1/2.50 usec) or 400 kHz.
The Maximum Output Frequency is:
Max Request Frequency = DA Fifo Output Frequency/Fifo Size
= 400 kHz/26213
= 15.260
************************************************************************/
/**************************************************************************************************************/
/**
<summary>
DA_PatternGenerator illustrates setting up the D/A Pattern Generator to generate various types of outputs. Output
data is read in from a file, loaded into the DA Pattern RAM, and then set to loop the pattern.
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t DA_PatternGenerator(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_DA_PatternGenerator();
}
}
}
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>
</summary>
*/
/**************************************************************************************************************/
static int32_t Run_DA_PatternGenerator(void)
{
bool_t bQuit = FALSE;
bool_t bContinue = TRUE;
int32_t cardIndex = -1, module = 1, channel = 1;
nai_status_t status;
int32_t MaxModule, MaxChannel;
uint32_t moduleID;
char patternFileNames[MAX_NUM_PATTERN_FILES][MAX_FILE_NAME_SIZE];
int32_t numPatternFiles;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
/* Query user on the Card and Module to use for this example */
bQuit = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (!bQuit)
{
status = check_status(naibrd_GetModuleCount(cardIndex, &MaxModule));
if (status == NAI_SUCCESS)
{
bContinue = TRUE;
while (bContinue)
{
bQuit = naiapp_query_ModuleNumber(MaxModule, 1, &module);
if (!bQuit)
{
/* Get the number of D/A channels on the module */
moduleID = naibrd_GetModuleID(cardIndex, module);
if (SupportsDAFuncGeneration(moduleID))
{
bool_t floatingPointMode = FALSE;
bool_t floatingPointCapable = FALSE;
/* If this module supports H/W floatingPoint, then query the user to enable it. */
naibrd_GetFloatingPointModeCapability(cardIndex, module, &floatingPointCapable);
if (FALSE != floatingPointCapable)
{
printf("This module supports H/W floating point conversion. Do you want to enable it? If not, software converting will\n");
printf(" be used (slower and processor intensive) (default: Y)");
inputResponseCnt = 0;
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if ((toupper(inputBuffer[0]) == 'Y') || (inputResponseCnt == 0))
{
naibrd_SetFloatingPointModeEnable(cardIndex, module, TRUE);
}
else
{
naibrd_SetFloatingPointModeEnable(cardIndex, module, FALSE);
}
/* Make sure FloatingPoint was enabled/disabled */
naibrd_GetRunningInFloatingPointMode(cardIndex, module, &floatingPointMode);
if (FALSE == floatingPointMode)
{
printf("**Floating point mode is disabled!**\n");
}
else
{
printf("**Floating point mode is enabled.**\n");
}
}
MaxChannel = naibrd_DA_GetChannelCount(moduleID);
/* Get the DA channel */
printf("\nD/A Setup\n");
printf("---------------------\n");
printf("D/A Channel Selection:");
bQuit = naiapp_query_ChannelNumber(MaxChannel, 1, &channel);
bContinue = FALSE;
}
else
printf("ERROR: Module selected does not support DA Functionality\n");
}
else
bContinue = FALSE;
}
}
/* Get a list of available pattern files */
GetPatternFileList( patternFileNames, &numPatternFiles );
/* Prompt user for the Pattern File */
if ( 0 < numPatternFiles )
{
PatternInfo patternInfo;
int32_t patternFileIndex = 0;
if ( 1 == numPatternFiles )
{
printf("1 Pattern File found. ");
}
else
{
printf( "List of Pattern Files:\n\n");
for( patternFileIndex = 0; patternFileIndex < numPatternFiles; patternFileIndex++ )
{
printf( "%d) %s\n", patternFileIndex + 1, patternFileNames[patternFileIndex] );
}
do
{
printf( "\n\nPlease select a Pattern File (1 - %d):\n", numPatternFiles );
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
patternFileIndex = inputBuffer[0] - 0x31;
} while ( (patternFileIndex < 0) || (patternFileIndex >= numPatternFiles));
}
/* Load the pattern file */
printf( "Loading Pattern file %s...", patternFileNames[patternFileIndex] );
if ( 0 == LoadPatternFile(patternFileNames[patternFileIndex], &patternInfo) )
{
printf("Done.\n");
/* Load the pattern into the D/A and output the signal. */
GeneratePattern(cardIndex, module, channel, &patternInfo);
}
else
{
printf("\nError loading pattern file! Can not generate output. Press ENTER to quit.\n");
getchar();
}
}
else
{
printf("No pattern files found!\n");
bContinue = FALSE;
}
if (bQuit)
bContinue = FALSE;
else
bContinue = TRUE;
}
return cardIndex;
}
static int32_t GeneratePattern( int32_t cardIndex, int32_t module, int32_t channel, PatternInfo *patternInfo )
{
nai_da_enable_t patternEnable = NAI_DA_ENABLE;
int key;
const char szPolarity[][10] = { "UniPolar", "BiPolar" };
uint32_t startAddress = 0, endAddress = 0;
/* Set Sample Rate */
printf("Setting Sample Rate to %u\n", patternInfo->sampleRate);
check_status(naibrd_DA_SetFIFORate(cardIndex, module, channel, patternInfo->sampleRate));
/* Set Operation Mode */
printf("Setting Operation Mode to VOLTAGE_PATTERN_GEN.\n");
check_status(naibrd_DA_SetOpMode(cardIndex, module, channel, NAI_DA_DATA_VOLTAGE_PATTERN_GEN));
/* Set Polarity and Range */
printf("Setting Range to %uv, Polarity to %s.\n", patternInfo->range, szPolarity[patternInfo->polarity]);
check_status(naibrd_DA_SetRange(cardIndex, module, channel, NAI_DA_DATA_VOLTAGE_PATTERN_GEN,
patternInfo->polarity, patternInfo->range));
/* Set the Start and End Addresses. */
startAddress = 0x20000 * channel;
printf("Setting START Address to 0x%4X.\n", startAddress );
check_status(naibrd_DA_SetPatternGenStartAddr(cardIndex, module, channel, startAddress));
endAddress = startAddress + ((patternInfo->dataLength - 1) * sizeof(uint32_t));
printf("Setting END Address to 0x%4X.\n", endAddress);
check_status(naibrd_DA_SetPatternGenEndAddr(cardIndex, module, channel, endAddress));
printf("Amount of data to write: (%u items x 4 bytes/item) = %u (0x%04X) total bytes.\n", patternInfo->dataLength,
patternInfo->dataLength * 4, patternInfo->dataLength * 4);
/* Write the pattern to the D/A and free allocated memory*/
printf("Writing pattern data to RAM..");
check_status(naibrd_DA_SetPatternGenData(cardIndex, module, channel, patternInfo->dataLength, patternInfo->data));
free(patternInfo->data);
printf("Done.\n");
/* Toggle the Pattern output Enable and Disable based on user input. */
do
{
check_status(naibrd_DA_SetPatternGenCtrl(cardIndex, module, channel, NAI_DA_CTRL_PATTERN_ENABLE, patternEnable));
if ( NAI_DA_ENABLE == patternEnable )
{
printf( "Pattern is ENABLED.\n" );
patternEnable = NAI_DA_DISABLE;
}
else
{
patternEnable = NAI_DA_ENABLE;
printf( "Pattern is DISABLED.\n" );
}
printf("Hit ENTER to toggle output, Type 'q' to quit\n" );
for (key = getchar(); ('q' != key) && ('Q' != key) && ('\n' != key); key = getchar());
} while ( ('q' != key) && ('Q' != key) );
/* Disable the output before exiting. */
check_status(naibrd_DA_SetPatternGenCtrl(cardIndex, module, channel,NAI_DA_CTRL_PATTERN_ENABLE, NAI_DA_DISABLE));
return 0;
}
#if WIN32
static int32_t GetPatternFileList( char patternFileNames[][MAX_FILE_NAME_SIZE], int32_t *numPatternFiles )
{
intptr_t hFile;
struct _finddata_t finddata;
int32_t done;
/* Search the directory for files with the .ptrn extension */
*numPatternFiles = 0;
hFile = _findfirst( "*.ptrn", &finddata );
done = ( 0 >= hFile );
while(!done)
{
strcpy( patternFileNames[*numPatternFiles], finddata.name );
(*numPatternFiles)++;
done = _findnext(hFile, &finddata);
}
_findclose(hFile);
return 0;
}
#else
static int32_t GetPatternFileList( char patternFileNames[][MAX_FILE_NAME_SIZE], int32_t *numPatternFiles )
{
DIR *dir;
struct dirent *entry;
int32_t done;
/* Search the directory for files with the .ptrn extension */
*numPatternFiles = 0;
dir = opendir( "./" );
done = ( NULL == dir );
while(!done)
{
entry = readdir(dir);
if (NULL != entry)
{
if (NULL != strstr(entry->d_name, ".ptrn"))
{
strcpy( patternFileNames[*numPatternFiles], entry->d_name );
(*numPatternFiles)++;
}
}
else
done = TRUE;
}
closedir(dir);
return 0;
}
#endif
static int32_t LoadPatternFile( char patternFileName[], PatternInfo *patternInfo )
{
char paramValue[20];
FILE *file;
int32_t retVal = 0;
strcpy( patternInfo->patternFileName, patternFileName );
/* Open Pattern File for reading */
file = fopen( patternInfo->patternFileName, "r" );
if ( NULL != file )
{
char line[MAX_LINE_SIZE];
/*** Load Parameters ***/
while ( (0 == retVal) && (fgets(line, MAX_LINE_SIZE, file)) )
{
if ( '/' != line[0] && '*' != line[1] )
{
if ( 0 == GetParamFromLine(line, "SAMPLE_RATE", paramValue) )
sscanf( paramValue, "%u", &(patternInfo->sampleRate) );
else if ( 0 == GetParamFromLine(line, "POLARITY", paramValue) )
{
if ( 0 == strcmp(paramValue, "BIPOLAR") )
patternInfo->polarity = 1;
else if ( 0 == strcmp(paramValue, "UNIPOLAR") )
patternInfo->polarity = 0;
else
{
printf( "\nIllegal value specified for the POLARITY parameter (%s?). Please check the pattern file!\n",
paramValue );
retVal = -1;
}
}
else if ( 0 == GetParamFromLine(line, "RANGE", paramValue) )
sscanf( paramValue, "%u", &(patternInfo->range) );
else if ( NULL != strstr(line, "DATA") )
retVal = GetDataFromPatternFile(file, &(patternInfo->dataLength), &(patternInfo->data));
}
}
/*** END Load Parameters ***/
fclose(file);
}
return retVal;
}
static int32_t GetParamFromLine( char line[], char paramName[], char paramValue[] )
{
int32_t retVal = -1;
if ( NULL != strstr(line, paramName) )
{
char *lineData = strstr(line, "=");
char *newLine;
(lineData)++;
if ( NULL != lineData )
{
while ( ' ' == *lineData )
lineData++;
newLine = strrchr(lineData, '\r');
if (NULL != newLine)
*newLine = '\0';
else
{
newLine = strrchr(lineData, '\n');
if (NULL != newLine)
*newLine = '\0';
}
strcpy(paramValue, lineData);
retVal = 0;
}
}
return retVal;
}
static int32_t GetDataFromPatternFile( FILE *file, uint32_t *dataLength, float64_t **patternData )
{
int32_t retVal = 0;
char lineData;
long fpos;
uint32_t patternDataIndex = 0;
bool_t doneReadingFile = FALSE;
*dataLength = 0;
do
{
lineData = (char)fgetc(file);
} while ( '=' == lineData || ' ' == lineData || '\n' == lineData );
/* Store this location, we'll need to come back after counting the ',' */
fpos = ftell(file);
fpos--;
/* Count the ',' to determine how much data is in the file. */
do
{
lineData = (char)fgetc(file);
if ( (char)EOF == lineData || ',' == lineData )
(*dataLength)++;
} while ( (char)EOF != lineData );
/* Allocate memory based on the count */
*patternData = (float64_t*)malloc(*dataLength * sizeof(float64_t));
/* Read the data */
fseek(file, fpos, SEEK_SET);
while (!doneReadingFile)
{
char data[20];
int32_t dataIndex = 0;
bool_t dataItemDone = FALSE;
/* Parse a datum */
do
{
data[dataIndex] = (char)fgetc(file);
if ((char)EOF == data[dataIndex])
{
/* Finished parsing last datum.. finished with file. */
data[dataIndex] = '\0';
dataItemDone = TRUE;
doneReadingFile = TRUE;
}
else if (',' == data[dataIndex])
{
/* Finished parsing a datum.. still more data to parse. */
data[dataIndex] = '\0';
dataItemDone = TRUE;
}
else
dataIndex++;
} while (!dataItemDone);
/* Store this datum as pattern data. */
sscanf( data, "%lf", &(*patternData)[patternDataIndex] );
patternDataIndex++;
}
return retVal;
}
static bool_t SupportsDAFuncGeneration(uint32_t moduleID)
{
bool_t bSupportDAFunc = FALSE;
switch (moduleID)
{
case NAI_MODULE_ID_DA3:
bSupportDAFunc = TRUE;
break;
default:
bSupportDAFunc = FALSE;
break;
}
return bSupportDAFunc;
}