
/*************************************************************************
* Copyright(c) 2023 Levetop Semiconductor Co.,Ltd. All rights reserved.
*
* @file   : FreeRTOS_Task.c
* @Brief  : This program is a demostration for FreeRTOS   
*
* @Version: V1.1
* @Date   : 2024-02-26
*
* @Author : Bert Lee
*************************************************************************/

#include "lt_api.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"

extern const unsigned char BMP1[];
extern const unsigned char BMP2[];

#define configSUPPORT_STATIC_ALLOCATION	1
#define configSUPPORT_DYNAMIC_ALLOCATION 	0

#define TASK_STACK_SIZE 	      			512

#define TASK_QUEUE_LENGTH						10
#define TASK_QUEUE_ITEM_SIZE					16

static StaticSemaphore_t 		mutex_0;
static StaticQueue_t 	 		queue_0,queue_1;
static StaticSemaphore_t 		semaphore_0;
static StaticEventGroup_t 		eventgroup_0;


static SemaphoreHandle_t 		mutex_handler;
static QueueHandle_t 			queue_handler;
static SemaphoreHandle_t 		sem_handler;
static EventGroupHandle_t 		event_handler;

// Define for FreeRTOS system Idle task while using STATIC memory 
StaticTask_t idle_buf;
StackType_t idle_stack[TASK_STACK_SIZE];

// For application tasks
static StaticTask_t task0_buf;
static StaticTask_t task1_buf;
static StaticTask_t task2_buf;
static StaticTask_t task3_buf;
static StaticTask_t task4_buf;
static StaticTask_t task5_buf;
static StaticTask_t task6_buf;
static StaticTask_t task7_buf;


static StackType_t task0_stack[TASK_STACK_SIZE];
static StackType_t task1_stack[TASK_STACK_SIZE];
static StackType_t task2_stack[TASK_STACK_SIZE] __attribute__ ((aligned (4)));
static StackType_t task3_stack[TASK_STACK_SIZE] __attribute__ ((aligned (4)));
static StackType_t task4_stack[TASK_STACK_SIZE] __attribute__ ((aligned (4)));
static StackType_t task5_stack[TASK_STACK_SIZE] __attribute__ ((aligned (4)));
static StackType_t task6_stack[TASK_STACK_SIZE] __attribute__ ((aligned (4)));
static StackType_t task7_stack[TASK_STACK_SIZE] __attribute__ ((aligned (4)));

// Define the counters used in the application...
static uint32_t 	thread_0_counter;
static uint32_t    thread_1_counter;
static uint32_t    thread_2_counter;
static uint32_t    thread_3_counter;
static uint32_t    thread_4_counter;
static uint32_t    thread_5_counter;
static uint32_t    thread_6_counter;
static uint32_t    thread_7_counter;

static uint8_t task1_queue[TASK_QUEUE_LENGTH * TASK_QUEUE_ITEM_SIZE];

uint32_t taskID[10]={0,1,2,3,4,5,6,7,8,9};

void x_application_define(void);

static void task_0_entry(void *p_arg);
static void task_1_entry(void *p_arg);
static void task_2_entry(void *p_arg);
static void task_3_and_4_entry(void *p_arg);
static void task_5_entry(void *p_arg);
static void task_6_and_7_entry(void *p_arg);

void vApplicationGetIdleTaskMemory(StaticTask_t **pxIdleTaskTCBBuffer,StackType_t **pxIdleTaskStackBuffer, uint32_t *ulIdleTaskStackSize )
{
	*pxIdleTaskTCBBuffer=&idle_buf;
	*pxIdleTaskStackBuffer=&idle_stack[0];
	*ulIdleTaskStackSize=TASK_STACK_SIZE;
}

