

#include "board.h"
#include "stm32f10x.h"


#define UART_Initer() {.USART_WordLength=USART_WordLength_8b,\
  .USART_StopBits=USART_StopBits_1,\
  .USART_Parity=USART_Parity_No,\
  .USART_HardwareFlowControl=USART_HardwareFlowControl_None,\
  .USART_Mode=USART_Mode_Rx | USART_Mode_Tx,\
}

#define GPIO_Initer() {.GPIO_Speed=GPIO_Speed_50MHz,\
  .GPIO_Mode=GPIO_Mode_AF_PP,\
}



#define NVIC_Initer() {0}



#define DMA_RX_Initer() {\
  .DMA_DIR = DMA_DIR_PeripheralSRC,\
  .DMA_PeripheralInc = DMA_PeripheralInc_Disable,\
  .DMA_MemoryInc = DMA_MemoryInc_Enable,\
  .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte,\
  .DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte,\
  .DMA_Mode = DMA_Mode_Normal,\
  .DMA_Priority = DMA_Priority_High,\
  .DMA_M2M = DMA_M2M_Disable,\
  .DMA_BufferSize = 0,\
}


#define DMA_TX_Initer() {\
  .DMA_DIR = DMA_DIR_PeripheralDST,\
  .DMA_PeripheralInc = DMA_PeripheralInc_Disable,\
  .DMA_MemoryInc = DMA_MemoryInc_Enable,\
  .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte,\
  .DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte,\
  .DMA_Mode = DMA_Mode_Normal,\
  .DMA_Priority = DMA_Priority_High,\
  .DMA_M2M = DMA_M2M_Disable,\
  .DMA_BufferSize = 0,\
}




typedef struct{
  char *name;
  USART_TypeDef *uart;
  void (*uart_clock_fun)(uint32_t,FunctionalState);
  uint32_t uart_rcc;
  int baudrate;
  int irq_channel;
  
  void (*gpio_tx_clock_fun)(uint32_t,FunctionalState);
  uint32_t gpio_tx_rcc;
  GPIO_TypeDef *gpio_tx_base;
  uint16_t gpio_tx_pin;
  void (*gpio_rx_clock_fun)(uint32_t,FunctionalState);
  uint32_t gpio_rx_rcc;
  GPIO_TypeDef *gpio_rx_base;
  uint16_t gpio_rx_pin;
  
  DMA_Channel_TypeDef *dma_rx_channel;
  void (*dma_rx_clock_fun)(uint32_t,FunctionalState);
  uint32_t dma_rx_rcc;
  
  DMA_Channel_TypeDef *dma_tx_channel;
  void (*dma_tx_clock_fun)(uint32_t,FunctionalState);
  uint32_t dma_tx_rcc;
  int dma_tx_irq_channel;
  uint32_t dma_tx_tc_flag;
  
}uart_dtb;




