#include <stm32l4xx_hal.h>
#include <stm32_hal_legacy.h>

#include <iostream>
#include <string>
#include <string.h>
#include <stdio.h>
#include <ctime>

#include "ff.h"
#include "stm32l4xx_hal_sd.h"
#include "stm32l4r9i_discovery.h"
#include "stm32l4r9i_discovery_io.h"
#include "stm32l4r9i_discovery_sd.h"
#include "sd_diskio.h"
#include "ff_gen_drv.h"

using namespace std;

#ifdef __cplusplus
extern "C"
#endif
void SysTick_Handler(void)
{
	HAL_IncTick();
	HAL_SYSTICK_IRQHandler();
}

UART_HandleTypeDef s_UARTHandle = UART_HandleTypeDef();
static uint8_t RXBuffer[256];
static uint8_t GPSMessage[32];
static uint16_t GPSMessageIndex = 0;

FATFS SDFatFs; /* File system object for SD card logical drive */
FIL MyFile; /* File object */
char SDPath[4]; /* SD card logical drive path */


extern "C" void LPUART1_IRQHandler()
{
	//cout << "hit LPUART1_IRQHandler" << endl;
	HAL_UART_IRQHandler(&s_UARTHandle);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_Receive_IT(&s_UARTHandle, RXBuffer, 1);
	GPSMessage[GPSMessageIndex] = RXBuffer[0];
	
	FRESULT res; /* FatFs function common result code */
	uint byteswritten; 
	
	if (RXBuffer[0] == '\n')
	{
		cout << "RX GPS Message Complete: " << GPSMessage << endl;
		
		res = f_write(&MyFile, GPSMessage, sizeof(GPSMessage), &byteswritten);
		
		GPSMessageIndex = 0;
		for (int i = 0; i < sizeof(GPSMessage); i++)
			GPSMessage[i] = 0;
	}
	else
		GPSMessageIndex++;
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	//cout << "UART TX Complete" << endl;
}

void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
	cout << "UART TX Half Complete" << endl;
}


static void SystemClock_Config(void);
static void SD_Initialize(void);
static void Error_Handler(void);

static uint8_t isInitialized = 0;
uint8_t workBuffer[_MAX_SS];


