//////////////////////////////////////////////////////////////////
//
// App:			Support
// Author:		Milan Korinek
// Version:		1.0
// Notice:		Loging (only for debug!) and support functions
//////////////////////////////////////////////////////////////////


#ifndef SUPPORT_H_
#define SUPPORT_H_

#include <asf.h>



#ifdef NDEBUG
#	define	DIO_NDEBUG
#endif

#ifndef DIO_SEVERITY_MAX
#	define DIO_SEVERITY_MAX			10
#endif

#ifndef DIO_SEV_LEVEL_MIN
#	define DIO_SEVERITY_MIN			0
#endif

#define DIO_SEVERITY_CRITICAL		(DIO_SEVERITY_MAX - 1)
#define DIO_SEVERITY_IMPORTANT		(DIO_SEVERITY_MAX - 2)
#define DIO_SEVERITY_HIGH			(DIO_SEVERITY_MAX - 3)
#define DIO_SEVERITY_MEDIUM			(DIO_SEVERITY_MAX - 4)
#define DIO_SEVERITY_NORMAL			(DIO_SEVERITY_MAX - 5)
#define DIO_SEVERITY_LOW			(DIO_SEVERITY_MAX - 6)

#ifndef DIO_SEVERITY_LEVEL
#	define DIO_SEVERITY_LEVEL		DIO_SEVERITY_NORMAL
#endif

// GCC specific: ## - delete comma if no argument 
#ifdef  DIO_NDEBUG
#	define debug_printf(severity, FORMAT, ...)		((void)0)
#	define debug_puts(severity, MSG)				((void)0)
#	define debug_func_begin(severity, FORMAT, ...)	((void)0)
#	define debug_func_end(severity, FORMAT, ...)	((void)0)
#	define debug_error(severity, FORMAT, ...)		((void)0)
#	define debug_warning(severity, FORMAT, ...)		((void)0)
#	define debug_info(severity, FORMAT, ...)		((void)0)
#	define debug_event(severity, FORMAT, ...)		((void)0)
#else
#	define debug_iprintf(severity, HEADER, FORMAT, ...) \
do { if ((severity) >= DIO_SEVERITY_LEVEL) printf(HEADER "(%d)::%s():: " FORMAT "\r\n", severity, __FUNCTION__, ## __VA_ARGS__); } while ( 0 )
#	define debug_printf(severity, FORMAT, ...) \
do { if ((severity) >= DIO_SEVERITY_LEVEL) printf(FORMAT, ## __VA_ARGS__); } while ( 0 )
#	define debug_func_begin(severity, FORMAT, ...)	debug_iprintf(severity,	"BEGIN", FORMAT, ## __VA_ARGS__)
#	define debug_func_end(severity, FORMAT, ...)	debug_iprintf(severity,	"END", FORMAT, ## __VA_ARGS__)
#	define debug_error(severity, FORMAT, ...)		debug_iprintf(severity,	"ERROR", FORMAT, ## __VA_ARGS__)
#	define debug_warning(severity, FORMAT, ...)		debug_iprintf(severity,	"WARN", FORMAT, ## __VA_ARGS__)
#	define debug_info(severity, FORMAT, ...)		debug_iprintf(severity,	"INFO", FORMAT, ## __VA_ARGS__)
#	define debug_event(severity, FORMAT, ...)		debug_iprintf(severity,	"EVENT", FORMAT, ## __VA_ARGS__)
#endif

#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,


typedef struct _DeviceStateInternal {
	DIO_Behavior_t DeviceBehavior;
	E_DeviceState_t DeviceState;
	E_DeviceConnectionState_t	DeviceConnectionState;
	DIO_PortConfig_t PortsConfiguration[DIO_MAX_PORTS];
} DeviceStateInternal_t;

// Macros is needed for initialization
#define _DIO_BEHAVIOR_DEFAULT	{ DIO_E_MODE_ACCES_DIO }

#define _DIO_PORT_CONFIG_DEFAULT	{ 0x00u, DIO_E_PORTDIR_INPUT, DIO_E_PULLRES_PULLUP }
	
#define _DEVICE_STATE_INTERNAL_DEFAULT {	_DIO_BEHAVIOR_DEFAULT,																						\
											E_DEVICE_STATE_CLOSE,																						\
											E_DEVICE_CONNECTION_STATE_DISCONNECTED,																		\
											{_DIO_PORT_CONFIG_DEFAULT, _DIO_PORT_CONFIG_DEFAULT, _DIO_PORT_CONFIG_DEFAULT, _DIO_PORT_CONFIG_DEFAULT} }	\


#define EP_CONTROL_BUFFER_SIZE	64
#define EP_DATA_BUFFER_SIZE		64

extern const DeviceStateInternal_t DEVICE_STATE_INTERNAL_DEFAULT;

// Global state of Digital I/O USB card
extern DeviceStateInternal_t DeviceStateInt;

extern uint8_t buffer_control[EP_CONTROL_BUFFER_SIZE];
extern bool buffer_control_lock;

void PrintRawPacket(_In_ UINT8 * payload, _In_ UINT payload_length);

void Parse_Copy(_In_ UINT8 * source, _Inout_ UINT * sourcePos, _Out_ void * dest, _In_ size_t size);

void Serialize_Copy(_In_ void * source, _In_ size_t size, _Out_ UINT8 * dest, _Inout_ UINT * destPos);

void Parse_DIO_Behavior_t(_In_ UINT8 * buffer, _Inout_ UINT * buffPos, _Out_ DIO_Behavior_t * structure);

void Serialize_DIO_Behavior_t(_In_ DIO_Behavior_t * structure, _Out_ UINT8 * buffer, _Inout_ UINT * buffPos);

void Parse_DIO_PortConfig_t(_In_ UINT8 * buffer, _Inout_ UINT * buffPos, _Out_ DIO_PortConfig_t * structure);

void Serialize_DIO_PortConfig_t(_In_ DIO_PortConfig_t * structure, _Out_ UINT8 * buffer, _Inout_ UINT * buffPos);


BOOL ParseDeviceConfigurationPacket(_In_ UINT8 * payload,
_In_ UINT payload_length,
_Out_ E_DeviceState_t * DeviceState,
_Out_ DIO_Behavior_t * DeviceBehavior,
_Out_ DIO_PortConfig_t PortsConfiguration[DIO_MAX_PORTS]);

BOOL CreateDeviceConfigurationPacket(_In_ E_DeviceState_t DeviceState,
_In_ DIO_Behavior_t * DeviceBehavior,
_In_ DIO_PortConfig_t PortsConfiguration[DIO_MAX_PORTS],
_Out_ UINT8 * payload,
_Out_ UINT * payload_length);


#endif /* SUPPORT_H_ */