static const uart_dtb g_uartdtb[]={
  {
    .name="uart1",
    .uart=USART1,
    .uart_clock_fun=RCC_APB2PeriphClockCmd,
    .uart_rcc=RCC_APB2Periph_USART1,
    .baudrate=38400,
    .irq_channel=USART1_IRQn,
    
    .gpio_tx_clock_fun=RCC_APB2PeriphClockCmd,
    .gpio_tx_rcc=RCC_APB2Periph_GPIOA,
    .gpio_tx_base=GPIOA,
    .gpio_tx_pin=9,
    .gpio_rx_clock_fun=RCC_APB2PeriphClockCmd,
    .gpio_rx_rcc=RCC_APB2Periph_GPIOA,
    .gpio_rx_base=GPIOA,
    .gpio_rx_pin=10,
    
    .dma_rx_clock_fun=RCC_AHBPeriphClockCmd,
    .dma_rx_rcc=RCC_AHBPeriph_DMA1,
    .dma_rx_channel=DMA1_Channel5,
    
    .dma_tx_clock_fun=RCC_AHBPeriphClockCmd,
    .dma_tx_rcc=RCC_AHBPeriph_DMA1,
    .dma_tx_channel=DMA1_Channel4,
    .dma_tx_irq_channel=DMA1_Channel4_IRQn,
    .dma_tx_tc_flag=DMA1_FLAG_TC4,
  },
  {
    .name="uart2",
    .uart=USART2,
    .uart_clock_fun=RCC_APB1PeriphClockCmd,
    .uart_rcc=RCC_APB1Periph_USART2,
    .baudrate=57600,
    .irq_channel=USART2_IRQn,
    
    .gpio_tx_clock_fun=RCC_APB2PeriphClockCmd,
    .gpio_tx_rcc=RCC_APB2Periph_GPIOA,
    .gpio_tx_base=GPIOA,
    .gpio_tx_pin=2,
    .gpio_rx_clock_fun=RCC_APB2PeriphClockCmd,
    .gpio_rx_rcc=RCC_APB2Periph_GPIOA,
    .gpio_rx_base=GPIOA,
    .gpio_rx_pin=3,
    
    .dma_rx_clock_fun=RCC_AHBPeriphClockCmd,
    .dma_rx_rcc=RCC_AHBPeriph_DMA1,
    .dma_rx_channel=DMA1_Channel6,
    
    .dma_tx_clock_fun=RCC_AHBPeriphClockCmd,
    .dma_tx_rcc=RCC_AHBPeriph_DMA1,
    .dma_tx_channel=DMA1_Channel7,
    .dma_tx_irq_channel=DMA1_Channel7_IRQn,
    .dma_tx_tc_flag=DMA1_FLAG_TC7,
  },
  {
    .name="uart3",
    .uart=USART3,
    .uart_clock_fun=RCC_APB1PeriphClockCmd,
    .uart_rcc=RCC_APB1Periph_USART3,
    .baudrate=57600,
    .irq_channel=USART3_IRQn,
    
    .gpio_tx_clock_fun=RCC_APB2PeriphClockCmd,
    .gpio_tx_rcc=RCC_APB2Periph_GPIOB,
    .gpio_tx_base=GPIOB,
    .gpio_tx_pin=10,
    .gpio_rx_clock_fun=RCC_APB2PeriphClockCmd,
    .gpio_rx_rcc=RCC_APB2Periph_GPIOB,
    .gpio_rx_base=GPIOB,
    .gpio_rx_pin=11,
    
    .dma_rx_clock_fun=RCC_AHBPeriphClockCmd,
    .dma_rx_rcc=RCC_AHBPeriph_DMA1,
    .dma_rx_channel=DMA1_Channel3,
    
    .dma_tx_clock_fun=RCC_AHBPeriphClockCmd,
    .dma_tx_rcc=RCC_AHBPeriph_DMA1,
    .dma_tx_channel=DMA1_Channel2,
    .dma_tx_irq_channel=DMA1_Channel2_IRQn,
    .dma_tx_tc_flag=DMA1_FLAG_TC2,
  },
};






typedef struct{
  const uart_dtb *dtb;
  void (*irq_fun)(void *t,uint8_t d);
  void (*irq_fun_end)(void *t,uint32_t len);
  void *t;
  uint8_t *rx_buff;
  uint32_t rx_buff_size;
  void *sem;
  volatile int in_send;
}self_data;


static self_data g_self[LENGTH(g_uartdtb)];


def_find_fun(uart_dtb,g_uartdtb)



static int init(uart_def *u,int bsp)
{
  param_check(u);
  if(u->private_data) return 0;
  GPIO_InitTypeDef init=GPIO_Initer();
  USART_InitTypeDef init2=UART_Initer();
  NVIC_InitTypeDef init3=NVIC_Initer();
  
  int index;
  const uart_dtb *dtb=find(u->name,&index);
  self_data *self=&g_self[index];
  self->dtb=dtb;
  self->irq_fun=0;
  self->t=0;
  self->sem=rt_sem_create(u->name,1,RT_IPC_FLAG_FIFO);
  self->in_send=0;

  u->private_data=self;
  dtb->uart_clock_fun(dtb->uart_rcc,ENABLE);
  if(bsp==0) bsp=dtb->baudrate;
  init2.USART_BaudRate = bsp;
  USART_Init(dtb->uart, &init2);	
  USART_Cmd(dtb->uart, ENABLE);	
  
  dtb->gpio_tx_clock_fun(dtb->gpio_tx_rcc,ENABLE);
  init.GPIO_Pin=1<<dtb->gpio_tx_pin;
  GPIO_Init(dtb->gpio_tx_base,&init); 

  dtb->gpio_rx_clock_fun(dtb->gpio_rx_rcc,ENABLE);
  init.GPIO_Pin=1<<dtb->gpio_rx_pin;
  init.GPIO_Mode=GPIO_Mode_IPU;
  GPIO_Init(dtb->gpio_rx_base,&init); 

  init3.NVIC_IRQChannel = dtb->irq_channel;
  init3.NVIC_IRQChannelPreemptionPriority=3;
  init3.NVIC_IRQChannelSubPriority =3;
  init3.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&init3);
  
  init3.NVIC_IRQChannel = dtb->dma_tx_irq_channel;
  init3.NVIC_IRQChannelPreemptionPriority=3;
  init3.NVIC_IRQChannelSubPriority =3;
  init3.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&init3);
  return 0;
}


