/*
 ============================================================================
 Name        : ad-hoc-emulation-example.c
 Author      : zborac
 Copyright   : 
 Description : Example for uFR Ad-Hoc Emulation Mode
 Dependencies: uFR firmware - min. version 3.9.35
               uFRCoder library - min. version 4.0.23
 ============================================================================
 */
#define APP_VERSION		"1.0"

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <windows.h>
#ifndef __linux
#   define DL_uFC_GCC_DLL_IMPORT
#endif
#include "uFCoder.h"
typedef const char * chr_ptr;
#include "main.h"

#define MAX_WAIT_TIME		1000 // [ms]
#define READER_MODE_TIME	200  // [ms] 200 ms is necessary for Samsung Galaxy A5 (2016).
								 //      With other tested Android devices we can set this value to 100 ms.
#define EMULATION_MODE_TIME	300  // [ms]
bool ad_hoc_emul_active = false, automatic_emul_active = false;
uint32_t  ad_hoc_emul_time;
//==============================================================================
int app_loop(void);
UFR_STATUS NewCardInField(uint8_t sak, uint8_t *uid, uint8_t uid_size);
chr_ptr GetDlTypeName(uint8_t dl_type_code);

int main(int argc, char *argv[]) {

	int result = app_loop();

	return result;
}
//==============================================================================
int app_loop(void) {
	UFR_STATUS status;
	bool card_in_field = false;
	uint8_t old_sak = 0, old_uid_size = 0, old_uid[10];
	uint8_t sak, uid_size, uid[10], isExternalFieldPresent;
	uint32_t temp;

	printf( "-----------------------------------------\n"
			"  Example for uFR Ad-Hoc Emulation Mode  \n"
			"             version "APP_VERSION"\n"
			"-----------------------------------------\n"
			"Please wait while opening uFR NFC reader.\n"
			"-----------------------------------------\n");
	status = ReaderOpen();
	if (status != UFR_OK) {
		printf("Error while opening device, status is: 0x%08X\n", status);
		return EXIT_FAILURE;
	}
	printf("uFR NFC reader successfully opened.\n");

	do {
		if (ad_hoc_emul_active) {
			status = GetExternalFieldState(&isExternalFieldPresent);
			if (!isExternalFieldPresent && (temp = (GetTickCount() - ad_hoc_emul_time)) > MAX_WAIT_TIME) {
				status = AdHocEmulationStop();
				ad_hoc_emul_active = false;
				automatic_emul_active = false;
				ad_hoc_emul_time = GetTickCount();
			}
			continue;
		}
		else if (automatic_emul_active) {
			status = GetExternalFieldState(&isExternalFieldPresent);
			if (!isExternalFieldPresent && (temp = (GetTickCount() - ad_hoc_emul_time)) > EMULATION_MODE_TIME) {
				automatic_emul_active = false;
				status = AdHocEmulationStop();
				ad_hoc_emul_time = GetTickCount();
			}
			continue;
		}
		else if ((temp = (GetTickCount() - ad_hoc_emul_time)) > READER_MODE_TIME) {
			automatic_emul_active = true;
			status = AdHocEmulationStart();
			ad_hoc_emul_time = GetTickCount();
		}
		if (!automatic_emul_active) {
			status = GetCardIdEx(&sak, uid, &uid_size);
			switch(status)
			{
			case UFR_OK:
				if (card_in_field) {
					if (old_sak != sak || old_uid_size != uid_size ||
							memcmp(old_uid, uid, uid_size)) {
						old_sak = sak;
						old_uid_size = uid_size;
						memcpy(old_uid, uid, uid_size);
						NewCardInField(sak, uid, uid_size);
					}
				} else {
					old_sak = sak;
					old_uid_size = uid_size;
					memcpy(old_uid, uid, uid_size);
					NewCardInField(sak, uid, uid_size);
					card_in_field = true;
				}
				break;
			case UFR_NO_CARD:
				card_in_field = false;
				status = UFR_OK;
				break;
			default:
//				card_in_field = false;
//				status = UFR_OK;
//				break;
				printf("Fatal error while trying to read card, status is: 0x%08X\n", status);
				return EXIT_FAILURE;
			}
		usleep(APP_LOOP_CYCLE_PERIOD);
		}
	} while (status == UFR_OK);

	ReaderClose();
	return EXIT_SUCCESS;
}