void v_application_define(void)
{
	TaskHandle_t task_result; 	

	// Create task resource
	sem_handler  =xSemaphoreCreateBinaryStatic(&semaphore_0);
	mutex_handler=xSemaphoreCreateMutexStatic(&mutex_0);
	event_handler=xEventGroupCreateStatic(&eventgroup_0);	
	queue_handler=xQueueCreateStatic(TASK_QUEUE_LENGTH,TASK_QUEUE_ITEM_SIZE,&task1_queue[0],&queue_0);

	// Create task
	task_result=xTaskCreateStatic(task_0_entry,      "Event send"   ,TASK_STACK_SIZE,(void *)0 ,1,task0_stack,&task0_buf);
	task_result=xTaskCreateStatic(task_1_entry,      "MsgBuf send"  ,TASK_STACK_SIZE,(void *)1 ,2,task1_stack,&task1_buf);
	task_result=xTaskCreateStatic(task_2_entry,      "MsgBuf rcv"   ,TASK_STACK_SIZE,(void *)2 ,2,task2_stack,&task2_buf);
	task_result=xTaskCreateStatic(task_3_and_4_entry,"Semaphore1"   ,TASK_STACK_SIZE,(void *)3 ,5,task3_stack,&task3_buf);
	task_result=xTaskCreateStatic(task_3_and_4_entry,"Semaphore2"   ,TASK_STACK_SIZE,(void *)4 ,5,task4_stack,&task4_buf);
	task_result=xTaskCreateStatic(task_5_entry,      "Event rcv" 	 ,TASK_STACK_SIZE,(void *)5 ,6,task5_stack,&task5_buf);
	task_result=xTaskCreateStatic(task_6_and_7_entry,"Mutex1"  		 ,TASK_STACK_SIZE,(void *)6 ,8,task6_stack,&task6_buf);
	task_result=xTaskCreateStatic(task_6_and_7_entry,"Mutex2"  		 ,TASK_STACK_SIZE,(void *)7 ,8,task7_stack,&task7_buf);

}

static void task_0_entry(void *p_arg)
{
	EventBits_t status;
	Display_16BitBMP(12,20,BMP1,0xFFFF);
	Display_Text(18,2,24,1,grRED,grYELLOW,"Event Send");
	// This thread simply sits in while-forever-sleep loop.
	while(1)
	{
		// Increment the thread counter.
		if (thread_0_counter<9999) thread_0_counter++;
		else thread_0_counter=0;
		Display_16BitDec(8,9,thread_0_counter,grWHITE,grBLACK);
		// Set event flag 0 to wakeup thread 5.
		status = xEventGroupSetBits(event_handler, 0x04);
		// Check status.
		if (status != 0x04) break;

		// Sleep for 50 ticks.
		vTaskDelay(50);

		if (thread_0_counter%2) Display_16BitBMP(12,20,BMP1,0xFFFF);
		else Display_16BitBMP(12,20,BMP2,0xFFFF);
    }
}

static void task_1_entry(void *p_arg)
{
	BaseType_t status;
	uint8_t txMsg[TASK_QUEUE_ITEM_SIZE]="~LeveTop~";
	
	Display_16BitBMP(176,20,BMP1,0xFFFF);
	Display_Text(192,2,24,1,grRED,grYELLOW,"Msg send");
	// This thread simply sends messages to a queue shared by thread 2.
	while(1)
    {
		// Increment the thread counter.
		if (thread_1_counter<9999) thread_1_counter++;
		else thread_1_counter=0;
		Display_16BitDec(28,9,thread_1_counter,grWHITE,grBLACK);
		// Send message to queue.
		status =  xQueueSend(queue_handler, &txMsg[0], portMAX_DELAY);
		// Check completion status.
		if (status != pdPASS) break;

		vTaskDelay(50);

		if (thread_1_counter%2) Display_16BitBMP(176,20,BMP1,0xFFFF);
		else Display_16BitBMP(176,20,BMP2,0xFFFF);
    }
}

static void task_2_entry(void *p_arg)
{
	BaseType_t  status;
	uint8_t rxMsg[TASK_QUEUE_ITEM_SIZE];
	
	Display_16BitBMP(176,180,BMP1,0xFFFF);
	Display_Text(200,162,24,1,grRED,grYELLOW,"Msg rcv");
	// This thread retrieves messages placed on the queue by thread 1.
	while(1)
	{
		// Increment the thread counter.
		if (thread_2_counter<9999) thread_2_counter++;
		else thread_2_counter=0;
		Display_16BitDec(28,19,thread_2_counter,grWHITE,grBLACK);
		
		// Retrieve a message from the queue.
		status = xQueueReceive(queue_handler, &rxMsg[0],portMAX_DELAY);        // Check completion status and make sure the message is what we expected.
		 
		if (status != pdPASS) break;

		if (thread_2_counter%2) Display_16BitBMP(176,180,BMP1,0xFFFF);
		else Display_16BitBMP(176,180,BMP2,0xFFFF);
    }
}

