/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 *
 * https://www.kozco.com/tech/soundtests.html
 * http://www0.cs.ucl.ac.uk/teaching/GZ05/samples/
 * https://www.adafruit.com/product/3678
 *
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2022 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "fatfs.h"
#include "rng.h"
#include "sai.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "usb_host.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
//#include "ILI9341_Touchscreen.h"
#include "ILI9341_STM32_Driver.h"
#include "ILI9341_GFX.h"

#include "image.h"

#include "snow_tiger.h"

#include <stdio.h>
#include <string.h>
#include <math.h>
#include "wav.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define AUDIO_BUFSIZE (1024*32)

#define MIN(a,b) (((a)<(b))? (a):(b))

#define LCD_LINE_LIMIT 180 // last line position in pixels
#define LCD_LINE_HEIGHT 20 // in pixels
#define LCD_FONT_SIZE 2
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
FATFS FatFs;
FRESULT res;
DIR dir;
FILINFO fno;

extern ApplicationTypeDef Appli_state;

union audioBuffer
{
	int16_t audioBuffer[AUDIO_BUFSIZE];
	uint8_t fileBuffer[AUDIO_BUFSIZE * 2];
} conv8to16;

volatile uint8_t DataTransmittedFlag1of2;
volatile uint8_t DataTransmittedFlag2of2;

uint8_t DataWrittenFlag1of2;
uint8_t DataWrittenFlag2of2;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void PeriphCommonClock_Config(void);
void MX_USB_HOST_Process(void);

/* USER CODE BEGIN PFP */
void GFX_Demo(void);
void ILI9341_Draw_Text_Next_Line_Scroll(const char *Text, uint8_t X,
		uint16_t Colour, uint16_t Size, uint16_t Background_Colour,
		uint32_t Delay, uint16_t Line_Increment, uint16_t Line_Limit);
uint8_t isSupprtedWavFile(const struct Wav_Header *header);
uint8_t playWavFile(char *filename);
void outputSamples(FIL *fil, struct Wav_Header *header);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{
	/* USER CODE BEGIN 1 */

	/* USER CODE END 1 */

	/* MCU Configuration--------------------------------------------------------*/

	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();

	/* USER CODE BEGIN Init */

	/* USER CODE END Init */

	/* Configure the system clock */
	SystemClock_Config();

	/* Configure the peripherals common clocks */
	PeriphCommonClock_Config();

	/* USER CODE BEGIN SysInit */

	/* USER CODE END SysInit */

	/* Initialize all configured peripherals */
	MX_GPIO_Init();
	MX_DMA_Init();
	MX_USART2_UART_Init();
	MX_SPI3_Init();
	MX_RNG_Init();
	MX_TIM1_Init();
	MX_FATFS_Init();
	MX_USB_HOST_Init();
	MX_SAI1_Init();
	/* USER CODE BEGIN 2 */
	ILI9341_Init();
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Fill_Screen(BLACK);
	ILI9341_Draw_Logo((ILI9341_SCREEN_WIDTH - bmBULogo.xSize),
			(ILI9341_SCREEN_HEIGHT - bmBULogo.ySize), &bmBULogo);

	/* USER CODE END 2 */

	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	while (1)
	{
		/* USER CODE END WHILE */
		MX_USB_HOST_Process();

		/* USER CODE BEGIN 3 */
		if (Appli_state == APPLICATION_READY)
		{

			res = f_mount(&FatFs, "", 0);
			if (res != FR_OK)
				return EXIT_FAILURE;

			res = f_opendir(&dir, "");
			if (res != FR_OK)
				return EXIT_FAILURE;

			while (1)
			{
				res = f_readdir(&dir, &fno);
				if (res != FR_OK || fno.fname[0] == 0)
					break;

				char *filename = fno.fname;

				if ((strstr(filename, ".WAV") != 0)
						|| (strstr(filename, ".wav") != 0))
				{
					ILI9341_Draw_Text_Next_Line_Scroll(filename, 10, WHITE,
					LCD_FONT_SIZE,
					BLACK, 500, LCD_LINE_HEIGHT, LCD_LINE_LIMIT);
					playWavFile(filename);
				}
			}
			ILI9341_Draw_Text_Next_Line_Scroll("No more WAV files.", 10, BLUE,
			LCD_FONT_SIZE, BLACK, 1000, LCD_LINE_HEIGHT,
			LCD_LINE_LIMIT);
			res = f_closedir(&dir);
			ILI9341_Draw_Text_Next_Line_Scroll("Press B1 to repeat.", 10, RED,
			LCD_FONT_SIZE, BLACK, 1000, LCD_LINE_HEIGHT,
			LCD_LINE_LIMIT);
			while (HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin))
			{
				HAL_Delay(10);
			}
		}

	}
	/* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
	RCC_OscInitTypeDef RCC_OscInitStruct =
	{ 0 };
	RCC_ClkInitTypeDef RCC_ClkInitStruct =
	{ 0 };

	/** Configure the main internal regulator output voltage
	 */
	if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
	{
		Error_Handler();
	}

	/** Configure LSE Drive Capability
	 */
	HAL_PWR_EnableBkUpAccess();
	__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);

	/** Initializes the RCC Oscillators according to the specified parameters
	 * in the RCC_OscInitTypeDef structure.
	 */
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE
			| RCC_OSCILLATORTYPE_MSI;
	RCC_OscInitStruct.LSEState = RCC_LSE_ON;
	RCC_OscInitStruct.MSIState = RCC_MSI_ON;
	RCC_OscInitStruct.MSICalibrationValue = 0;
	RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
	RCC_OscInitStruct.PLL.PLLM = 1;
	RCC_OscInitStruct.PLL.PLLN = 40;
	RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
	RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
	RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
	{
		Error_Handler();
	}

	/** Initializes the CPU, AHB and APB buses clocks
	 */
	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
			| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
	{
		Error_Handler();
	}

	/** Enable MSI Auto calibration
	 */
	HAL_RCCEx_EnableMSIPLLMode();
}

