//////////////////////////////////////////////////////////////////
//
// App:			Digital I/O USB Card Library
// Author:		Milan Korinek
// Version:		1.0
// Notice:		API interface of Digital I/O USB Card Library
//////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <stdio.h>

#include "GlobalDevicesLists.h"
#include "support.h"
#include "Communication.h"
#include <stdint.h>


/* ============================================ */
/*				Local functions					*/
/* ============================================ */

NOMANGLE static DIO_Errors_t CheckBeforeContinue(_In_ UINT32 Module, _Out_ DeviceInfoInternal_t ** DeviceInfo);


/* ============================================ */
/*					Globals						*/
/* ============================================ */

//! DLL is itialized if function DIO_Initialize() was successful and it is not initialized after DIO_Clear(). 
static BOOL Is_DLL_Initialized = FALSE;

/* ============================================ */
/*				Local functions					*/
/* ============================================ */

static DIO_Errors_t CheckBeforeContinue(_In_ UINT32 Module, _Out_ DeviceInfoInternal_t ** DeviceInfo)
{
	int index;

	if (!Is_DLL_Initialized) {
		debug_warning(DIO_SEVERITY_CRITICAL, "DLL is not initialized. Can not continue.");
		return DIO_ERROR_FAIL_NOT_INIT;
	}

	if (DeviceInfo != NULL) {
		// Exists device with this module?
		index = FindDeviceInfoByModule(Module, DeviceInfo); 
		if (index < 0) {
			debug_warning(DIO_SEVERITY_CRITICAL, "END, Could not find device. Module = %d, ret list index = %d.", Module, index);
			return DIO_ERROR_FAIL_NOT_EXISTS;
		}
	}

	return DIO_ERROR_SUCCESS;
}


/* ============================================ */
/*				General functions				*/
/* ============================================ */

DIO_Errors_t DIO_Initialize(void)
{
	DIO_Errors_t retValue;
	printf("----- %d \n", sizeof(DIO_E_Mode_t));
	debug_func_begin(DIO_SEVERITY_CRITICAL, "");

	if (Is_DLL_Initialized) {
		debug_warning(DIO_SEVERITY_CRITICAL, "DLL 'Digital_IO_USB_Card' is initialized. Can not continue.");
		return DIO_ERROR_ALREADY_INIT;
	}

	// Initialize USB, Device Lists
	if ((retValue = InitiateLists()) != DIO_ERROR_SUCCESS) {
		debug_error(DIO_SEVERITY_CRITICAL, "Could not create Device Info Internal List, error status = %d.", retValue);
		retValue = DIO_ERROR_FAIL_INIT;
		goto CleanUp;
	}	
	
	Is_DLL_Initialized = TRUE;
	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", DIO_ERROR_SUCCESS);
	return DIO_ERROR_SUCCESS;

CleanUp:
	DIO_Clear();
	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}

DIO_Errors_t DIO_Clear(void)
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;
	DIO_Errors_t retErr;
	
	debug_func_begin(DIO_SEVERITY_CRITICAL, "");

	// Free USB, Device Lists
	if ((retErr = FreeLists()) != DIO_ERROR_SUCCESS) retValue = retErr;

	Is_DLL_Initialized = FALSE;
	debug_func_end(DIO_SEVERITY_IMPORTANT, "error status = %d", retValue);
	return retValue;
}

UINT32 DIO_GetDevices(void)
{
	if (!Is_DLL_Initialized) {
		debug_warning(DIO_SEVERITY_CRITICAL, "DLL is not initialized. Can not continue.");
		return 0;
	}

	return GetDeviceInfoListCount();
}

DIO_Errors_t DIO_GetDeviceInfo(_In_ UINT32 Module, _Out_ DIO_DeviceInfo_t * DeviceInfo)
{
	DIO_Errors_t retValue;
	DeviceInfoInternal_t *device;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "module = %d", Module);

	retValue = CheckBeforeContinue(Module, &device);
	if (retValue != DIO_ERROR_SUCCESS) return retValue;

	if (DeviceInfo != NULL) * DeviceInfo = device->DeviceInfo;
	debug_func_begin(DIO_SEVERITY_CRITICAL, "success = 1");
	return DIO_ERROR_SUCCESS;
}

/* ============================================ */
/*		Configuration functions	 			    */
/* ============================================ */


DIO_Errors_t DIO_OpenDevice(_In_ UINT32 Module)
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;
	DIO_Errors_t retErr;
	DeviceInfoInternal_t *device;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "module = %d", Module);

	retValue = CheckBeforeContinue(Module, &device);
	if (retValue != DIO_ERROR_SUCCESS) return retValue;

	if ((retErr = OpenDevice(device)) != DIO_ERROR_SUCCESS) retValue = retErr;

	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}