static void task_3_and_4_entry(void *p_arg)
{
	BaseType_t status;
	UINT32 id=(UINT32) p_arg;

	Display_16BitBMP(340,20,BMP1,0xFFFF);
	Display_Text(346,2,24,1,grRED,grYELLOW,"Semaphore");
	
	// This thread is executed from thread 3 and thread 4.  As the loop
	// below shows, these function compete for ownership of semaphore.
	xSemaphoreGive(sem_handler);
	vTaskDelay(10);
    while(1)
    {
		// Increment the thread counter.
		if (id == 3)
		{
			if (thread_3_counter<9999) thread_3_counter++;
			else thread_3_counter=0;
			Display_16BitDec(46,9,thread_3_counter,grWHITE,grBLACK);
		}
		else
		{
			if (thread_4_counter<9999) thread_4_counter++;
			else thread_4_counter=0;
			Display_16BitDec(52,9,thread_4_counter,grWHITE,grBLACK);
		}

		// Get the semaphore with suspension.
		status = xSemaphoreTake(sem_handler,portMAX_DELAY);	//portMAX_DELAY = WAITING_FOREVER 
		// Check status.
		if (status != pdPASS) break;

		// Sleep for 50 ticks to hold the semaphore.
		vTaskDelay(50);

		// Release the semaphore.
		status = xSemaphoreGive(sem_handler);
		// Check status.
		if (status != pdPASS) break;
		
		if (thread_3_counter%2) Display_16BitBMP(340,20,BMP1,0xFFFF);
		else Display_16BitBMP(340,20,BMP2,0xFFFF);
    }
}

static void task_5_entry(void *p_arg)
{
	EventBits_t status;
	TaskHandle_t  event;

	Display_16BitBMP(12,180,BMP1,0xFFFF);
	Display_Text(24,162,24,1,grRED,grYELLOW,"Event rcv");
	// This thread simply waits for an event in a forever loop.
	while(1)
    {
		// Increment the thread counter.
		if (thread_5_counter<9999) thread_5_counter++;
		else thread_5_counter=0;
		Display_16BitDec(8,19,thread_5_counter,grWHITE,grBLACK);

		// Wait for event flag.
		do
		{
			vTaskDelay(50);
			status = xEventGroupGetBits(event_handler);
		} while (status != 0x04);
		
		status = xEventGroupWaitBits(event_handler,0x04,pdTRUE,pdFALSE,portMAX_DELAY);
		 // Check status.
		if (status!=0x04) break;

		if (thread_5_counter%2) Display_16BitBMP(12,180,BMP1,0xFFFF);
		else Display_16BitBMP(12,180,BMP2,0xFFFF);
    }
}

static void task_6_and_7_entry(void *p_arg)
{
	BaseType_t status;
	UINT32 id=(UINT32) p_arg;

	Display_16BitBMP(340,180,BMP1,0xFFFF);
	Display_Text(376,162,24,1,grRED,grYELLOW,"Mutex");
	// This thread is executed from thread 6 and thread 7.  As the loop
	// below shows, these function compete for ownership of mutex.
	
	xSemaphoreGive(mutex_handler);
	vTaskDelay(10);
	while(1)
	{
		// Increment the thread counter.
		if (id == 6)
		{
			if (thread_6_counter<9999) thread_6_counter++;
			else thread_6_counter=0;
			Display_16BitDec(46,19,thread_6_counter,grWHITE,grBLACK);
		}
		else
		{
			if (thread_7_counter<9999) thread_7_counter++;
			else thread_7_counter=0;
			Display_16BitDec(52,19,thread_7_counter,grWHITE,grBLACK);
		}

		// Get the mutex with suspension.
		status = xSemaphoreTake(mutex_handler,portMAX_DELAY);	 
		// Check status.
		if (status !=pdPASS) break;

		// Sleep for 50 ticks to hold the mutex.
		vTaskDelay(50);

		// Release the mutex.
		status = xSemaphoreGive(mutex_handler);
		// Check status.
		if (status != pdPASS) break;
		
		if (thread_6_counter%2) Display_16BitBMP(340,180,BMP1,0xFFFF);
		else Display_16BitBMP(340,180,BMP2,0xFFFF);
	}
}

