#include "includes.h"

#define DEBUG_PORT	USART6

// 系统TickCount
volatile u32 Systick_TickCount = 0;

// 启动原因代码
volatile uint32_t SYS_RSTSTS = 0;

// 实现stdout的硬件输出
int stdout_putchar(int ch)
{
	if(ch == '\n')
	{
		while(!(DEBUG_PORT->SR & LL_USART_SR_TXE));
		DEBUG_PORT->DR = '\r';
	}
	while(!(DEBUG_PORT->SR & LL_USART_SR_TXE));
	DEBUG_PORT->DR = (uint8_t) ch;
	
	return ch;
}

u32 GetDelayTick(u32 ms)
{
	return GetTickCount() + ms;
}
	
// 考虑了u32溢出翻转的情况
u8 IsTickOut(u32 OutTick)
{
    u32 tick = GetTickCount();

    if(tick > OutTick)
    {
        if(tick - OutTick > 0x80000000UL)
            return 0;
        return 1;
    }
    if(OutTick - tick > 0x80000000UL)
        return 1;
    return 0;
}

// 这个函数必须在初始化完成，中断开启以后才有效
void delay_ms(u32 ms)
{
	u32 tick = GetDelayTick(ms);

	do
	{
	} while(!IsTickOut(tick));
}

void delay_us(uint16_t us)
{
	uint32_t j;
	
	while(us--)
	{
		j = SystemCoreClock / 1000000;
		while(j--);
	}
}

/* ************************************************************************* 
Bootloader和App跳转设计要点

1. Bootloader的程序在前面，大小为8K（0x08000000~0x08001FFF)
   App的程序在后面，从0x08002000开始，大小为0x3E000
2. Bootloader的内存在前面，大小为2K（0x20000000~0x200007FF）
   //App的内存在后面，从0x20000800开始，大小为0xF800
3. 从Bootloader跳转到App：
   1）关闭全局中断响应（__disable_irq）
   2）禁止中断允许（将各中断的允许位清零）
   3）清除中断标志（将各中断的标志位清零）
   4) 设置堆栈（MSP）为App的堆栈值
   5）跳转到App的程序入口
4. 从App跳转到Bootloader：
   直接系统复位，运行Bootloader
5. Bootloader工程的特殊处理
   1）在Target页，按照上述要求设置IROM1和IRAM1
   2）在Linker页，勾选“Use Memory Layout from Target Dialog”
6. App工程的特殊处理
   1）在Target页，按照上述要求设置IROM1和IRAM1
   2）在Linker页，勾选“Use Memory Layout from Target Dialog”
   3) 在system_stm32l4xx.c中修改以下代码：
      a. 将宏定义VECT_TAB_OFFSET改为0x2000
      b. 在SystemInit（）函数最后，重新打开全局中断响应（__enable_irq)
	  
7. 从App的任务中跳转到Bootloader，按第3条的方法试验不成功。
   具体原因未明，可能是因为要关掉的中断太多，没有一一试验；
   也可能是因为FreeRTOS将CPU的特权模式接管了，导致PSP、MSP设置无效等。
************************************************************************* */
typedef void (*pIapFun_TypeDef)(void); //定义一个函数类型的参数.

// 实现从Bootloader跳转到App
void JumpToEntry(uint32_t addr)
{
	printf("\r\nJump to 0x%08X\r\n", addr);
	
	__disable_irq();
	SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);
	__set_MSP(*(volatile uint32_t *) addr);
	((pIapFun_TypeDef) (*(volatile uint32_t *) (addr + 4)))();
	
	// 不应该到这里来
	while(1)
		printf(".");
}

// 实现从App跳转到Bootloader
void JumpToLoader()
{
	printf("\r\nJump to 0x%08X\r\n", (uint32_t) FLASH_BASE);

	// 直接复位，跳转到Bootloader
	HAL_NVIC_SystemReset();

	// 不应该到这里来
	while(1)
		printf(".");
}

// 实现串口发送
USART_Handle huart1 = {USART1, 0, 0, 1, NULL, NULL, NULL, 0, NULL, NULL};
USART_Handle huart2 = {USART2, 0, 0, 1, NULL, NULL, NULL, 0, NULL, NULL};
USART_Handle huart3 = {USART3, 0, 0, 1, NULL, NULL, NULL, 0, NULL, NULL};
USART_Handle huart4 = {UART4, 0, 0, 1, NULL, NULL, NULL, 0, NULL, NULL};
USART_Handle huart6 = {USART6, 0, 0, 1, NULL, NULL, NULL, 0, NULL, NULL};
USART_Handle huart8 = {UART8, 0, 0, 1, NULL, NULL, NULL, 0, NULL, NULL};
USART_Handle huart10 = {UART10, 0, 0, 1, NULL, NULL, NULL, 0, NULL, NULL};

