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); ... }