/**
 * @brief Peripherals Common Clock Configuration
 * @retval None
 */
void PeriphCommonClock_Config(void)
{
	RCC_PeriphCLKInitTypeDef PeriphClkInit =
	{ 0 };

	/** Initializes the peripherals clock
	 */
	PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI1 | RCC_PERIPHCLK_USB
			| RCC_PERIPHCLK_RNG;
	PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1;
	PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1;
	PeriphClkInit.RngClockSelection = RCC_RNGCLKSOURCE_PLLSAI1;
	PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
	PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
	PeriphClkInit.PLLSAI1.PLLSAI1N = 24;
	PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
	PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
	PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
	PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK
			| RCC_PLLSAI1_48M2CLK;
	if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
	{
		Error_Handler();
	}
}

/* USER CODE BEGIN 4 */
void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
	HAL_GPIO_WritePin(LOGIC_ANALYZER_A5_GPIO_Port, LOGIC_ANALYZER_A5_Pin,
			GPIO_PIN_SET);
	DataTransmittedFlag1of2 = 1;
}

void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
{
	HAL_GPIO_WritePin(LOGIC_ANALYZER_A5_GPIO_Port, LOGIC_ANALYZER_A5_Pin,
			GPIO_PIN_RESET);
	DataTransmittedFlag2of2 = 1;
}