int main(void)
{
	HAL_Init();

	__GPIOH_CLK_ENABLE();
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.Pin = GPIO_PIN_4;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStructure.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);

	__LPUART1_CLK_ENABLE();
	__GPIOC_CLK_ENABLE();
	GPIO_InitStructure.Pin = GPIO_PIN_1;
	GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStructure.Alternate = GPIO_AF8_LPUART1;
	GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
	GPIO_InitStructure.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	GPIO_InitStructure.Pin = GPIO_PIN_0;
	GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);

	s_UARTHandle.Instance = LPUART1;
	s_UARTHandle.Init.BaudRate = 9600;
	s_UARTHandle.Init.WordLength = UART_WORDLENGTH_8B;
	s_UARTHandle.Init.StopBits = UART_STOPBITS_1;
	s_UARTHandle.Init.Parity = UART_PARITY_NONE;
	s_UARTHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
	s_UARTHandle.Init.Mode = UART_MODE_TX_RX;
	
	if (HAL_UART_Init(&s_UARTHandle) != HAL_OK)
	{
		cout << "Error in UART_Init" << endl;
		while (1) {}
	}

	NVIC_EnableIRQ(LPUART1_IRQn);
	
	SystemClock_Config();
	
	BSP_IO_Init();
	
	if (FATFS_LinkDriver(&SD_Driver, SDPath) == 0)
	{
		SD_Initialize();
		HAL_NVIC_SetPriority(SysTick_IRQn, 0x0E, 0);
	}
	
	FRESULT res; /* FatFs function common result code */
	uint byteswritten, bytesread; /* File write/read counts */
	uint8_t wtext[] = "2020Jun22 2230 stm32l4r9i-discovery: This is STM32 working with FatFs"; /* File write buffer */
	uint8_t rtext[100]; /* File read buffer */

	SD_Initialize();
	
	/* Register the file system object to the FatFs module */
	if (f_mount(&SDFatFs, (TCHAR const*)SDPath, 0) == FR_OK)
	{
		/* Create and Open a new text file object with write access */
		if (f_open(&MyFile, "uSDExample2020Jun22GPS.TXT", FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
		{
			cout << "Opened MyFile OK" << endl;
			
//			/* Write data to the text file */
//			res = f_write(&MyFile, wtext, sizeof(wtext), &byteswritten);
//
//			if ((byteswritten > 0) && (res == FR_OK))
//			{
//				/* Close the open text file */
//				f_close(&MyFile);
//			}
		}
	}
	
	uint8_t TXBuffer[] = "xxxx$PUBX,00*33\r\n";
	time_t timeNow;
	char tempChar[4];
	
	timeNow = time(NULL);

	cout << "\r\n" << ctime(&timeNow) << "Calling Receive before transmit loop" << endl;
	HAL_UART_Receive_IT(&s_UARTHandle, RXBuffer, 1);
	for (int i = 0; i < 3; i++)
	{
		HAL_GPIO_WritePin(GPIOH, GPIO_PIN_4, GPIO_PIN_SET);
		HAL_Delay(500);
		HAL_GPIO_WritePin(GPIOH, GPIO_PIN_4, GPIO_PIN_RESET);
		HAL_Delay(500);
			
		//Add a counter to TXBuffer
		sprintf(tempChar, "%04i", i);
		for (int j = 0; j < sizeof(tempChar); j++)
			TXBuffer[j] = tempChar[j];
		
		timeNow = time(NULL);
		cout << ctime(&timeNow) << "Calling Transmit,loop number: " << i  << endl;
		HAL_UART_Transmit_IT(&s_UARTHandle, (uint8_t *)TXBuffer, sizeof(TXBuffer));

		HAL_Delay(2000);
		GPSMessageIndex = 0;
	}
	
	f_close(&MyFile);
	
	cout << "Transmit loop complete" << endl;
}

/**
  * @brief  System Clock Configuration
  *         The system Clock is configured as follows :
  *            System Clock source            = PLL (MSI)
  *            SYSCLK(Hz)                     = 120000000
  *            HCLK(Hz)                       = 120000000
  *            AHB Prescaler                  = 1
  *            APB1 Prescaler                 = 1
  *            APB2 Prescaler                 = 1
  *            MSI Frequency(Hz)              = 4000000
  *            PLL_M                          = 1
  *            PLL_N                          = 60
  *            PLL_Q                          = 2
  *            PLL_R                          = 2
  *            PLL_P                          = 7
  *            Flash Latency(WS)              = 5
  * @param  None
  * @retval None
  */
void SystemClock_Config(void)
{
	RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
	RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };

	/* Enable voltage range 1 boost mode for frequency above 80 Mhz */
	__HAL_RCC_PWR_CLK_ENABLE();
	HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
	__HAL_RCC_PWR_CLK_DISABLE();

	/* Enable MSI Oscillator and activate PLL with MSI as source */
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
	RCC_OscInitStruct.MSIState = RCC_MSI_ON;
	RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
	RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
	RCC_OscInitStruct.PLL.PLLM = 1;
	RCC_OscInitStruct.PLL.PLLN = 60;
	RCC_OscInitStruct.PLL.PLLR = 2;
	RCC_OscInitStruct.PLL.PLLQ = 2;
	RCC_OscInitStruct.PLL.PLLP = 7;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
	{
		/* Initialization Error */
		while (1) ;
	}

	/* To avoid undershoot due to maximum frequency, select PLL as system clock source */
	/* with AHB prescaler divider 2 as first step */
	RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
	{
		/* Initialization Error */
		while (1) ;
	}

	/* AHB prescaler divider at 1 as second step */
	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
	{
		/* Initialization Error */
		while (1) ;
	}
}

static void SD_Initialize(void)
{
	if (isInitialized == 0)
	{
		if (BSP_SD_Init() == MSD_OK)
		{
			isInitialized = 1;
		}

		BSP_SD_ITConfig();
	}
}
