Hi Mark:
Got interrupted with a support call.
The below clarion code is using a different set of group, types with same array style in question.
This has an example of use:
Thanks
~Peter
ABS_BIR_HEADER GROUP,TYPE
Length ULONG
HeaderVersion BYTE
Type BYTE
FormatOwner SHORT
FormatID SHORT
Quality BYTE
Purpose BYTE
FactorsMask ULONG
End
ABS_BIR_HEADER_1 Like(ABS_BIR_HEADER)
ABS_BIR Group, Dim(16), TYPE !dim(16)
abs_bir_Header Long !Address(ABS_BIR_HEADER)
abs_bir_Data BYTE,DIM(ABS_VARLEN)
End
ABS_BIR_1 Like(ABS_BIR)
</* Maximal template set size. */
#define TSET_SIZE 16
/* We use trivial template set representation, as an array of pointers
* to ABS_BIR. Unused slots are set to NULL. */
static ABS_BIR* tset[TSET_SIZE];
/* 0 - BIR was obtained via a ABS_* call (and thus should be freed
* by ABSFree()),
* 1 - BIR was created manually and should be freed with free(). */
static char tsetAttr[TSET_SIZE];
/* BSAPI session handle. */
static ABS_CONNECTION conn = 0;
/* Pointer to ABS_OPERATION is taken as a parameter by those BSAPI
* funtions which work as interactive operation. The main purpose of it is
* to pass pointer to the callback function into the interactive functions.
*
* It also allows to specifie some flags and/or timeout.
*
* In this sample we reuse this one operation instance. In real complex
* application you may need to use special ABS_OPERATION instance for
* each BSAPI interactive operation. This allows you to use specialized
* callback for them, past various flags etc.
*/
static ABS_OPERATION op = {
/* ID of the operation. We don't need to identify the operation in this
* sample. When non-zero, the ID identifies the operation and allows it
* to be canceled from any other thread with ABSCancelOperation(). */
0,
/* Arbitrary pointer, which allows application to pass any data into
* the callback. Not used in this sample. */
NULL,
/* Pointer to a simple callback implementation function. */
callback,
/* Timeout. For example, lets set timeout to 60 sec. Note the value does
* not limit how long the operation (e.g. ABSVerify()) can take. The
* timeout only specifies time the operation waits for user to put his
* finger on a sensor. Zero would mean no timeout (i.e. the operation can
* never end if user never puts his finger on the sensor.) */
60000,
/* By default BSAPI places short time delays between sending some important
* callback messages. The purpose of this is to guarantee that if multiple
* messages come very closely in sequence, then the user still has enough
* time to see all the messages and not just the lat one of the fast
* sequence.
*
* For application developer, this simplifies callback implementation
* which in most cases can be just showing an appropriate message in a
* window or dialog.
*
* However the time delays are not needed when user can see all history
* of the messages, e.g. (as in this sample) the messages are outputted
* to standard output stream. Hence we disable the time delays with with
* the flag ABS_OPERATION_FLAG_LL_CALLBACK here. */
ABS_OPERATION_FLAG_LL_CALLBACK
};
/* Helper function, asking the user to choose what slot in the template set
* to work with. Returns number of the slot or -1 if the slot can not be used.
*/
static int
choose_slot(const char* msg)
{
int slot;
printf("%s: ", msg);
scanf("%d", &slot);
if(slot < 0 || slot >= TSET_SIZE) {
printf("No such slot.\n");
return -1;
}
if(tset[slot] == NULL) {
printf("Slot %d is not enrolled.\n", slot);
return -1;
}
return slot;
}
/* Open BSAPI session. Note that this sample allows only one session
* at a time to be opened. */
static void
cmd_open(void)
{
ABS_STATUS res;
ABS_DEVICE_LIST* dev_list;
int dev_index;
printf("Openening a session...\n");
/* Check whether it's not already open. It is possible to use multiple
* sessions from one process, but it would make this sample much more
* copmplex, and most applications do not need that anyway. */
if(conn != 0) {
printf("The session is already open.\n");
return;
}
/* Enumerate all supported USB devices and decide which one of them to
* use. */
res = ABSEnumerateDevices("usb", &dev_list);
if(res != ABS_STATUS_OK) {
printf("ABSEnumerateDevices() failed.\n");
status_info(res);
return;
}
if(dev_list->NumDevices == 0) {
printf("No fingerprint device found.\n");
return;
}
if(dev_list->NumDevices == 1) {
/* There is a single device, so take it. */
dev_index = 0;
} else {
/* There is more then one device connected: Ask user which one
* of them to use. */
int i;
printf("Found devices: \n");
for(i = 0; i < (int)dev_list->NumDevices; i++)
printf(" %d %s\n", i, dev_list->List[i].DsnSubString);
printf("Enter number of device you want to use: ");
scanf("%d", &dev_index);
if(dev_index < 0 || dev_index >= (int)dev_list->NumDevices) {
printf("No such device.\n");
return;
}
}
/* Open the selected device. */
printf("Opening device '%s'...\n", dev_list->List[dev_index].DsnSubString);
res = ABSOpen(dev_list->List[dev_index].DsnSubString, &conn);
if(res != ABS_STATUS_OK) {
ABSFree(dev_list);
printf("ABSOpen() failed.\n");
status_info(res);
return;
}
/* Release memory allocated for the device list. */
ABSFree(dev_list);
printf("Opened successfully.\n");
}
/* Close BSAPI session */
static void
cmd_close(void)
{
ABS_STATUS res;
printf("Closing the current session...\n");
/* close the connection */
res = ABSClose(conn);
if(res != ABS_STATUS_OK) {
printf("ABSClose() failed.\n");
status_info(res);
return;
}
conn = 0;
}
/* Add (enroll) new template into the template set. */
static void
cmd_add(void)
{
int i;
int slot = -1;
ABS_STATUS res;
printf("Add new template...\n");
/* find an empty slot */
for(i = 0; i < TSET_SIZE; i++) {
if(tset[i] == NULL) {
slot = i;
break;
}
}
if(slot < 0) {
printf("Cannot add new template. The template set is full.\n");
return;
}
/* enroll the tamplate into the slot */
res = ABSEnroll(conn, &op, &tset[slot], 0);
if(res != ABS_STATUS_OK) {
printf("ABSEnroll() failed.\n");
status_info(res);
return;
}
printf("Successfully enrolled into the template set as slot #%d.\n", slot);
}
/* Import a template from a file into the template set. */
static void
cmd_import(void)
{
int i;
int slot = -1;
char templateFileName[1024];
FILE *f;
long fileSize;
printf("Import a template...\n");
/* find an empty slot */
for(i = 0; i < TSET_SIZE; i++) {
if(tset[i] == NULL) {
slot = i;
break;
}
}
if(slot < 0) {
printf("Cannot add new template. The template set is full.\n");
return;
}
/* ask user for the filename */
printf("Please enter template file name: ");
if (scanf("%s", templateFileName) != 1) {
printf("Cannot get the file name.\n");
return;
}
f = fopen(templateFileName, "rb");
if (f == NULL) {
printf("Cannot open file '%s'.\n", templateFileName);
return;
}
if (fseek(f, 0, SEEK_END) != 0) {
printf("Cannot seek in file '%s'.\n", templateFileName);
fclose(f);
return;
}
fileSize = ftell(f);
if (fileSize < 0) {
printf("Cannot determine the size of file '%s'.\n", templateFileName);
fclose(f);
return;
}
if (fseek(f, 0, SEEK_SET) != 0) {
printf("Cannot seek back in file '%s'.\n", templateFileName);
fclose(f);
return;
}
tset[slot] = (ABS_BIR*)malloc(fileSize);
if (tset[slot] == NULL) {
printf("Cannot allocate %ld bytes.\n", fileSize);
fclose(f);
return;
}
if (fread(tset[slot], fileSize, 1, f) != 1) {
printf("Cannot read %ld bytes from file '%s'.\n", fileSize,
templateFileName);
free(tset[slot]);
tset[slot] = NULL;
fclose(f);
return;
}
tsetAttr[slot] = 1;
fclose(f);
printf("Successfully imported into the template set as slot #%d.\n", slot);
}
/* Export a template from the template set into a file. */
static void
cmd_export(void)
{
int slot;
char templateFileName[1024];
FILE *f;
printf("Exporting a template from the template set...\n");
/* Ask user which templates to compare */
slot = choose_slot("Enter slot number of template to export");
if(slot < 0)
return;
/* ask user for the filename */
printf("Please enter template file name: ");
if (scanf("%s", templateFileName) != 1) {
printf("Cannot get the file name.\n");
return;
}
f = fopen(templateFileName, "wb");
if (f == NULL) {
printf("Cannot open file '%s'.\n", templateFileName);
return;
}
if (fwrite(tset[slot], tset[slot]->Header.Length, 1, f) != 1) {
printf("Cannot write %u bytes to file '%s'.\n",
tset[slot]->Header.Length, templateFileName);
fclose(f);
return;
}
fclose(f);
printf("Successfully exported template from the slot #%d to file '%s'.\n",
slot, templateFileName);
}
/* Remove one slot from the template set */
static void
cmd_delete(void)
{
int slot;
printf("Delete a template from the template set...\n");
/* Ask user which slot to delete */
slot = choose_slot("Enter slot number to delete from template set");
if(slot < 0)
return;
/* And just do it */
if (tsetAttr[slot] != 0)
free(tset[slot]);
else
ABSFree(tset[slot]);
tset[slot] = NULL;
printf("Successfully deleted slot %d\n", slot);
}
/* Remove all templates stored in the template set */
static void
cmd_delete_all(void)
{
int i;
printf("Delete all templates from the template set...\n");
/* Remove all templates in the template set */
for(i = 0; i < TSET_SIZE; i++) {
if(tset[i] != NULL) {
if (tsetAttr[i] != 0)
free(tset[i]);
else
ABSFree(tset[i]);
tset[i] = NULL;
}
}
printf("Successfully deleted all slots\n");
}
/* This function only lists which slots on the template sets are used
* (i.e. which contain an enrolled template). */
static void
cmd_list(void)
{
int i;
int empty = 1;
printf("Listing which slots are used (enrolled)...\n");
printf("Enrolled slots: ");
for(i = 0; i < TSET_SIZE; i++) {
if(tset[i] != NULL) {
printf("%d ", i);
empty = 0;
}
}
if(empty)
printf("none\n");
else
printf("\n");
}
/* Verify user's finger against one template in the set */
static void
cmd_verify(void)
{
int slot;
ABS_STATUS res;
ABS_LONG matching_slot;
printf("Verify user's finger against a template in template set...\n");
/* Ask user which template to compare with */
slot = choose_slot("Enter slot number to match against");
if(slot < 0)
return;
/* And just do it. Note that matching_slot is set to index of the
* matching slot in the template set or -1 is no one matches. Here
* we pass in only the one template we are interested in, so in case of
* match it will be zero. */
res = ABSVerify(conn, &op, 1, &tset[slot], &matching_slot, 0);
if(res != ABS_STATUS_OK) {
printf("ABSVerify() failed\n");
status_info(res);
return;
}
if(matching_slot == 0) {
printf("Match\n");
} else if(matching_slot < 0) {
printf("No match\n");
} else {
/* this never happen */
assert(0);
}
}
/* Here we compare the user's finger with all templates stored in the set */
static void
cmd_verify_all(void)
{
int i;
ABS_BIR* tmp_tset[TSET_SIZE];
int tmp_slot[TSET_SIZE];
ABS_DWORD count = 0;
ABS_STATUS res;
ABS_LONG index;
printf("Verify user's finger against all templates in template set...\n");
/* Functions ABSVerify accepts an arbitrary count of templates to verify
* the scanned finger against. It expects pointers to the templates in an
* array of pointers to ABS_BIR structures. This matches our template
* set representation, however our template set might have some gaps
* (NULLs) in the array, so we copy the BIR pointers to a temporary array
* without the gaps (i.e. NULL values can be only on tail of the array).
* Therefore we also have to save the original index so we can map the
* resulting matching index to the original slot number.
*
* During the work we also count how many templates are in the set.
*/
for(i = 0; i < TSET_SIZE; i++) {
if(tset[i] != NULL) {
tmp_tset[count] = tset[i];
tmp_slot[count] = i;
count++;
}
}
if(count == 0) {
printf("The template set is empty.\n");
return;
}
/* Now we can compare the finger against all the templates in the
* temporary array */
res = ABSVerify(conn, &op, count, tmp_tset, &index, 0);
if(res != ABS_STATUS_OK) {
printf("ABSVerify() failed\n");
status_info(res);
return;
}
/* Find out the slot number (index in the tset array) */
if(index >= 0) {
printf("Slot %d matches.\n", tmp_slot[index]);
} else {
printf("No slot matches.\n");
}
}
/* Here we compare two templates from the template set */
static void
cmd_verify_match(void)
{
int slot1, slot2;
ABS_STATUS res;
ABS_BOOL match;
printf("Comparing two templates in the template set...\n");
/* Ask user which templates to compare */
slot1 = choose_slot("Enter slot number of template 1 to compare");
if(slot1 < 0)
return;
slot2 = choose_slot("Enter slot number of template 2 to compare");
if(slot2 < 0)
return;
/* Now compare the two templates. Note this is not interactive operation.
* I.e. the user is not asked to manipulate with the sensor, nor the
* function takes pointer to ABS_OPERATION. */
res = ABSVerifyMatch(conn, tset[slot1], tset[slot2], &match, 0);
if(res != ABS_STATUS_OK) {
printf("ABSVerifyMatch() failed.\n");
status_info(res);
return;
}
if(match)
printf("Templates %d and %d do match.\n", slot1, slot2);
else
printf("Templates %d and %d do NOT match.\n", slot1, slot2);
}
/* Writes down simple help. */
static void
cmd_help(void)
{
printf("Press any of the following keys to do the corresponding action:\n");
printf(" o ... open BSAPI session\n");
printf(" c ... close the BSAPI session\n");
printf(" a ... add new template into the template set\n");
printf(" i ... import a template into the template set\n");
printf(" e ... export a template from the template set to a file\n");
printf(" d ... delete template from the template set\n");
printf(" D ... delete all templates from the template set\n");
printf(" l ... list templates in the template set\n");
printf(" v ... verify finger against one template\n");
printf(" V ... verify finger against complete template set\n");
printf(" m ... match two templates from the template set\n");
printf(" h ... writes down this help message\n");
printf(" q ... quit this sample program\n");
}
int
main(int argc, char** argv)
{
ABS_STATUS res;
int i;
int done = 0;
char buffer[256];
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
printf(
"This sample shows BSAPI as it can be used in typical real application\n"
"The sample keeps a fingerprint template set in memory and provides\n"
"functions for manipulating with the template set as adding new\n"
"template into it (enrollment), removing it, various verification\n"
"and matching functions.\n"
"\n"
"Note that when started, it does not open session to the device\n"
"automatically so before you can use any command operating with\n"
"the fingerprint device you have to open it with 'o'.\n"
"\n"
"In this regard behavior of the sample may differ from real life\n"
"applications which may call ABSOpen() just after ABSInitialize().\n"
"\n"
"This design was chosen so that you can manually close and reopen\n"
"the session, and that you can see which functions require an open\n"
"session and which do not.\n"
"\n"
);
/* initialize BSAPI */
res = ABSInitialize();
if(res != ABS_STATUS_OK) {
printf("ABSInitilize() failed\n");
status_info(res);
return -1;
}
/* ensure the template set is empty */
for(i = 0; i < TSET_SIZE; i++)
{
tset[i] = NULL;
tsetAttr[i] = 0;
}
/* On the start, always show the help */
cmd_help();
while(!done) {
/* Ask the use what to do... */
printf("\n");
printf("\n>> ");
scanf("%s", buffer);
/* ...and then just do that. */
switch(buffer[0]) {
case 'o': cmd_open(); break;
case 'c': cmd_close(); break;
case 'a': cmd_add(); break;
case 'i': cmd_import(); break;
case 'e': cmd_export(); break;
case 'd': cmd_delete(); break;
case 'D': cmd_delete_all(); break;
case 'l': cmd_list(); break;
case 'v': cmd_verify(); break;
case 'V': cmd_verify_all(); break;
case 'm': cmd_verify_match(); break;
case 'q': done = 1; break;
case '?':
case 'h': cmd_help(); break;
default:
printf("Unknown command. Press 'h' to get help.\n");
break;
}
}
/* Release any templates kept in the template set. */
for(i = 0; i < TSET_SIZE; i++) {
if(tset[i] != NULL) {
if (tsetAttr[i] != 0)
free(tset[i]);
else
ABSFree(tset[i]);
tset[i] = NULL;
}
}
/* If BSAPI session is opened, close it */
if(conn != 0)
cmd_close();
/* Free any resources allocated in ABSInitialize. */
ABSTerminate();
return 0;
}