void outputSamples(FIL *fil, struct Wav_Header *header)
{

	ILI9341_Draw_Text_Next_Line_Scroll("Playing WAV file.", 10, GREEN,
	LCD_FONT_SIZE, BLACK, 1000, LCD_LINE_HEIGHT, LCD_LINE_LIMIT);

	uint32_t bytes_last = header->dataChunkLength;

	DataTransmittedFlag1of2 = 0;
	DataTransmittedFlag2of2 = 0;
	memset(conv8to16.audioBuffer, 0, sizeof(conv8to16.audioBuffer));
	HAL_SAI_Transmit_DMA(&hsai_BlockA1, (uint8_t*) (&conv8to16.audioBuffer),
	AUDIO_BUFSIZE);
	DataWrittenFlag2of2 = 1;

	while (0 < bytes_last)
	{

		int blksize = MIN(bytes_last, AUDIO_BUFSIZE);

		UINT bytes_read;
		FRESULT res;

		if (DataTransmittedFlag1of2 && DataWrittenFlag2of2)
		{
			HAL_GPIO_WritePin(LOGIC_ANALYZER_A4_GPIO_Port,
			LOGIC_ANALYZER_A4_Pin, GPIO_PIN_SET);
			DataTransmittedFlag1of2 = 0;

			res = f_read(fil, &conv8to16.fileBuffer[0], blksize, &bytes_read);
			if (res != FR_OK || bytes_read == 0)
				break;

			bytes_last -= blksize;
			DataWrittenFlag1of2 = 1;
			DataWrittenFlag2of2 = 0;
			HAL_GPIO_WritePin(LOGIC_ANALYZER_A4_GPIO_Port,
			LOGIC_ANALYZER_A4_Pin, GPIO_PIN_RESET);
		}
		else if (DataTransmittedFlag2of2 && DataWrittenFlag1of2)
		{
			HAL_GPIO_WritePin(LOGIC_ANALYZER_A3_GPIO_Port,
			LOGIC_ANALYZER_A3_Pin, GPIO_PIN_SET);
			DataTransmittedFlag2of2 = 0;

			res = f_read(fil, &conv8to16.fileBuffer[AUDIO_BUFSIZE], blksize,
					&bytes_read);
			if (res != FR_OK || bytes_read == 0)
				break;

			bytes_last -= blksize;
			DataWrittenFlag2of2 = 1;
			DataWrittenFlag1of2 = 0;
			HAL_GPIO_WritePin(LOGIC_ANALYZER_A3_GPIO_Port,
			LOGIC_ANALYZER_A3_Pin, GPIO_PIN_RESET);
		}
		else
		{
			;
//			ILI9341_Draw_Text_Next_Line_Scroll("Waiting for DMA.", 10, RED, 1, BLACK, 0,
//					LCD_LINE_HEIGHT, LCD_LINE_LIMIT);
		}
	}
	HAL_SAI_DMAStop(&hsai_BlockA1);
}

uint8_t isSupprtedWavFile(const struct Wav_Header *header)
{
	if (strncmp(header->riff, "RIFF", 4) != 0)
		return 0;

	if (header->vfmt != 1)
		return 0;

	if (strncmp(header->dataChunkHeader, "data", 4) != 0)
		return 0;

	return 1;
}

uint8_t playWavFile(char *filename)
{
	FIL fil;
	FRESULT res;
	UINT count = 0;

	struct Wav_Header header;

	res = f_open(&fil, filename, FA_READ);
	if (res != FR_OK)
		return 1;

	res = f_read(&fil, &header, sizeof(struct Wav_Header), &count);
	if ((res != FR_OK) || (!isSupprtedWavFile(&header)))
	{
		res = f_close(&fil);
		return 1;
	}
	else
	{
		outputSamples(&fil, &header);
		res = f_close(&fil);
		if (res != FR_OK)
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}
}

void ILI9341_Draw_Text_Next_Line_Scroll(const char *Text, uint8_t X,
		uint16_t Colour, uint16_t Size, uint16_t Background_Colour,
		uint32_t Delay, uint16_t Line_Increment, uint16_t Line_Limit)
{
	static uint16_t line_number = 0;

	if ((line_number + Line_Increment) > Line_Limit)
	{
		ILI9341_Fill_Screen(BLACK);
		ILI9341_Draw_Logo((ILI9341_SCREEN_WIDTH - bmBULogo.xSize),
				(ILI9341_SCREEN_HEIGHT - bmBULogo.ySize), &bmBULogo);
		line_number = 0;
	}

	ILI9341_Draw_Text(Text, X, line_number, Colour, Size, Background_Colour);
	line_number = line_number + Line_Increment;
	HAL_Delay(Delay);
}