//------------------------------------------------------------------------------
UFR_STATUS NewCardInField(uint8_t sak, uint8_t *uid, uint8_t uid_size) {
	UFR_STATUS status;
	uint8_t dl_card_type;

	status = GetDlogicCardType(&dl_card_type);
	if (status != UFR_OK)
		return status;

	if (dl_card_type == DL_UNKNOWN_ISO_14443_4 && uid_size == 4 &&
					(!memcmp("\001\002\003\004", uid, uid_size)
					 || uid[0] == 8)) {
		printf("\a-------------------------------------------------------------\n");
		printf("Device with NFC Support detected. Switch into emulation mode.\n");
		printf("-------------------------------------------------------------\n");
		ad_hoc_emul_active = true;
		status = AdHocEmulationStart();
		ad_hoc_emul_time = GetTickCount();
		return UFR_OK;
	}

	printf("\a-----------------------------------------------------\n");
	printf("Card type: %s, uid[%d] = ", GetDlTypeName(dl_card_type), uid_size);
	for (int i = 0; i < uid_size; i++) {
		printf("%02X", uid[i]);
		if (i < uid_size - 1) printf(":");
	}
	printf("\n-----------------------------------------------------\n");
	return UFR_OK;
}

//------------------------------------------------------------------------------
chr_ptr GetDlTypeName(uint8_t dl_type_code) {
	static char s[50];

	switch (dl_type_code) {
	case DL_MIFARE_ULTRALIGHT:
		strcpy(s, "DL_MIFARE_ULTRALIGHT");
		break;
	case DL_MIFARE_ULTRALIGHT_EV1_11:
		strcpy(s, "DL_MIFARE_ULTRALIGHT_EV1_11");
		break;
	case DL_MIFARE_ULTRALIGHT_EV1_21:
		strcpy(s, "DL_MIFARE_ULTRALIGHT_EV1_21");
		break;
	case DL_MIFARE_ULTRALIGHT_C:
		strcpy(s, "DL_MIFARE_ULTRALIGHT_C");
		break;
	case DL_NTAG_203:
		strcpy(s, "DL_NTAG_203");
		break;
	case DL_NTAG_210:
		strcpy(s, "DL_NTAG_210");
		break;
	case DL_NTAG_212:
		strcpy(s, "DL_NTAG_212");
		break;
	case DL_NTAG_213:
		strcpy(s, "DL_NTAG_213");
		break;
	case DL_NTAG_215:
		strcpy(s, "DL_NTAG_215");
		break;
	case DL_NTAG_216:
		strcpy(s, "DL_NTAG_216");
		break;
	case DL_MIKRON_MIK640D:
		strcpy(s, "DL_MIKRON_MIK640D");
		break;
	case DL_MIFARE_MINI:
		strcpy(s, "DL_MIFARE_MINI");
		break;
	case DL_MIFARE_CLASSIC_1K:
		strcpy(s, "DL_MIFARE_CLASSIC_1K");
		break;
	case DL_MIFARE_CLASSIC_4K:
		strcpy(s, "DL_MIFARE_CLASSIC_4K");
		break;
	case DL_MIFARE_PLUS_S_2K:
		strcpy(s, "DL_MIFARE_PLUS_S_2K");
		break;
	case DL_MIFARE_PLUS_S_4K:
		strcpy(s, "DL_MIFARE_PLUS_S_4K");
		break;
	case DL_MIFARE_PLUS_X_2K:
		strcpy(s, "DL_MIFARE_PLUS_X_2K");
		break;
	case DL_MIFARE_PLUS_X_4K:
		strcpy(s, "DL_MIFARE_PLUS_X_4K");
		break;
	case DL_MIFARE_DESFIRE:
		strcpy(s, "DL_MIFARE_DESFIRE");
		break;
	case DL_MIFARE_DESFIRE_EV1_2K:
		strcpy(s, "DL_MIFARE_DESFIRE_EV1_2K");
		break;
	case DL_MIFARE_DESFIRE_EV1_4K:
		strcpy(s, "DL_MIFARE_DESFIRE_EV1_4K");
		break;
	case DL_MIFARE_DESFIRE_EV1_8K:
		strcpy(s, "DL_MIFARE_DESFIRE_EV1_8K");
		break;
	case DL_UNKNOWN_ISO_14443_4:
		strcpy(s, "DL_UNKNOWN_ISO_14443_4");
		break;
	case DL_IMEI_UID:
		strcpy(s, "DL_IMEI_UID");
		break;
	default:
		strcpy(s, "UNSUPPORTED CARD");
	}

	return s;
}

//==============================================================================