static int deinit(uart_def *u)
{
  param_check(u);
  return 0;
}






static int set_irq(uart_def *u,void (*irq)(void *t,uint8_t d),void *t)
{
  param_check(u);
  param_check(u->private_data);
  self_data *self=u->private_data;
  const uart_dtb *dtb=self->dtb;
  irq_disable();
  self->irq_fun=irq;
  self->t=t;
  irq_enable();
  if(irq)
    USART_ITConfig(dtb->uart, USART_IT_RXNE, ENABLE);	
  else
    USART_ITConfig(dtb->uart, USART_IT_RXNE, DISABLE);	
  return 0;
}



static int dma_rx_init(self_data *self,uint8_t *rx_buff,uint32_t rx_buff_size)
{
  const uart_dtb *dtb=self->dtb;
	DMA_InitTypeDef init=DMA_RX_Initer();	
  
  USART_DMACmd(dtb->uart,USART_DMAReq_Rx,ENABLE);
  DMA_DeInit(dtb->dma_rx_channel);
  dtb->dma_rx_clock_fun(dtb->dma_rx_rcc,ENABLE);
  init.DMA_PeripheralBaseAddr = (u32)(&(dtb->uart->DR));
  init.DMA_MemoryBaseAddr = (u32)rx_buff;
  init.DMA_BufferSize=rx_buff_size;
  DMA_Init(dtb->dma_rx_channel, &init);
  DMA_Cmd(dtb->dma_rx_channel, DISABLE);
  USART_ITConfig(dtb->uart, USART_IT_IDLE, ENABLE);	
  return 0;
}

static int dma_rx_reset(self_data *self)
{
  const uart_dtb *dtb=self->dtb;
  
  DMA_Cmd(dtb->dma_rx_channel, DISABLE);
  DMA_SetCurrDataCounter(dtb->dma_rx_channel, self->rx_buff_size);  
  DMA_Cmd(dtb->dma_rx_channel, ENABLE);
  
  return 0;
}



static int set_end_irq(uart_def *u,uint8_t *rx_buff,int rx_buff_size,
  void (*irq)(void *t,uint32_t len),void *t)
{
  param_check(u);
  param_check(u->private_data);
  self_data *self=u->private_data;
  dma_rx_init(self,rx_buff,rx_buff_size);
  self->rx_buff=rx_buff;
  self->rx_buff_size=rx_buff_size;
  dma_rx_reset(self);
  irq_disable();
  self->irq_fun_end=irq;
  self->t=t;
  irq_enable();
  return 0;
}




static int read(uart_def *u,uint8_t *b,int len)
{
  param_check(u);
  param_check(u->private_data);
  return 0;
}



static int dma_tx_init(self_data *self,const uint8_t *tx_buff,uint32_t tx_buff_size)
{
  const uart_dtb *dtb=self->dtb;
	DMA_InitTypeDef init=DMA_TX_Initer();	
  
  USART_DMACmd(dtb->uart,USART_DMAReq_Tx,ENABLE);
  DMA_DeInit(dtb->dma_tx_channel);
  dtb->dma_tx_clock_fun(dtb->dma_tx_rcc,ENABLE);
  init.DMA_PeripheralBaseAddr = (u32)(&(dtb->uart->DR));
  init.DMA_MemoryBaseAddr = (u32)tx_buff;
  init.DMA_BufferSize=tx_buff_size;
  DMA_Init(dtb->dma_tx_channel, &init);
  DMA_Cmd(dtb->dma_tx_channel, ENABLE);
  DMA_ITConfig(dtb->dma_tx_channel,DMA_IT_TC,ENABLE);
  return 0;
}