void GFX_Demo(void)
{
	//----------------------------------------------------------PERFORMANCE TEST
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("FPS TEST, 40 loop 2 screens", 10, 10, BLACK, 1,
	WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	uint32_t Timer_Counter = 0;
	for (uint32_t j = 0; j < 2; j++)
	{
		HAL_TIM_Base_Start(&htim1);
		for (uint16_t i = 0; i < 10; i++)
		{
			ILI9341_Fill_Screen(WHITE);
			ILI9341_Fill_Screen(BLACK);
		}

		//20.000 per second!
		HAL_TIM_Base_Stop(&htim1);
		Timer_Counter += __HAL_TIM_GET_COUNTER(&htim1);
		__HAL_TIM_SET_COUNTER(&htim1, 0);
	}
	Timer_Counter /= 2;

	char counter_buff[30];
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	sprintf(counter_buff, "Timer counter value: %li", Timer_Counter * 2);
	ILI9341_Draw_Text(counter_buff, 10, 10, BLACK, 1, WHITE);

	double seconds_passed = 2 * ((float) Timer_Counter / 20000);
	sprintf(counter_buff, "Time: %.3f Sec", seconds_passed);
	ILI9341_Draw_Text(counter_buff, 10, 30, BLACK, 2, WHITE);

	double timer_float = 20 / (((float) Timer_Counter) / 20000); //Frames per sec

	sprintf(counter_buff, "FPS:  %.2f", timer_float);
	ILI9341_Draw_Text(counter_buff, 10, 50, BLACK, 2, WHITE);
	double MB_PS = timer_float * 240 * 320 * 2 / 1000000;
	sprintf(counter_buff, "MB/S: %.2f", MB_PS);
	ILI9341_Draw_Text(counter_buff, 10, 70, BLACK, 2, WHITE);
	double SPI_utilized_percentage = (MB_PS / (6.25)) * 100;  //50mbits / 8 bits
	sprintf(counter_buff, "SPI Utilized: %.2f", SPI_utilized_percentage);
	ILI9341_Draw_Text(counter_buff, 10, 90, BLACK, 2, WHITE);
	HAL_Delay(5000);

	static uint16_t x = 0;
	static uint16_t y = 0;

	char Temp_Buffer_text[40];

	//----------------------------------------------------------IMAGE EXAMPLE, Snow Tiger
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("RGB Picture", 10, 10, BLACK, 1, WHITE);
	ILI9341_Draw_Text("TIGER", 10, 20, BLACK, 1, WHITE);
	HAL_Delay(2000);
	ILI9341_Draw_Image((const char*) snow_tiger, SCREEN_VERTICAL_2);
	ILI9341_Set_Rotation(SCREEN_VERTICAL_1);
	HAL_Delay(5000);

	//----------------------------------------------------------COUNTING MULTIPLE SEGMENTS
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Counting multiple segments at once", 10, 10, BLACK, 1,
	WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	for (uint16_t i = 0; i <= 10; i++)
	{
		sprintf(Temp_Buffer_text, "Counting: %d", i);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 10, BLACK, 2, WHITE);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 30, BLUE, 2, WHITE);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 50, RED, 2, WHITE);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 70, GREEN, 2, WHITE);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 90, BLACK, 2, WHITE);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 110, BLUE, 2, WHITE);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 130, RED, 2, WHITE);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 150, GREEN, 2, WHITE);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 170, WHITE, 2, BLACK);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 190, BLUE, 2, BLACK);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 210, RED, 2, BLACK);
	}

	HAL_Delay(1000);

	//----------------------------------------------------------COUNTING SINGLE SEGMENT
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Counting single segment", 10, 10, BLACK, 1, WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	for (uint16_t i = 0; i <= 100; i++)
	{
		sprintf(Temp_Buffer_text, "Counting: %d", i);
		ILI9341_Draw_Text(Temp_Buffer_text, 10, 10, BLACK, 3, WHITE);
	}

	HAL_Delay(1000);

	//----------------------------------------------------------ALIGNMENT TEST
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Rectangle alignment check", 10, 10, BLACK, 1, WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	ILI9341_Draw_Hollow_Rectangle_Coord(50, 50, 100, 100, BLACK);
	ILI9341_Draw_Filled_Rectangle_Coord(20, 20, 50, 50, BLACK);
	ILI9341_Draw_Hollow_Rectangle_Coord(10, 10, 19, 19, BLACK);
	HAL_Delay(1000);

	//----------------------------------------------------------LINES EXAMPLE
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Randomly placed and sized", 10, 10, BLACK, 1, WHITE);
	ILI9341_Draw_Text("Horizontal and Vertical lines", 10, 20, BLACK, 1,
	WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	for (uint32_t i = 0; i < 30000; i++)
	{
		uint32_t random_num = 0;
		uint16_t xr = 0;
		uint16_t yr = 0;
		uint16_t radiusr = 0;
		uint16_t colourr = 0;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		xr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		yr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		radiusr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		colourr = random_num;

		xr &= 0x01FF;
		yr &= 0x01FF;
		radiusr &= 0x001F;
		//ili9341_drawpixel(xr, yr, WHITE);
		ILI9341_Draw_Horizontal_Line(xr, yr, radiusr, colourr);
		ILI9341_Draw_Vertical_Line(xr, yr, radiusr, colourr);
	}

	HAL_Delay(1000);

	//----------------------------------------------------------HOLLOW CIRCLES EXAMPLE
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Randomly placed and sized", 10, 10, BLACK, 1, WHITE);
	ILI9341_Draw_Text("Circles", 10, 20, BLACK, 1, WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	for (uint32_t i = 0; i < 3000; i++)
	{
		uint32_t random_num = 0;
		uint16_t xr = 0;
		uint16_t yr = 0;
		uint16_t radiusr = 0;
		uint16_t colourr = 0;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		xr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		yr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		radiusr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		colourr = random_num;

		xr &= 0x01FF;
		yr &= 0x01FF;
		radiusr &= 0x001F;
		//ili9341_drawpixel(xr, yr, WHITE);
		ILI9341_Draw_Hollow_Circle(xr, yr, radiusr * 2, colourr);
	}
	HAL_Delay(1000);

	//----------------------------------------------------------FILLED CIRCLES EXAMPLE
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Randomly placed and sized", 10, 10, BLACK, 1, WHITE);
	ILI9341_Draw_Text("Filled Circles", 10, 20, BLACK, 1, WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	for (uint32_t i = 0; i < 1000; i++)
	{
		uint32_t random_num = 0;
		uint16_t xr = 0;
		uint16_t yr = 0;
		uint16_t radiusr = 0;
		uint16_t colourr = 0;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		xr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		yr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		radiusr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		colourr = random_num;

		xr &= 0x01FF;
		yr &= 0x01FF;
		radiusr &= 0x001F;
		//ili9341_drawpixel(xr, yr, WHITE);
		ILI9341_Draw_Filled_Circle(xr, yr, radiusr / 2, colourr);
	}
	HAL_Delay(1000);

	//----------------------------------------------------------HOLLOW RECTANGLES EXAMPLE
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Randomly placed and sized", 10, 10, BLACK, 1, WHITE);
	ILI9341_Draw_Text("Rectangles", 10, 20, BLACK, 1, WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	for (uint32_t i = 0; i < 20000; i++)
	{
		uint32_t random_num = 0;
		uint16_t xr = 0;
		uint16_t yr = 0;
		uint16_t radiusr = 0;
		uint16_t colourr = 0;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		xr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		yr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		radiusr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		colourr = random_num;

		xr &= 0x01FF;
		yr &= 0x01FF;
		radiusr &= 0x001F;
		//ili9341_drawpixel(xr, yr, WHITE);
		ILI9341_Draw_Hollow_Rectangle_Coord(xr, yr, xr + radiusr, yr + radiusr,
				colourr);
	}
	HAL_Delay(1000);

	//----------------------------------------------------------FILLED RECTANGLES EXAMPLE
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Randomly placed and sized", 10, 10, BLACK, 1, WHITE);
	ILI9341_Draw_Text("Filled Rectangles", 10, 20, BLACK, 1, WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	for (uint32_t i = 0; i < 20000; i++)
	{
		uint32_t random_num = 0;
		uint16_t xr = 0;
		uint16_t yr = 0;
		uint16_t radiusr = 0;
		uint16_t colourr = 0;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		xr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		yr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		radiusr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		colourr = random_num;

		xr &= 0x01FF;
		yr &= 0x01FF;
		radiusr &= 0x001F;
		//ili9341_drawpixel(xr, yr, WHITE);
		ILI9341_Draw_Rectangle(xr, yr, radiusr, radiusr, colourr);
	}
	HAL_Delay(1000);

	//----------------------------------------------------------INDIVIDUAL PIXEL EXAMPLE

	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Slow draw by selecting", 10, 10, BLACK, 1, WHITE);
	ILI9341_Draw_Text("and adressing pixels", 10, 20, BLACK, 1, WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	x = 0;
	y = 0;
	while (y < 240)
	{
		while ((x < 320) && (y < 240))
		{

			if (x % 2)
			{
				ILI9341_Draw_Pixel(x, y, BLACK);
			}

			x++;
		}

		y++;
		x = 0;
	}

	x = 0;
	y = 0;

	while (y < 240)
	{
		while ((x < 320) && (y < 240))
		{

			if (y % 2)
			{
				ILI9341_Draw_Pixel(x, y, BLACK);
			}

			x++;
		}

		y++;
		x = 0;
	}
	HAL_Delay(2000);

	//----------------------------------------------------------INDIVIDUAL PIXEL EXAMPLE
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Random position and colour", 10, 10, BLACK, 1,
	WHITE);
	ILI9341_Draw_Text("500000 pixels", 10, 20, BLACK, 1, WHITE);
	HAL_Delay(2000);
	ILI9341_Fill_Screen(WHITE);

	for (uint32_t i = 0; i < 500000; i++)
	{
		uint32_t random_num = 0;
		uint16_t xr = 0;
		uint16_t yr = 0;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		xr = random_num;
		random_num = HAL_RNG_GetRandomNumber(&hrng);
		yr = random_num;
		uint16_t color = HAL_RNG_GetRandomNumber(&hrng);

		xr &= 0x01FF;
		yr &= 0x01FF;
		ILI9341_Draw_Pixel(xr, yr, color);
	}
	HAL_Delay(2000);

	//----------------------------------------------------------565 COLOUR EXAMPLE, Grayscale
	ILI9341_Fill_Screen(WHITE);
	ILI9341_Set_Rotation(SCREEN_HORIZONTAL_2);
	ILI9341_Draw_Text("Colour gradient", 10, 10, BLACK, 1, WHITE);
	ILI9341_Draw_Text("Grayscale", 10, 20, BLACK, 1, WHITE);
	HAL_Delay(2000);

	for (uint16_t i = 0; i <= (320); i++)
	{
		uint16_t Red = 0;
		uint16_t Green = 0;
		uint16_t Blue = 0;

		Red = i / (10);
		Red <<= 11;
		Green = i / (5);
		Green <<= 5;
		Blue = i / (10);

		uint16_t RGB_color = Red + Green + Blue;
		ILI9341_Draw_Rectangle(i, x, 1, 240, RGB_color);

	}
	HAL_Delay(2000);
}
/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
	/* USER CODE BEGIN Error_Handler_Debug */
	/* User can add his own implementation to report the HAL error return state */
	__disable_irq();
	while (1)
	{
	}
	/* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