DIO_Errors_t DIO_CloseDevice(_In_ UINT32 Module)
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;
	DIO_Errors_t retErr;
	DeviceInfoInternal_t *device;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "module = %d", Module);

	retValue = CheckBeforeContinue(Module, &device);
	if (retValue != DIO_ERROR_SUCCESS) return retValue;

	if ((retErr = CloseDevice(device)) != DIO_ERROR_SUCCESS) retValue = retErr;

	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}


DIO_Errors_t DIO_CloseDevices(void)
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "");

	if (!Is_DLL_Initialized) {
		debug_warning(DIO_SEVERITY_CRITICAL, "DLL is not initialized. Can not continue.");
		return DIO_ERROR_FAIL_INIT;
	}

	retValue = CloseDevices();

	//serialize_int

	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}

DIO_Errors_t DIO_SetDeviceConfiguration(_In_ UINT32 Module, _In_ DIO_Behavior_t DeviceBehavior, _In_ DIO_PortConfig_t PortsConfiguration[DIO_MAX_PORTS])
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;
	DeviceInfoInternal_t *device;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "");

	retValue = CheckBeforeContinue(Module, &device);
	if (retValue != DIO_ERROR_SUCCESS) return retValue;

	if (DeviceBehavior.Mode == DIO_E_MODE_ACCES_DIO) {
		retValue = SetDeviceConfiguration(device, &DeviceBehavior, PortsConfiguration);
	} else {
		debug_warning(DIO_SEVERITY_CRITICAL, "Unknown requested Behavior mode %d.", DeviceBehavior.Mode);
		retValue = DIO_ERROR_FAIL_UNKNOWN_REQUEST;
	}

	

	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}


/* ============================================ */
/*			Device access functions				*/
/* ============================================ */

/* ------ DIO_E_Mode_t.DIO_MODE_ACCES_DIO ------- */

DIO_Errors_t DIO_WriteAll(_In_ UINT32 Module, _In_ UINT8 Data[DIO_MAX_PORTS])
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;
	DeviceInfoInternal_t *device;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "");

	retValue = CheckBeforeContinue(Module, &device);

	if (retValue == DIO_ERROR_SUCCESS) 
		retValue = DeviceImmediateRW(TRUE, device, DIO_MAX_PORTS, 0, Data);

	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}

DIO_Errors_t DIO_Write8(_In_ UINT32 Module, _In_ UINT32 PortIndex, _In_ UINT8 Data)
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;
	DeviceInfoInternal_t *device;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "");

	retValue = CheckBeforeContinue(Module, &device);

	if (retValue == DIO_ERROR_SUCCESS) 
		retValue = DeviceImmediateRW(TRUE, device, 1, PortIndex, &Data);

	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}

DIO_Errors_t DIO_Write1(_In_ UINT32 Module, _In_ UINT32 Channel, _In_ BOOL Data)
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;
	DeviceInfoInternal_t *device;
	UINT8 settings = Data;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "");

	retValue = CheckBeforeContinue(Module, &device);

	if (retValue == DIO_ERROR_SUCCESS) 
		retValue = DeviceImmediateRW(TRUE, device, 0, Channel, &settings);

	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}

DIO_Errors_t DIO_ReadAll(_In_ UINT32 Module, _Out_ UINT8 Data[DIO_MAX_PORTS])
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;
	DeviceInfoInternal_t *device;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "");

	retValue = CheckBeforeContinue(Module, &device);

	if (retValue == DIO_ERROR_SUCCESS) 
		retValue = DeviceImmediateRW(FALSE, device, DIO_MAX_PORTS, 0, Data);

	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}

DIO_Errors_t DIO_Read8(_In_ UINT32 Module, _In_ UINT32 PortIndex, _Out_ UINT8 * Data)
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;
	DeviceInfoInternal_t *device;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "");

	retValue = CheckBeforeContinue(Module, &device);

	if (retValue == DIO_ERROR_SUCCESS) 
		retValue = DeviceImmediateRW(FALSE, device, 1, PortIndex, Data);

	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}

DIO_Errors_t DIO_Read1(_In_ UINT32 Module, _In_ UINT32 Channel, _Out_ BOOL * Data)
{
	DIO_Errors_t retValue = DIO_ERROR_SUCCESS;
	DeviceInfoInternal_t *device;
	UINT8 settings;

	debug_func_begin(DIO_SEVERITY_CRITICAL, "");

	retValue = CheckBeforeContinue(Module, &device);

	if (retValue == DIO_ERROR_SUCCESS) {
		retValue = DeviceImmediateRW(FALSE, device, 0, Channel, &settings);
		*Data = (BOOL)settings;
	}

	debug_func_end(DIO_SEVERITY_CRITICAL, "error status = %d", retValue);
	return retValue;
}
