/*
  serial.c - Low level functions for sending and recieving bytes via the serial port
  Part of Grbl

  The MIT License (MIT)

  GRBL(tm) - Embedded CNC g-code interpreter and motion-controller
  Copyright (c) 2009-2011 Simen Svale Skogsrud
  Copyright (c) 2011-2012 Sungeun K. Jeon

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/
#include "stm32f10x.h"
//#include <avr/interrupt.h>
#include "serial.h"
#include "config.h"
#include "motion_control.h"
#include "protocol.h"
#include "delay.h"

uint8_t serial_rx_buffer[RX_BUFFER_SIZE];
uint16_t serial_rx_buffer_head = 0;
volatile uint16_t serial_rx_buffer_tail = 0;

uint8_t serial_tx_buffer[RX_BUFFER_SIZE];
uint16_t serial_tx_buffer_head = 0;
volatile uint16_t serial_tx_buffer_tail = 0;

#ifdef ENABLE_XONXOFF
  volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable
  
  // Returns the number of bytes in the RX buffer. This replaces a typical byte counter to prevent
  // the interrupt and main programs from writing to the counter at the same time.
  static uint8_t get_serial_rx_buffer_count()
  {
    if (serial_rx_buffer_head == serial_rx_buffer_tail) { return(0); }
    if (serial_rx_buffer_head < serial_rx_buffer_tail) { return(serial_rx_buffer_tail-serial_rx_buffer_head); }
    return (RX_BUFFER_SIZE - (serial_rx_buffer_head-serial_rx_buffer_tail));
  }
#endif

void serial_init()
{
//  // Set baud rate
//  #if BAUD_RATE < 57600
//    uint16_t UBRR0_value = ((F_CPU / (8L * BAUD_RATE)) - 1)/2 ;
//    UCSR0A &= ~(1 << U2X0); // baud doubler off  - Only needed on Uno XXX
//  #else
//    uint16_t UBRR0_value = ((F_CPU / (4L * BAUD_RATE)) - 1)/2;
//    UCSR0A |= (1 << U2X0);  // baud doubler on for high baud rates, i.e. 115200
//  #endif
//  UBRR0H = UBRR0_value >> 8;
//  UBRR0L = UBRR0_value;
//            
//  // enable rx and tx
//  UCSR0B |= 1<<RXEN0;
//  UCSR0B |= 1<<TXEN0;
//	
//  // enable interrupt on complete reception of a byte
//  UCSR0B |= 1<<RXCIE0;
//	  
//  // defaults to 8-bit, no parity, 1 stop bit
}

void serial_write(uint8_t data) {
  // Calculate next head
  uint16_t next_head = serial_tx_buffer_head + 1;
  if (next_head == TX_BUFFER_SIZE) { next_head = 0; }

  // Wait until there is space in the buffer
  while (next_head == serial_tx_buffer_tail) { 
    if (sys.execute & EXEC_RESET) { return; } // Only check for abort to avoid an endless loop.
  }

  // Store data and advance head
  serial_tx_buffer[serial_tx_buffer_head] = data;
  serial_tx_buffer_head = next_head;
  
	USART_SendData(USART1, data);
	while (!(USART1->SR & USART_FLAG_TXE));		 //µÈ´ý·¢ËÍÍê³É
	
  // Enable Data Register Empty Interrupt to make sure tx-streaming is running
  //UCSR0B |=  (1 << UDRIE0); 
}

// Data Register Empty Interrupt handler
/*
ISR(SERIAL_UDRE)
{
  // Temporary serial_tx_buffer_tail (to optimize for volatile)
  uint8_t tail = serial_tx_buffer_tail;
  
  #ifdef ENABLE_XONXOFF
    if (flow_ctrl == SEND_XOFF) { 
      UDR0 = XOFF_CHAR; 
      flow_ctrl = XOFF_SENT; 
    } else if (flow_ctrl == SEND_XON) { 
      UDR0 = XON_CHAR; 
      flow_ctrl = XON_SENT; 
    } else
  #endif
  { 
    // Send a byte from the buffer	
    UDR0 = serial_tx_buffer[tail];
  
    // Update tail position
    tail++;
    if (tail == TX_BUFFER_SIZE) { tail = 0; }
  
    serial_tx_buffer_tail = tail;
  }
  
  // Turn off Data Register Empty Interrupt to stop tx-streaming if this concludes the transfer
  if (tail == serial_tx_buffer_head) { UCSR0B &= ~(1 << UDRIE0); }
}
*/


