7526 CFR Sample Library of Utility Functions
--------------------------------------------
Introduction
------------
This library of utility Custom Function Routine functions provides various
useful, pre-written routines which help to speed development of CFRs for the
7526 Data Collection Terminal.
Included are:
- Routines to extract data from validation files by finding a specific record
offset or a numbered record
- A binary validation file search routine which greatly speeds the checking of
a record in a validation file of fixed length, sorted records.
- A version of sprintf() which is written specifically for use on the
data collection terminal
- Higher level print functions for 7526's equipped with printer-capable
processor boards.
- Format the time and date into strings
- Get the current time, represented as seconds since January 1, 1900 at
mid-night.
- Control input from sensor ports and/or keypad, forcing numeric input to
valid forms, handling scanner errors, and allowing cursor control within the
input field.
- Write a character a number of times to the display
Source code is available for educational purposes, for creation of derivative
functions, and for fixing of any defects which may exist in the code.
Function Reference
------------------
BinaryValidation
----------------
Description: This function performs a validation of the presence or absence of
a match between a string and the records of a validation file, using a binary
searching method. The binary search can yield a much faster search time when
the validation file has many records.
For example, while the 7526 has built-in binary file searching, programs like
Data Collector and DCC/2 do not inform the terminal that the files are sorted
(even though they most often actually are) so it uses a sequential search.
For a 3,000 record employee badge file (each record about 10 characters), the
search can take about 3 seconds. With this binary search, the elapsed time
is less than 0.5 seconds (its so fast, it is hard to measure).
Records must be of fixed length, and must be sorted into ascending order.
An example of a properly formated validation file is:
123456789
222222222
987654321
If the file is not found on the terminal, the function will return
FILE_NOT_FOUND. Otherwise, it will return VAL_PASSED or VAL_FAILED,
depending on the seach type which was requested and the results of the
search.
C Format:
int BinaryValidation(
(
char * ValFilename, // The validation file name
char type, // The validation type desired, either
// INCL_SKIP_IF_FAIL or
// EXCL_SKIP_IF_FAIL.
char * data // The string to compare against.
);
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
int far main (int funct,char far *params)
{
USHORT xfrcnt; // Vio transfer count
char filename[13];
char badge_read[40];
...
strcpy(filename, "BADGES.VAL");
type = INCL_SKIP_IF_FAIL;
// get data passed from transaction program
ReadUserVariable(0, badge_read);
// Try to do binary validation. If file is
// not found, resort to trying the regular
// Validation routine, which will try to
// do a host-based validation.
rc = BinaryValidation(filename, type, badge_read);
if (rc == FILE_NOT_FOUND)
{
// try regular support
// (returns E_OK or E_DATA_NOT_FOUND,
// which in the case of inclusive validation
// are the same as VAL_PASSED and VAL_FAILED
// as returned by the BinaryValidation routine.
rc = Validation(filename, badge_read);
} /* endif */
// handle results...
switch(rc)
{
case VAL_PASSED:
case E_OK:
// more...
break;
case VAL_FAILED:
case E_DATA_NOT_FOUND:
// more...
break;
case E_HOST_DOWN:
// more...
break;
case FILE_NOT_FOUND:
// more...
break;
}
...
}
format_date
-----------
Description: This function reads the current date from the DCT's real-time
clock and formats the data into strings which are ready for presentation or
printing. You can specify AMERican or EUROpean format and the character you
want as the months-days-years delimiters.
You must provide the addresses of two data areas:
- A buffer of at least 9 characters in length for the time string with
delimiters between the date elements
- A buffer of at least 7 characters in length for a compact string with
no element delimiters
C Format:
void format_date
(
char * formatted_date, // A pointer to a results work area which your
// program must provide for the formatted date
// with delimiters in place -- minimum size 12 bytes
char * no_delim_date, // A pointer to a results work area which your
// program must provide for the formatted date
// with no delimiters used -- minimum size 9 bytes
char form, // The form of the date string; defines are
// EURO (DD.MM.YY) or AMER (MM/DD/YY)
char date_delimiter // The character you want used between date
// elements
);
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
int far main (int funct,char far *params)
{
char date_str[9], short_date[7]; // data return areas
...
// get the current date for printing
format_date(date_str, short_date, EURO, '.');
...
}
format_time
-----------
Description: This function reads the current time from the DCT's real-time
clock and formats the data into strings which are ready for presentation or
printing. You can specify 12 or 24-hour time and the character you
want as the hours-minutes-seconds delimiters.
You must provide the addresses of two data areas:
- A buffer of at least 12 characters in length for the time string with
delimiters between the time elements
- A buffer of at least 9 characters in length for a compact string with
no element delimiters
C Format:
void format_time
(
char * formatted_time, // A pointer to a results work area which your
// program must provide for the formatted time with
// delimiters in place -- minimum size 12 bytes
char * no_delim_time, // A pointer to a results work area which your
// program must provide for the formatted time with
// no delimiters used -- minimum size 9 bytes
int form, // The form of the time string; defines are
// HHMMSS_24 and HHMMSS_12
char time_delimiter // The character you want used between time elements
);
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
int far main (int funct,char far *params)
{
char time_str[12], short_time[9]; // data return areas
...
// get the current time for printing
format_time(time_str, short_time, HHMMSS_24, ':');
...
}
GetRecord
---------
Description: This function returns a pointer to any numbered record within
an on-board terminal validation file. The pointer is to the beginning of the
record number prefix text.
Records may be fixed or variable length. The record number is a zero-padded,
ascending prefix at the beginning of each record. Each record in a 7526
validation file is delimited by a record separator character (character 30d;
1E hex). The record prefix may be from 1 to 5 characters in length. The
records must be sorted into ascending order, but need not be consecutive.
An example of a properly formated validation file is:
00001 This is record 1
00100 This is record 100
11000 This is record 11000
Because the records are sorted, this function can perform a binary search for
the desired record, resulting in very fast access to any record in a large
file.
If the record cannot be found in the file, or the file cannot be found,
a NULL is returned for the pointer.
C Format:
char * GetRecord
(
char * val_file_name, // Validation file name
unsigned int record_number, // Desired record number
UCHAR digits // Number of digits in zero-padded
// prefix string.
);
Example:
#include "cfrutl26.h"
#include "CFRAPI26.h"
#define PREFIX 5 // 5 digit prefixes used here
#define MAX_WIDTH 80
#define RS "\x1E" // Record separator string
int far main (int funct, char far *params)
{
USHORT xfrcnt; // Vio transfer count
char filename[13];
char * help_ptr;
unsigned int help_rec;
int LenRS; // length to first RS
// character.
char temp[MAX_WIDTH+1];
...
strcpy(filename, "HELP.VAL");
help_rec = 155; // Get record prefixed with 00155
// get line from val file and show the part after the
// record prefix.
help_ptr = GetRecord(filename, help_rec, PREFIX);
if (help_ptr == NULL)
{
char temp[35];
strcpy(temp,"Could not find record #");
itoa((int)msg_start + ctr, &temp[24], 10);
VioWrtCharStr(temp, strlen(temp), 0,0, &xfrcnt, 0);
}
// Make a null-terminated string of the record's data
// handle 'blank lines' in HELP.VAL which have no
// characters but the terminator after the prefix.
if (help_ptr[PREFIX] != 0x1E)
{
strncpy(temp,&help_ptr[PREFIX+1], MAX_WIDTH );
// truncate at RS
lenRS = strcspn(temp, RS);
if ( lenRS != 0 )
temp[lenRS] = '\0';
}
else
{
strcpy(temp," ");
}
VioWrtCharStr(temp, strlen(temp), 0, 0, &xfrcnt, NO_CURSOR_MOVE);
...
}
get_seconds
-----------
Description: This function reads the current time and date from the DCT's
real-time clock and converts it to an unsigned long integer representing the
number of seconds which have elapsed since Janary 1, 1900 at midnight.
This is useful for determining a point in time at which an event started
or the current point in time for comparison to a starting time so that
elapsed time can be calculated (i.e. for time-outs, durations, etc.).
C Format:
unsigned long get_seconds(void);
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
int far main (int funct,char far *params)
{
unsigned long start_time;
...
// get the starting time of the procedure
start_time = get_seconds();
// perform some function (e.g. watch for keypad data,
// just sit and do nothing, show a message) for
// 5 seconds
do
{
// do something
...
}
while (get_seconds() - start_time <= 5);
...
}
GetValRecord
------------
Description: This function returns a pointer to any absolute record within an
on-board terminal validation file. The function works by starting at the
beginning of the file and counting records until it find the one requested.
The first record in the file is considered absolute record zero.
Records may be fixed or variable length. Each record in a 7526 valiation
file is delimited by a record separator character (character 30d; 1E hex).
An example of a properly formated validation file is:
This is record 0
This is record 1
This is record 2
If the record cannot be found in the file, or the file cannot be found,
a NULL is returned for the pointer.
C Format:
char * GetValRecord
(
char * val_file_name, // Validation file name
unsigned int record_number // Desired record number
);
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
#define MAX_WIDTH 80
int far main (int funct,char far *params)
{
USHORT xfrcnt; // Vio transfer count
char filename[13];
char * help_ptr;
unsigned int help_rec;
char temp[MAX_WIDTH+1];
...
strcpy(filename, "HELP.VAL");
help_rec = 155; // Get record 155 (the 156th record
// from the beginning of the file
// get line from val file and show the part after the
// record prefix.
help_ptr = GetValRecord(filename, help_rec);
if (help_ptr == NULL)
{
char temp[35];
strcpy(temp,"Could not find record #");
itoa((int)msg_start + ctr, &temp[24], 10);
VioWrtCharStr(temp, strlen(temp), 0,0, &.xfrcnt, 0);
}
// Make a null-terminated string of the record's data
// by turning RS into NULL, if found before hitting
// NULL put in by strncpy.
strncpy(temp,help_ptr, MAX_WIDTH );
// truncate at RS
lenRS = strcspn(temp, RS);
if ( lenRS != 0 )
temp[lenRS] = '\0';
VioWrtCharStr(help_ptr, strlen(help_ptr), 0, 0,
&.xfrcnt, NO_CURSOR_MOVE);
...
}
GetValRecordFast
----------------
Description: This function returns a pointer to any absolute record within an
on-board terminal validation file. The function works by starting at the
beginning of the file and counting records until it find the one requested.
The first record in the file is considered absolute record zero.
The function learns the location of each offset of 100 records on the first
invocation of the function which searches to or past those locations. On
subsequent invocations, it already knows a short-cut to within 100 records
of the final record. This can save substantial time (as much as 1-2 seconds
on large files) after the function gets warmed up.
The validation file must be limited to under 1,099 records.
The list of learned locations is only valid for the last file name used in
the call. If the next invocation requests another file name, the search must
be done without benefit of learned locations. Thus, if you alternate very
frequently between files searched, the Fast function may be of little value.
A side effect of the function is that the first character of the first record
is changed to a '%' character. This serves as a flag to the function that
the validation file has not been reloaded since it learned the locations of
the 100-record offsets.
Records may be fixed or variable length. Each record in a 7526 valiation
file is delimited by a record separator character (character 30d; 1E hex).
An example of a properly formated validation file is:
This is record 0
This is record 1
This is record 2
If the record cannot be found in the file, or the file cannot be found,
a NULL is returned for the pointer.
C Format:
char * GetValRecordFast
(
char * val_file_name, // Validation file name
unsigned int record_number // Desired record number
);
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
#define MAX_WIDTH 80
int far main (int funct,char far *params)
{
USHORT xfrcnt; // Vio transfer count
char filename[13];
char * help_ptr;
unsigned int help_rec;
char temp[MAX_WIDTH+1];
...
strcpy(filename, "HELP.VAL");
help_rec = 155; // Get record 155 (the 156th record
// from the beginning of the file
// get line from val file and show the part after the
// record prefix.
help_ptr = GetValRecordFast(filename, help_rec);
if (help_ptr == NULL)
{
char temp[35];
strcpy(temp,"Could not find record #");
itoa((int)msg_start + ctr, &temp[24], 10);
VioWrtCharStr(temp, strlen(temp), 0,0, &.xfrcnt, 0);
}
// Make a null-terminated string of the record's data
// by turning RS into NULL, if found before hitting
// NULL put in by strncpy.
strncpy(temp,help_ptr, MAX_WIDTH );
// truncate at RS
lenRS = strcspn(temp, RS);
if (lenRS != 0)
temp[lenRS] = '\0';
VioWrtCharStr(help_ptr, strlen(help_ptr), 0, 0,
&.xfrcnt, NO_CURSOR_MOVE);
...
}
pop_up_wnd
----------
Description: This routine saves the current screen contents and clears the
screen so that a pop-up window may be displayed. Another call to the routine
will restore the display to its original content. The entire screen is
cleared, and an indication of the screen size (model) is returned.
C Format:
unsigned char pop_up_wnd
(
char operation_code // Either CLEAR to clear the window, or REFRESH
// to refresh the display with the orignal data.
);
Returns ONE_LINE_DISPLAY if 7526 model 100 with 1x16 display, or
TWO_LINE_DISPLAY if 7526 model 200 with 2x40 display.
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
int far main (int funct,char far *params)
{
// key.code is an int for evaluating control key reads
// key.chr.mapped gives the key character as mapped by any file a downloaded
// key.chr.base gives the native, unchanging key character
union
{
struct
{
char base;
char mapped;
}
chr;
unsigned short code;
}
key;
...
// Clear a window, show an error message, wait for
// a key to be pressed, and restore screen
pop_up_wnd(CLEAR);
VioWrtCharStr("Invalid numeric input", 11, 0 ,0 , &xfrcnt, NO_CURSOR_MOVE);
VioWrtCharStr("Press any key to continue", 15, 1 ,0 , &xfrcnt, NO_CURSOR_MOVE);
while (KbdReadAscii(&key.code) == E_NO_DATA)
IdleManager(5);
pop_up_wnd(RESTORE);
...
}
print
-----
Description: This routine prints a string on a line printer, checking for
return codes which may indicate a problem with the printing action.
If given a length of 0, it treats the data to be printed as a null-terminated
string and uses strlen to find size. Otherwise, provide the length of the
data to printer (e.g. if it has embedded nulls or you do not want to printer
the entire string).
Specify prt_buffer_size as DEFAULT_PRT (100 bytes) unless you have set a new
buffer location and size. The routine will break up longer strings into
chunks which will fit into the current printer buffer, as defined to the
routine in the buffer size passed to it.
If prt_mode is set to 1 (STOP_ON_ERROR), the 7526 will prompt for user
intervention when an error is encountered. Use 2 (IGNORE_ERROR) to allow the
terminal to ignore printer errors.
C Format:
void print
(
char * prt, // The string to be printed
int length, // Length of the string, or 0 if the string
// is null-terminated so that strlen may be
// used by the print function.
int prt_buf_size, // The current printer buffer size (DEFAULT_BUF if
// PrtSetBuffer has not been used to increase it.
char prt_mode // 1 (STOP_ON_ERROR) to have the 7526 not proceed
// until printer error is cleared, or 2 (IGNORE_ERROR)
// to ignore such errors.
);
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
int far main (int funct,char far *params)
{
...
// print null-terminated string, correct printer errors
print("Badge number", 0, DEF_BUFFER, 1);
...
}
print_char
----------
Description: This routine prints a single character on a line printer,
checking for return codes which may indicate a problem with the printing
action.
If prt_mode is set to 1 (STOP_ON_ERROR), the 7526 will prompt for user
intervention when an error is encountered. Use 2 (IGNORE_ERROR) to allow
the terminal to ignore printer errors.
C Format:
void print_char
(
char prt, // The character to be printed
char prt_mode // 1 (STOP_ON_ERROR) to have the 7526 not proceed
// until printer error is cleared, or 2 (IGNORE_ERROR)
// to ignore such errors.
);
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
int far main (int funct,char far *params)
{
...
// print null-terminated string, correct printer errors
print_char('%', 1);
...
}
read_auto
---------
Description: The read_auto function obtains keypad and/or sensor port input in
the form desired, and shows it in the designated position on the screen. It
will control the method of data input, its maximum length, and numeric
features such as signed/non-signed, integer or floating point.
Data read is returned in key_in_num variable provided by the user. This
buffer must be large enough to hold the length (plus 1) specified in the
call.
When keypad input is enabled, the following keys may be used when the
function has control:
Function Keys Used
-------- ---------
Accept data Left tab (shift-7), Right tab (shift-8), Enter,
or OK (Fill) keys.
Cursor Left Shift-4
Cursor Right Shift-5
Backward Rub-out Shift-6
Note: This key rubs-out the data immediately to
the left of the cursor, and moves all text
past the cursor along with it to the left.
Clear Ends the input in a non-completed state and
returns CLEAR_KEY.
C Format:
int read_auto
(
int length, // Length of the input field; defines maximum keypad
// input length and the length of the underscored
// input field. Maximum value is 39, assuming column
// 0 is used (see below).
UCHAR row, // Starting position of the input field. (0,0) is the
UCHAR col, // upper left corner of the display. The starting column
// plus the length (see above) must total 39 or less
// on a 40-character display, or 15 or less for a 7526-100.
char inputs_allowed, // The input methods allowed in the field. Defined
// input modes are:
//
// AI_ONLY Only bar code and magnetic
// sensor inputs are allowed
// AI_OR_KEYBD Sensor or full keypad input is
// allowed
// KEYBD_ONLY Only full keypad input is allowed
// NUM_KEYBD_ONLY Only numeric keys forming a valid
// number are allowed
// AI_OR_NUMKEYBD Only sensor input (any data) or
// valid numeric keys
// DATE_AMER Date in form DD-MM-YYYY
// DATE_EURO Date in form MM-DD-YYYY
// TIME_STD 24 hour time in form HH:MM:SS
char * prefill, // String of characters to prefill the input field.
// Use empty string for no prefill. Time and date
// format will be filled with input template as a default.
int time_limit, // Number of seconds allowed of inactivity before timeout.
// Values are 1-65535, or 0 for no timeout enforced.
char edit, // Use defines YES and NO to allow editing of the prefilled
// data; NO means prefilled data is cleared as soon as a
// data key is pressed.
char field_signed, // Use YES or NO defines to tell if the negative
// (change sign) key should be allowed.
int field_precision, // -1 for no decimal point allowed, any other value
// allows decimal point to be input.
char * key_in_num, // String buffer for function to place obtained from
// sensors or keypad
);
Return values are:
CLEAR_KEY if Clear key is pressed
LEFT_TAB, RIGHT_TAB, OK_KEY (Fill key), or ENTER_KEY if one of those keys
are pressed to accept the keyed input
AI_READ if bar code or mag scanned
TIME_OUT if time limit expired
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
#define BUFFER_SIZE 40
int far main (int funct,char far *params)
{
char buffer[BUFFER_SIZE];
int rc;
char prefill[10];
...
strcpy( prefill, " 1.50");
// read an signed, real number from the numeric keypad, allowing
// up to 30 seconds for input. Show the 10 position input field
// at row 1, column 20, with a prefilled value.
// Loop while operator presses Clear key
do
{
rc = read_auto(10, 1, 20, NUM_KEYBD_ONLY, prefill, 30, YES, YES,
1, buffer);
switch (rc)
{
case TIME_OUT:
return(ABORT);
break;
case CLEAR_KEY:
// re-do the read with no prefill
strcpy(prefill, "");
break;
}
}
while( rc == CLEAR_KEY );
// return data in UV 1
WriteUserVariable(buffer, 1);
...
}
sprintf_752x / sprintf_752xf
----------------------------
Description: sprintf_752x performs print string formating like the regular C
library sprintf function provides, but without the PC-specific usage of
stdout. All aspects of the function work as printf/sprintf work, except the
following:
- The length of the target buffer area must be provided (to prevent buffer
overruns.
- The output may be automatically displayed at the requested row and column
of the 752x display. 0,0 is the upper left corner of the display. Use -1,
-1 for non-display usage (e.g. for formating a transaction or printer
string).
- The F and N addressing convention prefixes are not supported. The h prefix
(short 'size') is not supported (USHORTS will work with the 'u' type).
- The e, E, g, and G types will be converted to f type.
- The n and p types are not supported.
- The # flag is not supported for any type.
The sprintf_752xf named version of the routine has the floating point support
included. This adds several kilobytes of storage requirements over the basic
sprintf_752x version. However, if you need floating point numbers formated
in a CFR, you should use the floating point version for all calls to avoid
redundant code being included in the file.
C Format:
int sprintf_752x
(
char * buffer, // A pointer to a results work area which your
// program must provide
int buf_size, // The size (in characters) of the buffer provided
// (see above)
int row, // The row and column where you want the resulting
int col, // string shown on the screen. If you do not want
// the string shown, then specify row = -1 (the
// column value may be anything).
char far * format_str, // The output format string specification. Refer
// to the IBM C/2 1.10 Language Reference under
// "printf" for details.
... // The variable number of numeric values, characters,
// and/or string pointers in the order referenced
// in the format string.
);
Return values are:
- OVERFLOW if the resulting string will not fit within the buffer provided
- BAD_WIDTH if a width specified is more than 2 digits long
- BAD_PREC if a precision specified is more than 2 digits long
- BAD_FORMAT_PHRASE if a "%" character is found with no valid trailing
type specifier.
- E_OK if no error occured.
In the event of an error, the formatted string obtained up to the point of
the error is available. Also, if optional automatic display was selected,
the following strings will be appended to the display to show the error
result:
- *** shows that the formatted result exceeded the length of the supplied
buffer
- *1* shows that a bad width was specified for a field
- *2* shows that a bad precision value was specified
- *3* shows that an unknown format identifier was used
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
#define BUFFER_SIZE 100
int far main (int funct,char far *params)
{
char buffer[BUFFER_SIZE];
static int number = 27;
static char string[] = "Hello World";
...
// format a string and show at upper left corner of the display. In this
// example, will show "String = Hello World, Decimal = 27, Hex = 1B"
sprintf_752x(buffer, BUFFER_SIZE, 0, 0,
"String = %s, Decimal = %d, Hex = %X",
string, number, number);
...
}
VioWrtNChar
-----------
Description: This function writes a given character a specified number of
times, begining at a specified location on the display.
C Format:
void VioWrtNChar
(
unsigned char row, // Row for characters to be shown (0 is top)
unsigned char col, // Starting column (0 is left edge)
unsigned char Char, // The character to be replicated
unsigned short count, // The # of times to replicate the character
unsigned short * xfrcnt, // The # of characters successfully written
unsigned char cursor_movement // CURSOR_MOVE or NO_CURSOR_MOVE
);
Example:
#include "cfrutl26.h"
#include "cfrapi26.h"
int far main (int funct,char far *params)
{
unsigned short xfrcnt;
...
// Draw a line of asterisks across the screen
VioWrtNChar(0, 0, '*', 40, &xfrcnt, NO_CURSOR_MOVE);
...
}