static int dma_tx_reset(self_data *self,uint8_t *tx_buff,uint32_t tx_buff_size)
{
  const uart_dtb *dtb=self->dtb;
  
  USART_DMACmd(dtb->uart,USART_DMAReq_Tx,ENABLE);
  DMA_Cmd(dtb->dma_tx_channel, DISABLE);
  DMA_ClearFlag(dtb->dma_tx_tc_flag);
  DMA_SetCurrDataCounter(dtb->dma_tx_channel, tx_buff_size);
  dtb->dma_tx_channel->CMAR=(uint32_t)tx_buff;
  DMA_Cmd(dtb->dma_tx_channel, ENABLE);
  return 0;
}




// dma后台发送需要保证数据在发送期间有效
static int write(uart_def *u,const uint8_t *b,int len)
{
  param_check(u);
  param_check(u->private_data);
  self_data *self=u->private_data;
  USART_TypeDef *uart=self->dtb->uart;
  if(1){
    dma_tx_init(self,b,len);
  }else{
    for(int i=0;i<len;i++)
    {
      while(!USART_GetFlagStatus(uart,USART_FLAG_TXE));
      uart->DR=b[i];
    }
  }
  return len;
}

// 阻塞发送，此函数结束即可释放内存
static int write_block(uart_def *u,const uint8_t *b,int len)
{
  param_check(u);
  param_check(u->private_data);
  self_data *self=u->private_data;
  USART_TypeDef *uart=self->dtb->uart;
  if(self->in_send){
    return 0;
  }
  self->in_send=1;
  if(1){
    dma_tx_init(self,b,len);
  }else{
    for(int i=0;i<len;i++)
    {
      while(!USART_GetFlagStatus(uart,USART_FLAG_TXE));
      uart->DR=b[i];
    }
    self->in_send=0;
  }
  while(self->in_send){}
  return len;
}






static inline void self_irq(self_data *self)
{
	rt_interrupt_enter();
  const uart_dtb *dtb=self->dtb;
  if(USART_GetFlagStatus(dtb->uart,USART_FLAG_RXNE))
  {
    uint8_t d=dtb->uart->DR;
    if(self->irq_fun){
      self->irq_fun(self->t,d);
    }
  }
  else if(USART_GetFlagStatus(self->dtb->uart,USART_FLAG_TC))
  {
    USART_ClearFlag(dtb->uart,USART_FLAG_TC);
  }
  else if(USART_GetFlagStatus(self->dtb->uart,USART_FLAG_IDLE))
  {
    USART_ReceiveData(dtb->uart);
    if(self->irq_fun_end){
      self->irq_fun_end(self->t,self->rx_buff_size-DMA_GetCurrDataCounter(dtb->dma_rx_channel));
    }
    dma_rx_reset(self);
  }
	rt_interrupt_leave();
}
static inline void self_dma_irq(self_data *self)
{
	rt_interrupt_enter();
  const uart_dtb *dtb=self->dtb;
  if(DMA_GetFlagStatus(dtb->dma_tx_tc_flag))
  {
    DMA_ClearFlag(dtb->dma_tx_tc_flag);
    DMA_Cmd(dtb->dma_tx_channel, DISABLE);
    self->in_send=0;
  }
	rt_interrupt_leave();
}


void USART1_IRQHandler(void)
{
  self_data *self=&g_self[0];
  self_irq(self);
}

void USART2_IRQHandler(void)
{
  self_data *self=&g_self[1];
  self_irq(self);
}
void USART3_IRQHandler(void)
{
  self_data *self=&g_self[2];
  self_irq(self);
}
void DMA1_Channel4_IRQHandler(void)
{
  self_data *self=&g_self[0];
  self_dma_irq(self);
}
void DMA1_Channel7_IRQHandler(void)
{
  self_data *self=&g_self[1];
  self_dma_irq(self);
}
void DMA1_Channel2_IRQHandler(void)
{
  self_data *self=&g_self[2];
  self_dma_irq(self);
}


uart_init_export(uart1,init,deinit,set_irq,set_end_irq,read,write_block,0)
uart_init_export(uart2,init,deinit,set_irq,set_end_irq,read,write,0)
uart_init_export(uart3,init,deinit,set_irq,set_end_irq,read,write,0)















