/*
 * projekt_wyklad_3.c
 *
 * Created: 2020-10-10 09:45:33
 * Author : Zbyszek
 */ 


#include "sam.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

unsigned long int ci=0, cp=0, ct=0, placebo=0;
char h1=0, h2=0;
TaskHandle_t xHandle1 = NULL, xHandle2 = NULL;
QueueHandle_t xQueue;
//TimerHandle_t xTimers[2/* NUM_TIMERS */];

/* Define an enumerated type used to identify the source of the data. */
typedef enum
{
	eSender1,
	eSender2
} DataSource_t;
/* Define the structure type that will be passed on the queue. */
typedef struct
{
	uint8_t ucValue;
	DataSource_t eDataSource;
} Data_t;
/* Declare two variables of type Data_t that will be passed on the queue. */
static const Data_t xStructsToSend[ 2 ] =
{
	{ 100, eSender1 }, /* Used by Sender1. */
	{ 200, eSender2 }  /* Used by Sender2. */
};

void vApplicationIdleHook( void )
{
	ci++;
}

void vApplicationTickHook( void )
{
	long fh= xPortGetFreeHeapSize();
	//uxTaskGetStackHighWaterMark(&xHandle1);
	//uxTaskGetStackHighWaterMark(&xHandle2);
	ct++;
}


void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName )
{
	for(;;);
}

void vApplicationMallocFailedHook( void )
{
	for(;;);
}

void vApplicationDaemonTaskStartupHook( void )
{
	ci=0;
	cp=0;
	ct=0;
}


void vTaskCode1( void * pvParameters )
{
	unsigned char p = 1; //(unsigned char) pvParameters;
	h1=1;
	
	// configASSERT( ( ( uint32_t ) pvParameters ) == 1 );

	//PORTB=(1<<PB5) | PORTB;

	for( ;; )
	{
		if(p==1)
		{
			//DDRA = 0xff;
			//PORTA = 0xff;
		}
		else
		{
			//DDRC = 0xff;
			//PORTC = 0xff;
		}
		
		vTaskDelay(10/ portTICK_PERIOD_MS);
		//taskYIELD();
	}
}

void vTaskCode2( void * pvParameters )
{
	unsigned char p = 2; // (unsigned char) pvParameters;
	h2=1;
	// configASSERT( ( ( uint32_t ) pvParameters ) == 1 );

//	PORTB=(1<<PB5) | PORTB;

	for( ;; )
	{
		if(p==1)
		{
			//DDRA = 0xff;
			//PORTA = 0xff;
		}
		else
		{
			//DDRC = 0xff;
			//PORTC = 0xff;
		}
		
		vTaskDelay(10/ portTICK_PERIOD_MS);
		//taskYIELD();
	}
}

int32_t lExpireCounters[ 2/*NUM_TIMERS*/ ] = { 0 };
//void vTimerCallback( TimerHandle_t pxTimer )
//{
	//int32_t lArrayIndex;
	//const int32_t xMaxExpiryCountBeforeStopping = 10;
	//
	//// Optionally do something if the pxTimer parameter is NULL.
	//configASSERT( pxTimer );
	//
	//// Which timer expired?
	//lArrayIndex = ( int32_t ) pvTimerGetTimerID( pxTimer );
	//
	//// Increment the number of times that pxTimer has expired.
	//lExpireCounters[ lArrayIndex ] += 1;
	//
	//// If the timer has expired 10 times then stop it from running.
	//if( lExpireCounters[ lArrayIndex ] == xMaxExpiryCountBeforeStopping )
	//{
		//// Do not use a block time if calling a timer API function from a
		//// timer callback function, as doing so could cause a deadlock!
		//xTimerStop( pxTimer, 0 );
	//}
//}

static void vSenderTask( void *pvParameters )
{
	BaseType_t xStatus;
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 100 );
	for( ;; )
	{
		xStatus = xQueueSendToBack( xQueue, pvParameters, xTicksToWait );
		if( xStatus != pdPASS )
		{
			placebo++;
			//vPrintString( "Could not send to the queue.\r\n" );
		}
		taskYIELD();
	}
}

static void vReceiverTask( void *pvParameters )
{
	Data_t xReceivedStructure;
	BaseType_t xStatus;
	for( ;; )
	{
		if( uxQueueMessagesWaiting( xQueue ) != 3 )
		{
			placebo++;
			//vPrintString( "Queue should have been full!\r\n" );
		}
		xStatus = xQueueReceive( xQueue, &xReceivedStructure, 0 );
		if( xStatus == pdPASS )
		{
			if( xReceivedStructure.eDataSource == eSender1 )
			{
				placebo++;
				//vPrintStringAndNumber( "From Sender 1 = ", xReceivedStructure.ucValue );
			}
			else
			{
				placebo++;
				//vPrintStringAndNumber( "From Sender 2 = ", xReceivedStructure.ucValue );
			}
		}
		else
		{
			placebo++;
			//vPrintString( "Could not receive from the queue.\r\n" );
		}
	}
}

int main(void)
{
	BaseType_t xReturned1, xReturned2;
	//static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
	//cli();
	//OCR1B=0xffff;
	//OCR1C=0xffff;
	//	TIMSK0=0x01;
	//	TCCR0A=0;
	//	TCCR0B=0x05;

	//DDRB = 0xff;
	//PORTB=~(1<<PB5) | PORTB;
	//PORTB=(1<<PB5) | PORTB;

	//for(int x = 0; x < 2/*NUM_TIMERS*/; x++ )
	//{
		//xTimers[ x ] = xTimerCreate(    "Timer",       // Just a text name, not used by the kernel.
		//( 100 * x ),   // The timer period in ticks.
		//pdTRUE,        // The timers will auto-reload themselves when they expire.
		//( void * ) x,  // Assign each timer a unique id equal to its array index.
		//vTimerCallback // Each timer calls the same callback when it expires.
		//);
		//
		//if( xTimers[ x ] == NULL )
		//{
			//// The timer was not created.
		//}
		//else
		//{
			//// Start the timer.  No block time is specified, and even if one was
			//// it would be ignored because the scheduler has not yet been
			//// started.
			//if( xTimerStart( xTimers[ x ], 0 ) != pdPASS )
			//{
				//// The timer could not be set into the Active state.
			//}
		//}
	//}

	xQueue = xQueueCreate( 3, sizeof( Data_t ) );
	if( xQueue != NULL )
	{
		xTaskCreate( vSenderTask, "Sender1", 1000, &( xStructsToSend[ 0 ] ), 2, NULL );
		xTaskCreate( vSenderTask, "Sender2", 1000, &( xStructsToSend[ 1 ] ), 2, NULL );
		
		xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL );
	}

//	xReturned1 = xTaskCreate(vTaskCode1, "A", 1*200, NULL/*( void * ) 1*/, 2, &xHandle1); //tskIDLE_PRIORITY
//	xReturned2 = xTaskCreate(vTaskCode2, "B", 1*200, NULL/*( void * ) 2*/, 2, &xHandle2); //tskIDLE_PRIORITY
/*	if(( xReturned1 != pdPASS ) || ( xReturned2 != pdPASS ))
	//if( xReturned1 != pdPASS )
	{
		vTaskDelete( xHandle1 );
		vTaskDelete( xHandle2 );
		for(;;);
	}*/
	size_t h = xPortGetFreeHeapSize();
	
	vTaskStartScheduler();
	
	while (1)
	{
		cp++;
	}
}


//ISR(BADISR_vect)
//{
//	for(;;);// user code here
//}
