/* This file demonstrates how to enumerate Baltech USB/HID devices.
 *
 * This enumeration feature is primarily needed when multiple readers might be
 * connected to the PC and the user needs to select a specific one. If only one
 * reader is connected, using brp_create_usb_hid(0) is sufficient.
 *
 * It is implemented as single threaded console application that:
 * 1. Enumerates all connected Baltech USB/HID devices using an iterator
 * 2. Displays information about each device
 * 3. Demonstrates using an enumerated protocol to communicate with a reader
 *
 * ATTENTION: To make this sample working on linux, you need to install
 *            /appnotes/usb_hid/baltech_linux_usb_hid.rules
 *            (see the comments in this file)
 */


#include <stdio.h>
#include <stdlib.h>
#include <brp_lib.h>
#include <baltech_sdk.h>


static void exit_on_error(brp_errcode errcode, char *errormessage,
						  brp_protocol dev)
{
	if (errcode != BRP_OK)
	{
		char * errname = brp_map_errcode(errcode);
		if (errname == NULL)
			fprintf(stderr, "%s [brp_errcode:%08X]\n", errormessage, errcode);
		else
			fprintf(stderr, "%s [%s]\n", errormessage, errname);
		brp_destroy(dev);
		exit(EXIT_FAILURE);
	}
}


int main(int argc, char *argv[])
{
	brp_errcode errcode;
	brp_ioiter iter;
	brp_protocol protocol;
	brp_protocol first_protocol = NULL;
	size_t dev_cnt = 0;

	// Create iterator for Baltech USB/HID devices
	printf("Enumerating Baltech USB/HID devices...\n");
	iter = brp_ioiter_create_usb_hid();
	if (iter == NULL)
	{
		fprintf(stderr, "Failed to create device iterator (out of memory)\n");
		return EXIT_FAILURE;
	}

	// Iterate through all devices
	while (1)
	{
		errcode = brp_ioiter_next(iter, &protocol);
		if (errcode != BRP_OK)
		{
			brp_ioiter_destroy(&iter);
			exit_on_error(errcode, "failed to iterate devices", first_protocol);
		}

		// Check if we reached the end
		if (protocol == NULL)
			break;

		// Display device information
		char* intf_name = NULL;
		char* friendly_name = NULL;
		struct brp_frame_t device_id_frame;
		brp_frame_init(&device_id_frame);

		brp_get_io_id(protocol, &intf_name, &device_id_frame);
		brp_get_friendly_name(protocol, &friendly_name);

		printf("  [%zu] %s: %s\n", dev_cnt,
			intf_name ? intf_name : "Unknown",
			device_id_frame.ptr ? (char*)device_id_frame.ptr : "Unknown");
		if (friendly_name != NULL)
			printf("      Product: %s\n", friendly_name);

		brp_frame_deinit(&device_id_frame);
		dev_cnt++;

		// Keep first protocol to demonstrate usage, clean up others
		if (first_protocol == NULL)
			first_protocol = protocol;
		else
			brp_destroy(protocol);
	}

	// Clean up iterator
	brp_ioiter_destroy(&iter);

	if (dev_cnt == 0)
	{
		printf("\nNo Baltech USB/HID devices found.\n");
		return EXIT_SUCCESS;
	}
	else
	{
		printf("\nFound %zu device(s) total.\n", dev_cnt);
	}

	// Demonstrate that the enumerated protocol can be used like any other
	// protocol created via brp_create_usb_hid()
	// The iterator returns IO protocols, so we need to wrap it in a BRP protocol
	printf("\nConnecting to first device to demonstrate protocol usage...\n");

	brp_protocol dev = brp_create();
	exit_on_error(dev == NULL ? BRP_ERR_OUT_OF_MEMORY : BRP_OK,
	              "failed to create BRP protocol", first_protocol);

	errcode = brp_set_io(dev, first_protocol);
	exit_on_error(errcode, "failed to set IO protocol", dev);

	errcode = brp_open(dev);
	exit_on_error(errcode, "failed to connect to device", dev);

	char * fws;
	errcode = brp_Sys_GetInfo((brp_Sys_GetInfo_t){dev, .Info=&fws});
	exit_on_error(errcode, "failed to retrieve firmware string", dev);

	printf("Firmware: %s\n", fws);

	brp_destroy(dev);
	return EXIT_SUCCESS;
}
