A.4. Test Application for the CIF Driver

The test application for the Cogent CIF Driver for Hilscher Fieldbus CIF Cards is a C program which comes with the CIF Driver distribution. It can be run from the command line using the command dvn_test. The command-line options are as follow:

-q          Interactive mode - query between steps
-i iter     Repeat test this many times
-n taskname Connect to this published driver name
-p point    Name of test point
            (must be specified to invoke point and direct interface tests)
-b addr     Base address of test block (dflt: 0)
-l len      Length of test block (bytes)
            (must be specified to perform block tests)
-a addr     Byte offset in block of analog word to write (dflt 0)
-d addr     Byte offset in block of digital word to write (dflt 4)
-s          Block data words are high-low byte format

The code for the test application is shown here.

[Note]

This code requires files from the Cogent API, which can be downloaded from the Cogent web site.

/* **********************************************************************
*
*  Filename:     cif_test.c
*  Description:  Sample application for CIF card administrator
*					- tests functionality of driver and interfaces
*
********************************************************************** */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <machdep.h>

#include <unistd.h>
#ifdef HAVE_SYS_NAME_H
#include <sys/name.h>
#endif
#ifdef HAVE_SYS_KERNEL_H
#include <sys/kernel.h>
#endif
#include <ioport.h>

#include "dr_api.h"
#include "cif_api.h"


#define MAX_DATA_SIZE 	80
#define MAX_MSG_SIZE 	(sizeof(DR_ApBlkHdr_t) -1 + MAX_DATA_SIZE)
#define DATA_MSG_SIZE	(sizeof(DR_ApBlkHdr_t) -1 + sizeof(short))

static IP_Task* AdminTask;


/* ****************************************************************************
 *  ToggleOutputBit
 *		uses direct QNX IPC messages (bypasses API) to read	and then write
 *		a pair of bytes from/to the specified process
 */   
int	ToggleOutputBit(IP_Task* admin_task, int device, int buffer,
					unsigned short ofs, int bit)
{
	int 			result=0;
	unsigned short	*data_word;
		
	char			msg [MAX_MSG_SIZE];
	DR_ApBlkHdr_t	*hdr;
	
	/* setup a message to read the specified 2 bytes from an 
		output buffer */
	hdr = (DR_ApBlkHdr_t *) msg;
	data_word = (unsigned short *)hdr->data;
	hdr->cmd = DR_API_BLK_RD;
	hdr->dev = device;
	hdr->buffer = buffer;
	hdr->buf_size = MAX_MSG_SIZE;
	hdr->offset = ofs;
	hdr->size = sizeof(short);

	result = IP_TaskSendRaw (admin_task, msg, DATA_MSG_SIZE,
							 msg, MAX_MSG_SIZE);
	if (result == 0)
	{
		if (!(result = hdr->status))
		{
			/* toggle the bit */
			(*data_word) ^= 1<<(bit-1);

			/* write it back out */
			hdr->cmd = DR_API_BLK_WR;
			result = IP_TaskSendRaw (admin_task, msg, DATA_MSG_SIZE, msg,
									 MAX_MSG_SIZE);
		}
		else
			printf ("     Administrator response: %s\n", hdr->data);
	}
	else
		printf ("     Error %d sending to administrator\n",
				result);
	
	return (result);
}

/* ****************************************************************************
 *  ReadBufferWord
 *		uses direct QNX IPC messages (bypasses API) to read
 *		a pair of bytes from/to the specified process
 */   
int	ReadBufferWord(IP_Task* admin_task, int device,
				   unsigned short buffer, unsigned short ofs)
{
	int 			result=0;
	unsigned short	*data_word;
	
	char			msg [MAX_MSG_SIZE];
	DR_ApBlkHdr_t	*hdr;
	
	/* setup a message to read the specified 2 bytes from the buffer */
	hdr = (DR_ApBlkHdr_t *) msg;
	data_word = (unsigned short *)hdr->data;
	hdr->cmd = DR_API_BLK_RD;
	hdr->dev = device;
	hdr->buffer = buffer;
	hdr->buf_size = MAX_MSG_SIZE;
	hdr->offset = ofs;
	hdr->size = 2;
	
	result = IP_TaskSendRaw (admin_task, msg, DATA_MSG_SIZE,
							 msg, MAX_MSG_SIZE);
	if (result == 0)
	{
		if (!(result = hdr->status))
		{
			printf ("     Data at %X[%X] = %X\n", buffer, ofs, *data_word);
		}
		else
			printf ("     Administrator error %d %s\n", hdr->status, "FIXME");
	}
	else
		printf ("     Error %d sending to administrator\n",
				result);
		
	return (result);
}