void USART1_IRQHandler(void)
{
	uint8_t data;
  uint16_t next_head;

	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 
	{
		data=USART_ReceiveData(USART1);
		
		next_head = serial_rx_buffer_head + 1;
		
		if (next_head == RX_BUFFER_SIZE) { next_head = 0; }
		
		if (next_head != serial_rx_buffer_tail)
		{
			serial_rx_buffer[serial_rx_buffer_head] = data;
			serial_rx_buffer_head = next_head;    
		}

		if(data==CMD_RESET){NVIC_SystemReset();}
		//else if(data==CMD_STATUS_REPORT){sys.execute |= EXEC_STATUS_REPORT;}
		else if(data==CMD_CYCLE_START){sys.execute |= EXEC_CYCLE_START;}
		else if(data==CMD_FEED_HOLD){sys.execute |= EXEC_FEED_HOLD;}
//		switch (data) 
//		{
//			case CMD_STATUS_REPORT: sys.execute |= EXEC_STATUS_REPORT; break; // Set as true
//			case CMD_CYCLE_START:   sys.execute |= EXEC_CYCLE_START; break; // Set as true
//			case CMD_FEED_HOLD:     sys.execute |= EXEC_FEED_HOLD; break; // Set as true
//			case CMD_RESET:         NVIC_SystemReset(); break; // Call motion control reset routine.

//		}	
		//rx_buffer[++rx_buffer_tail] = USART_ReceiveData(USART1);     // Read one byte from the receive data register
		USART_ClearITPendingBit(USART1, USART_IT_RXNE); 	  		 
	} 
}

uint8_t serial_read()
{
  uint16_t tail = serial_rx_buffer_tail; // Temporary serial_rx_buffer_tail (to optimize for volatile)
  if (serial_rx_buffer_head == tail) {
    return SERIAL_NO_DATA;
  } else {
    uint8_t data = serial_rx_buffer[tail];
    tail++;
    if (tail == RX_BUFFER_SIZE) { tail = 0; }
    serial_rx_buffer_tail = tail;
    
    return data;
  }
}
/*
ISR(SERIAL_RX)
{
  uint8_t data = UDR0;
  uint8_t next_head;
  
  // Pick off runtime command characters directly from the serial stream. These characters are
  // not passed into the buffer, but these set system state flag bits for runtime execution.
  switch (data) {
    case CMD_STATUS_REPORT: sys.execute |= EXEC_STATUS_REPORT; break; // Set as true
    case CMD_CYCLE_START:   sys.execute |= EXEC_CYCLE_START; break; // Set as true
    case CMD_FEED_HOLD:     sys.execute |= EXEC_FEED_HOLD; break; // Set as true
    case CMD_RESET:         mc_reset(); break; // Call motion control reset routine.
    default: // Write character to buffer    
      next_head = serial_rx_buffer_head + 1;
      if (next_head == RX_BUFFER_SIZE) { next_head = 0; }
    
      // Write data to buffer unless it is full.
      if (next_head != serial_rx_buffer_tail) {
        serial_rx_buffer[serial_rx_buffer_head] = data;
        serial_rx_buffer_head = next_head;    
        
        #ifdef ENABLE_XONXOFF
          if ((get_serial_rx_buffer_count() >= serial_rx_buffer_FULL) && flow_ctrl == XON_SENT) {
            flow_ctrl = SEND_XOFF;
            UCSR0B |=  (1 << UDRIE0); // Force TX
          } 
        #endif
        
      }
  }
}
*/
void serial_reset_read_buffer() 
{
  serial_rx_buffer_tail = serial_rx_buffer_head;

  #ifdef ENABLE_XONXOFF
    flow_ctrl = XON_SENT;
  #endif
}