// 实现串口发送
void UART_Transmit(USART_Handle *huart, uint8_t *buf, uint16_t len)
{
	while(len--)
	{
		while(!(huart->Instance->SR & LL_USART_SR_TXE));
		huart->Instance->DR = *buf++;
	}
	while(!(huart->Instance->SR & LL_USART_SR_TC));
}

// 实现以中断方式串口发送
void UART_TxISR_8BIT(USART_Handle *huart)
{
	/* Check that a Tx process is ongoing */
	if(!huart->BusyTx)
		return;
  
    if (huart->TxXferCount == 0U)
    {
		/* Disable the UART Transmit Data Register Empty Interrupt */
		CLEAR_BIT(huart->Instance->CR1, USART_CR1_TXEIE);

		/* Enable the UART Transmit Complete Interrupt */
		SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
    }
    else
    {
		huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr & (uint8_t)0xFF);
		huart->pTxBuffPtr++;
		huart->TxXferCount--;
    }
}

uint8_t UART_Transmit_IT(USART_Handle *huart, uint8_t *pData, uint16_t Size)
{
	/* Check that a Tx process is not already ongoing */
	if(huart->BusyTx)
		return 0;
  
	huart->pTxBuffPtr  = pData;
	huart->TxXferCount = Size;
	huart->TxISR = UART_TxISR_8BIT;
	huart->BusyTx = 1;

	/* Enable the Transmit Data Register Empty interrupt */
	SET_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
	  
	 return 1;
}

// 应用程序的串口中断处理
void APP_USART_IRQHandler(USART_Handle *huart)
{
	uint32_t isrflags   = huart->Instance->SR;
	uint32_t cr1its     = huart->Instance->CR1;

	uint32_t errorflags = (isrflags & ((uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_NE | USART_SR_ORE)));

	// 清除错误状态
	LL_USART_ClearFlag_PE(huart->Instance);
	LL_USART_ClearFlag_FE(huart->Instance);
	LL_USART_ClearFlag_NE(huart->Instance);
	LL_USART_ClearFlag_ORE(huart->Instance);

	/* If no error occurs */
	if (errorflags == 0U)
	{
		/* UART in mode Receiver ---------------------------------------------------*/
		if (((isrflags & USART_SR_RXNE) != 0U)
			&& ((cr1its & USART_CR1_RXNEIE) != 0U))
		{
			if(huart->RxISR)
				huart->RxISR(huart);
			else
				huart->Instance->DR;
		}
		/* UART in mode Transmit ---------------------------------------------------*/
		if (((isrflags & USART_SR_TXE) != 0U)
			&& ((cr1its & USART_CR1_TXEIE) != 0U))
		{
			if(huart->TxISR)
				huart->TxISR(huart);
			else
			{
				// 不应该到这里
				CLEAR_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
				huart->BusyTx = 0;
			}
		}
		/* UART in mode Transmitter (transmission end) -----------------------------*/
		if (((isrflags & USART_SR_TC) != 0U) && ((cr1its & USART_CR1_TCIE) != 0U))
		{
			/* Disable the UART Transmit Complete Interrupt */
			CLEAR_BIT(huart->Instance->CR1, USART_CR1_TCIE);
			// 清除发送忙标志
			huart->BusyTx = 0;
		}
	} 
}

// 读取启动原因代码
void Fetch_ResetFlags()
{
  if(LL_RCC_IsActiveFlag_PORRST())
	  SYS_RSTSTS |= 0x01;
  if(LL_RCC_IsActiveFlag_PINRST())
	  SYS_RSTSTS |= 0x02;
  if(LL_RCC_IsActiveFlag_IWDGRST())
	  SYS_RSTSTS |= 0x04;
  if(LL_RCC_IsActiveFlag_LPWRRST())
	  SYS_RSTSTS |= 0x08;
  if(LL_RCC_IsActiveFlag_BORRST())
	  SYS_RSTSTS |= 0x10;
  if(LL_RCC_IsActiveFlag_SFTRST())
  {
	  SYS_RSTSTS |= 0x20;
	  SYS_RSTSTS &= ~0x13;
  }

  // 清除启动标志
  __HAL_RCC_CLEAR_RESET_FLAGS();
}