void dump_data (int indent, char *data, int length, int width, int addr_ofs)
{
	int i,j;
	
	for (i=0; i<length;)
	{
		printf("%*s%04X: ", indent, "|", addr_ofs + i);
		for (j=0; j<width && i<length; j+=2, i+=2)
			printf("%02X%02X ",
				   (unsigned char)data[i], (unsigned char)data[i+1]);
		printf("\n");
	}
}

void wait_for_kybd (int single_step)
{
	if (single_step)
	{
		printf ("Press ENTER to continue");
		fflush (stdout);
		getchar();
		printf ("\n");
	}
}

		
static const char USAGE[] =
	"Usage: cif_test [-hq] [-n admin_name] options\n"
	;

int main (int argc, char ** argv)
{
	/* test parameters & command line options */
	int			 	opt;
	char			*taskname;
	char			*admin_name = "/dr/cif";
	char			*test_pnt = NULL;
	unsigned short	block_addr=0, block_length=0;
	unsigned short	analog_word_ofs=0, digital_word_ofs=4;
	int		 		iter = 1, swap=0, single_step = 0;

	/* common vars */
	int			 	result;
	char			*error_str;
	char			data[1024];
	int				nargs;
	char			*nargv[128];

	DR_ApValue_t	value;
	DR_ApValue_t	ivalue;
	unsigned short	dvalue;
		
	/*
	 * 	Extract command line parameters
	 */
	
	/* read command line options/configuration */
	taskname = argv[0];
	while ((opt = getopt(argc, argv, "hqn:p:b:l:a:d:si:")) != -1)
	{
		switch (opt)
		{
		  case 'h':
			printf("%s Test functionality of a Cogent device driver\n\n",
				   taskname);
			printf("%s", USAGE);
			printf("\nOptions:\n");
			printf("-q          Interactive mode - query between steps\n");
			printf("-i iter     Repeat test this many times\n");
			printf("-n taskname Connect to this published driver name\n");
			printf("-p point    Name of test point\n");
			printf("            (must be specified to invoke point and direct interface tests)\n");
			printf("-b addr     Base address of test block (dflt: %d)\n", block_addr);
			printf("-l len      Length of test block (bytes)\n");
			printf("            (must be specified to perform block tests)\n");
			printf("-a addr     Byte offset in block of analog word to write (dflt %d)\n", analog_word_ofs);
			printf("-d addr     Byte offset in block of digital word to write (dflt %d)\n", digital_word_ofs);
			printf("-s          Block data words are high-low byte format\n");
			exit(0);
		  case 'q':
			single_step = 1;
			printf ("Single stepping mode on\n");
			break;
		  case 'n':
			admin_name = optarg;
			printf ("Administrator name set to %s\n", admin_name);
			break;
		  case 'p':
			test_pnt = optarg;
			printf ("Test point %s will be used\n", test_pnt);
			break;
		  case 'b':
			block_addr = strtoul(optarg, NULL, 0);
			printf ("Test block base address set to %0X\n", block_addr);
			break;
		  case 'l':
			block_length = strtoul(optarg, NULL, 0);
			printf ("Test block length set to %d bytes\n", block_length);
			break;
		  case 'a':
			analog_word_ofs = strtoul(optarg, NULL, 0);
			printf ("Analog Test Word located at byte %0X of test block\n",
					analog_word_ofs);
			break;
		  case 'd':
			digital_word_ofs = strtoul(optarg, NULL, 0);
			printf ("Digital Test Word located at byte %0X of test block\n",
					digital_word_ofs);
			break;
		  case 's':
			swap = 1;
			break;
		  case 'i':
			iter = atoi(optarg);
			break;
		  default:
			fprintf(stderr, "%s", USAGE);
			exit(1);
		}
	}

	/*
	 *	Connect to target process
	 */
	
	if (!DR_ApInitIPC (taskname, admin_name))
	{
		int 	count;
		
		printf ("Successfully connected %s to %s\n\n", taskname, admin_name);
		for (count=0; count<iter; count++)
		{

			/* **************************************
			 *   test group A: command interface
			 ************************************** */
			
			wait_for_kybd (single_step);

			printf ("\nA) Testing command interface.\n");

			{
				/*** test A.1 send a command to list available commands	*/
				
				result = DR_ApCommand ("(apropos *)", data, 1024, &error_str);
				if (result == ST_OK)
					printf ("   Administrator commands available:\n%s\n",data);
				else
					printf ("     Error@ApCommand (%d, %s)\n",
							result, error_str);
			}
						
			/* **************************************
			 *   test group B: named point interface
			 ************************************** */
			
			wait_for_kybd (single_step);
			
			printf ("\nB) Testing Point Interface\n");
			
			/*** test B.1: get point names */
			{
				int				j, type, enabled, readable, writeable;
				int				device, buffer;
				unsigned short 	offset, bit;
				char			address[16];
	
				nargs = 0;
				result = DR_ApListPoints (NULL, &nargs, nargv, 128,
										  data, 1024, &error_str);
				printf ("   Listing points available:\n");
				for (j = 1; j<nargs; j++)
				{
					/*** test B.2: read specified point values */
					result = DR_ApReadPoint(nargv[j], &type, &value,
											&error_str);
					if (result == ST_OK)
					{
						printf ("     Pnt: %s ", nargv[j]);
						switch(type)
						{
						  case DR_API_DOUBLE_TYPE:
							  printf ("(real) = %f\n", value.d);
							  break;
						  case DR_API_INT32_TYPE:
							  printf ("(int) = %d\n", value.i);
							  break;
						  case DR_API_INT16_TYPE:
							  printf ("(short) = %d\n", value.s);
							  break;
						  case DR_API_BIT_TYPE:
							  printf ("(bit) = %1X\n", value.s);
							  break;
						  default:
							  printf ("(%d) = %X\n", type, value.i);
						  }
					}
					else
					{
						printf ("     Error: %s value not available\n",
								nargv[j]);
						//	printf ("     Error@ListPoints:%s (%d, %s): \n",
						//	nargv[j], result, error_str);
					}
				}
				
				if (test_pnt)
				{
					wait_for_kybd (single_step);
					
					/***	test B.3: describe a specified point */
					
					printf ("   Describing point %s: \n", test_pnt);
					result = DR_ApDescribePoint (test_pnt, &type, &enabled,
												 &readable, &writeable,
												 address, sizeof(address),
												 &error_str);
					if (result == ST_OK)
					{
						printf ("     Point %s: type %d, %s%s, addr: %s\n",
								test_pnt, type, (readable?"R":""),
								(writeable?"W":""),	address);
						
						result = DR_ApPointBufAddress (test_pnt, &device,
													   &buffer, &offset, &bit,
													   &error_str);
						if (result == ST_OK)
						{
							printf ("     Maps to: device %d, buffer %d, offset: %d",
									device, buffer, offset);
							if (type == DR_API_BIT_TYPE)
								printf (", bit: %d", bit);
							printf ("\n");
						}
						else
							printf ("     Error@PointBufAddress (%d, %s)\n",
									result, error_str);
					}
					else
						printf ("     Error@DescribePoint (%d, %s)\n",
								result, error_str);
					
					/*** test B.4: twiddle specified point value */
					
					wait_for_kybd (single_step);
					
					printf ("   Activating %s\n", test_pnt);
					ivalue.s = 1;
					result = DR_ApWritePoint (test_pnt, DR_API_BIT_TYPE,
											  &ivalue, &error_str);
					if (result == ST_OK)
					{
						delay (1000);
						printf ("   Deactivating %s\n", test_pnt);
						ivalue.s = 0;
						result = DR_ApWritePoint (test_pnt, DR_API_BIT_TYPE,
												  &ivalue, &error_str);
					}
					if (result != ST_OK)
						printf ("     Error@WritePoint (%d, %s)\n",
								result, error_str);
				}
			}
			
			/* ********************************************
			 *   test group C: binary block data transfer
			 ******************************************** */

			wait_for_kybd (single_step);
			
			printf ("\nC) Testing Block interface.\n");
				
			{
				int 					num_blks = 0;
				int						i, j, n_attr;
				unsigned short			buf_size[4];
				DR_ApSegAttributes_t 	seg_attr[4][32];
				
				/*** test C.1: list buffer info */

				result = DR_ApListBuffers (0, 4, &num_blks, buf_size,
										   &error_str);
				if (result == ST_OK)
				{
					printf ("   Device 0 has %d buffers with the following sizes:\n",
							num_blks);
					for (i=0; i<num_blks; i++)
						printf ("      Buffer %d: %d bytes.\n",
								i, buf_size[i]);
					printf ("\n");
				}
				else
					printf ("     Error@ListBuffers (%d,%s)\n",
							result, error_str);
				
				/*** test C.2 list buffer segment attributes */

				for (i=0; i<num_blks; i++)
				{
					result = DR_ApDescribeBuffer (0, i, 0, 32, &n_attr,
												  &(seg_attr[i][0]),
												  &error_str);
					if (result == ST_OK)
					{
						if (n_attr == 0)
							printf ("   Buffer %d has not defined any segments.\n", i);
						else
						{
							printf ("   Buffer %d has defined the following segments:\n", i);
							for (j=0; j<n_attr; j++)
							{
								printf ("      Buffer %d, segment %d:",
										(seg_attr[i][j].buf_id), j);
								
								printf (" %s%s%s", 
										(seg_attr[i][j].readable?"reads":""),
										((seg_attr[i][j].readable &&
										  seg_attr[i][j].writeable) ? " and ":""),
										(seg_attr[i][j].writeable?"writes":""));
								printf (" %s data",
										((DR_API_BIT_TYPE == seg_attr[i][j].type)
										 ?"digital":
										 ((DR_API_INT16_TYPE == seg_attr[i][j].type)
										  ? "analog" : "unknown type")) );
								printf (" from offset %d with length %d bytes\n",
										seg_attr[i][j].offset,
										seg_attr[i][j].size);
							}
						}
					}
					else
						printf ("     Error@DescribeBuffer (%d,%s)\n",
								result, error_str);
				}
				
				if (num_blks > 0 && n_attr > 0)
				{
					printf ("   Digital Inputs (bit) are available from the following segments:\n");
					for (i=0; i<num_blks; i++)
					{
						for (j=0; j<n_attr; j++)
						{
							if (seg_attr[i][j].readable &&
								seg_attr[i][j].type==DR_API_BIT_TYPE)
							{
								printf("     buffer %d, from offset %d for %d bytes\n",
									   seg_attr[i][j].buf_id,
									   seg_attr[i][j].offset,
									   seg_attr[i][j].size);
							}
						}
					}
					
					printf ("   Analog Outputs are available from the following segments:\n");
					for (i=0; i<num_blks; i++)
					{
						for (j=0; j<n_attr; j++)
						{
							if (seg_attr[i][j].writeable &&
								seg_attr[i][j].type==DR_API_INT16_TYPE)
							{
								printf("     buffer %d, from offset %d for %d bytes\n",
									   seg_attr[i][j].buf_id,
									   seg_attr[i][j].offset,
									   seg_attr[i][j].size);
							}
						}
					}
					printf ("\n");
				}
			}
			
			if (block_length > 0)
			{
				/*** test C.3: read data blocks */
				
				wait_for_kybd (single_step);
				
				DR_ApUpdateBuffers ();
			
				printf ("   Reading input block: device %d, buffer %d, offset %d, length %d bytes \n",
					0, 1, block_addr, block_length);
				result = DR_ApReadBlock (0, 1, block_addr, block_length,
										 data, &error_str);
				if (result == ST_OK)
					dump_data (6, data, block_length, 16, block_addr);
				else
					printf ("     Error@ReadBlock.input (%d,%s)\n",
							result, error_str);
				
				wait_for_kybd (single_step);

				printf ("   Reading output block: device %d, buffer %d, offset %d, length %d bytes \n",
					0, 0, block_addr, block_length);
				result = DR_ApReadBlock (0, 0, block_addr, block_length,
										 data, &error_str);
				if (result == ST_OK)
					dump_data (6, data, block_length, 16, block_addr);
				else
					printf ("     Error@ReadBlock.output (%d,%s)\n",
							result, error_str);

				/*** test C.4: write data blocks */
				
				wait_for_kybd (single_step);
			
				{
					int				i, j, a_incr = 100;
					unsigned short	blk_addr_a = block_addr + analog_word_ofs;
					unsigned short	blk_addr_d = block_addr + digital_word_ofs;
					
					printf ("   Writing to output block: "
							"device %d, buffer %d, offset %d, length %d bytes \n",
							0, 0, block_addr, block_length);
					
					printf ("     incrementing word at block offset 0x%02X in steps of %d)\n",
							blk_addr_a, a_incr);
					
					*(short *)&data[blk_addr_a] = 0;
					for (i=0; i<=100 && result==ST_OK; i++)
					{
						if (swap)
						{
							/* swab(src,dst,n) */
							swab (&(data[blk_addr_a]), (char *)&ivalue, 2);
							ivalue.s += a_incr;
							swab ((char *)&ivalue, &(data[blk_addr_a]), 2);
						}
						else
						{
							/* memcpy(dst,src,n) */
							memcpy ((char *)&ivalue, &(data[blk_addr_a]), 2);
							ivalue.s += a_incr;
							memcpy (&(data[blk_addr_a]), (char *)&ivalue, 2);
						}
						printf ("\r     %+06d    ", ivalue.s);
						for (j=0; j<block_length; j+=2)
							printf("%02X%02X ",
								   (unsigned char)data[block_addr + j],
								   (unsigned char)data[block_addr + j+1]);
						fflush (stdout);
						
						result = DR_ApWriteBlock (0, 0, block_addr, block_length,
												  data, &error_str);
						if (result != ST_OK)
							printf ("     Error@WriteBlock (%d,%s)\n",
									result, error_str);
						
						DR_ApUpdateBuffers ();
						delay (50);
					}
					printf ("\n");
					*(short *)&data[blk_addr_a] = 0;

					printf ("     cycling bit through byte at block byte offset 0x%02X.\n",
							blk_addr_d);

					for (i=0; i<=8 && result==ST_OK; i++)
					{
						dvalue = data[blk_addr_d] & 0x00FF;
						if (dvalue == 0)
							dvalue = 1;
						else
							dvalue <<= 1;
						data[blk_addr_d] = dvalue;
						
						printf ("\r     %04X      ", dvalue);
						for (j=0; j<block_length; j+=2)
							printf("%02X%02X ",
								   (unsigned char)data[block_addr + j],
								   (unsigned char)data[block_addr + j+1]);
						fflush (stdout);
						
						result = DR_ApWriteBlock (0, 0, block_addr, block_length,
												  data, &error_str);
						if (result != ST_OK)
							printf ("     Error@WriteBlock (%d,%s)\n",
									result, error_str);
						
						DR_ApUpdateBuffers ();
						delay (500);
					}
					printf ("\n");
					
					/* clear output digitals */
					data[blk_addr_d] = 0;
					result = DR_ApWriteBlock (0, 0, block_addr, block_length,
											  data, &error_str);
					DR_ApUpdateBuffers ();
				}
			}
			else
				printf ("   Block data read/write test skipped (block_length = 0)\n");
			
				
			/* ********************************************
			 *   test group D: control and status
			 ******************************************** */

			wait_for_kybd (single_step);
			
			printf ("\nD) Testing Control & Status interface.\n");
				
			{
				int				i;
				cif_ApParms_t	control;
				cif_ApState_t	status;

				printf ("   Reading Protocol Parameters:\n");
				result = DR_ApReadControl (0, 2, 0, sizeof (cif_ApParms_t),
										   &control, &error_str);
				if (result != ST_OK)
					printf ("     Error@ReadControl (%d,%s)\n",
							result, error_str);
				
				else
				{
					printf ("     Mode = %s (%X)\n",
							IOMODE_STR(control.Mode), control.Mode);
					printf ("     Storage format = %s (%d)\n",
							FORMAT_STR(control.Format), control.Format);
					printf ("     Watchdog Time = %d\n", control.WatchdogTime);
				}
				
				printf ("   Reading Status:\n");
				if ((result = DR_ApReadStatus (0, 2, 0, sizeof (cif_ApState_t),
											   &status, &error_str)))
					printf ("     Error@ReadStatus (%d,%s)\n",
							result, error_str);
				else
				{
					printf ("     GlobalState = %s, %s, %s\n",
							(status.GlobalBits & STATE_GLOBAL_CTRL ?
							 "Parm error" : "Parms OK"),
							(status.GlobalBits & STATE_GLOBAL_ACLR ?
							 "AutoClear/Slave error" :
							 "Mode/Slaves OK"),
							(status.GlobalBits & STATE_GLOBAL_NDATA ?
							 "Slave Fatal error" : "Slaves OK"));
					printf ("     DPMState = %s (%2.2X)\n",
							STATE_STR(status.DPMState),
							status.DPMState);
					printf ("     Error status: (%d, %d)\n",
							status.ErrorRemoteAddr, status.ErrorEvent);
					printf ("     Slaves state: ");
					for (i=0; i<16; i++)
						printf ("%2.2X", (unsigned char) status.SlaveState[i]);
					printf ("\n");
					printf ("     Slaves diagnostic bits: ");
					for (i=0; i<16; i++)
						printf ("%2.2X", (unsigned char) status.SlaveDiags[i]);
					printf ("\n");
				}
			}
			
			/* ********************************************
			 *   test group E: direct interface
			 ******************************************** */

			wait_for_kybd (single_step);

			printf ("\nE) Testing Direct interface: toggle test point.\n");

			if (test_pnt)
			{
				int				type, enabled, readable, writeable;
				int				device, buffer;
				unsigned short 	offset, bit;

				result = DR_ApDescribePoint (test_pnt, &type, &enabled,
											 &readable, &writeable,
											 NULL, 0, &error_str);
				result = DR_ApPointBufAddress (test_pnt, &device,
											   &buffer, &offset, &bit,
											   &error_str);

				if (writeable && type==DR_API_BIT_TYPE)
				{
					AdminTask = IP_TaskNew();
					if (IP_NserveLookup(admin_name, AdminTask) == -1)
					{
						IP_TaskDestroy (AdminTask);
						AdminTask = NULL;
					}
					if (AdminTask)
					{
						printf ("   Toggle bit of %s at %d:%d:%d:%d\n",
								test_pnt, 0, 0, offset, bit);
						/* remember: named point addresses are in word offsets;
						   direct and block level interfaces need byte offsets
						 */
						offset *= 2;
						
						ToggleOutputBit(AdminTask, device, buffer, offset,bit);
						DR_ApUpdateBuffers();
						delay(1000);
						ToggleOutputBit(AdminTask, device, buffer, offset,bit);
						DR_ApUpdateBuffers();

						IP_TaskDestroy (AdminTask);
						AdminTask = NULL;
					}
					else
						printf ("   Could not locate administrator %s\n",
								admin_name);
				}
				else
					printf ("   Select another point that is of type digital and writeable \n");
				
				delay (1000);
			}
			else
				printf ("   Test skipped - no test point specified\n");
		}
		
		DR_ApCloseIPC();
	}
	else
		printf ("Failed to connect %s to %s\n", argv[0], argv[1]);
	
	return (0);
}