/*
 * avr_uart1.c - device driver for hardware UART1 on AVR atmega128 platform
 *
 * 2001.01.09 Lukas Karrer <lkarrer@trash.net>
 * 2002.04.29 Jan Beutel <j.beutel@ieee.org>
 * 2002.05.23 Oliver Kasten <oliver.kasten@inf.ethz.ch>
 * 2002.12.04 Matthias Ringwald <matthias.ringwald@inf.ethz.ch>
 *
 * Note: Incoming Buffer overflows are not handled! Data is discarded
 *
 * This file is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * $Id: avr128_uart1.c,v 1.15 2002/12/05 18:11:46 mringwal Exp $
 */

/* -------------------------------------------------------------------------
 * BUGS
 * ------------------------------------------------------------------------- */

// port_or is not defined in iomacro.h (which gets included in io.h) while
// __port_or has a definition. This seems to be a bug in iomacro.h
// #define port_or __port_or
// ditto
// #define port_and __port_and


/* -------------------------------------------------------------------------
 * includes
 * ------------------------------------------------------------------------- */
#include <smart-its.h>

#ifdef USE_DISPATCHER
#include <dispatcher.h>
#endif // USE_DISPATCHER

#include "../error_codes.h"
#include "../uart1.h"
#include "../rtc.h"
#include "../led.h"
#include "../power.h"

// for OS_ENTER/EXIT_CRITICAL defines
#include "dispatcher-platform.h"

// -------------------------------------------------------------------------
// Hardware dependent defines
// -------------------------------------------------------------------------

#if defined(STK500)
// Atmel STK500 eval board
// hardware flow control is OFF
// #define UART1_RTSCTS
#elif defined(BTNODE)
// BTnode2.2
// hardware flow control is OFF
// #define UART1_RTSCTS

#else
 #error "either STK500 or BTNODE must be defined as target platform !"
#endif

#define UART1_RTSCTS

// -------------------------------------------------------------------------
// local variables and defines
// -------------------------------------------------------------------------
// size of buffer for incoming data: 32, 64, 128 or 256 bytes

#define UART1_RX_BUFFER_SIZE 128
#define UART1_RX_BUFFER_MASK ( UART1_RX_BUFFER_SIZE - 1 )

// needs to be defined for bt_node, must not be defined for stk500
#ifdef UART1_RTSCTS
// watermark when to signal the other party to stop sending
// experiments w/ linux and minicom @ 57.6 showed that after RTS, the
// PC uart still sends for another ~18 ms, that is 104 bytes

// #define UART1_RX_BUFFER_HIGH_WATERMARK (UART1_RX_BUFFER_SIZE-64)
#define UART1_RX_BUFFER_HIGH_WATERMARK 16

// watermark when to signal the other party start sending again
// was: #define UART1_RX_BUFFER_LOW_WATERMARK (UART1_RX_BUFFER_SIZE / 2)
#define UART1_RX_BUFFER_LOW_WATERMARK (UART1_RX_BUFFER_HIGH_WATERMARK / 2)
#endif // UART1_RTSCTS

// size of buffer for outgoing data: 32, 64, 128 or 256 bytes
#define UART1_TX_BUFFER_SIZE 128
#define UART1_TX_BUFFER_MASK ( UART1_TX_BUFFER_SIZE - 1 )

// buffer to store incoming data
static u8 UART1_RX_Buf[UART1_RX_BUFFER_SIZE];

// pointer to head of ringbuffer, points to the last entry in buffer
static volatile u8 UART1_RX_Head;

// pointer to the tail of ringbuffer, points to last byte sent
static volatile u8 UART1_RX_Tail;

// buffer to store outgoing data
static u8 UART1_TX_Buf[UART1_TX_BUFFER_SIZE];

// pointer to head of ringbuffer, points to the last entry in buffer
static volatile u8 UART1_TX_Head;

// pointer to the tail of ringbuffer, points to last byte sent
static volatile u8 UART1_TX_Tail;

// ongoing transmission
static volatile u8 UART1_TX_Process;

/* -------------------------------------------------------------------------
 * Hardwaredependant defines
 * ------------------------------------------------------------------------- */

// BTnode 2.2
// RxD: PD2
// TxD: PD3
// RTS: PD4
// CTS: PD5


#define UART1_CTS_PORT PINE        // PORT where CTS is connected
#define UART1_CTS_PORT_DDR DDRE    // DataDirectionRegister of CTS PORT
#define UART1_CTS 5                // Pin on which CTS is connected
#define UART1_RTS_PORT PORTD
#define UART1_RTS_PORT_DDR DDRD
#define UART1_RTS 4

// -------------------------------------------------------------------------
//
// -------------------------------------------------------------------------
// read up to count bytes from Receivebuffer into buf returns # of
// bytes read

s32 btn_uart1_read( u8 *buf, s32 count) {

  u8 tmptail;
  s32 i;

  if( UART1_RX_Tail == UART1_RX_Head ) {
    // we do not have any data in buffer
    return 0;
  }

 // disable interrupts to assure that an read event is only generated, if data is available
 OS_ENTER_CRITICAL();

 for( i=0; (i<count) && (UART1_RX_Tail != UART1_RX_Head); i++ ) {

    // calculate new buffer index
    tmptail = ( UART1_RX_Tail + 1 ) & UART1_RX_BUFFER_MASK;

    buf[i] = UART1_RX_Buf[tmptail];
    // store new index
    UART1_RX_Tail = tmptail;

    // CHECK_SP;
  }

#ifdef USE_DISPATCHER
  // ...generate a new dispatcher event if we have read some but not
  // all data from the reception buffer
  if( UART1_RX_Tail != UART1_RX_Head )
    btn_disp_put_event( UART1_RCV_EV, 1 );

#endif // USE_DISPATCHER

 OS_EXIT_CRITICAL();

#ifdef UART1_RTSCTS
  if( btn_uart1_read_pending() < UART1_RX_BUFFER_LOW_WATERMARK ) {
    // under watermark: we have enough buffer space -> signal to other
    // party to start sending again
    cbi( UART1_RTS_PORT, UART1_RTS );
  }
#endif // UART1_RTSCTS

  // CHECK_SP;

  // return number of bytes actually read
  return i;
}


// -------------------------------------------------------------------------
// s32 btn_uart1_read_pending ()
// -------------------------------------------------------------------------
// return # of available bytes in RX buffer

s32 btn_uart1_read_pending () {

  if( UART1_RX_Head > UART1_RX_Tail ) {
    return UART1_RX_Head - UART1_RX_Tail;
  } else if( UART1_RX_Head < UART1_RX_Tail ) {
    return UART1_RX_Head  + (UART1_RX_BUFFER_SIZE - UART1_RX_Tail);
  } else {
    return 0;
  }
}


// -------------------------------------------------------------------------
// s32 btn_uart1_write_pending ()
// -------------------------------------------------------------------------
// Return # of unsent bytes in TX buffer

s32 btn_uart1_write_pending () {
  if( UART1_TX_Head > UART1_TX_Tail ) {
    return UART1_TX_Head - UART1_TX_Tail;
  } else if( UART1_TX_Head < UART1_TX_Tail ) {
    return UART1_TX_Head  + (UART1_TX_BUFFER_SIZE - UART1_TX_Tail);
  } else {
    return 0;
  }
}


// -------------------------------------------------------------------------
//
// -------------------------------------------------------------------------
/* EXAMPLE OF HOW TO USE BTN_POWER_IDLE

void btn_uart1_write_byte_blk( u8 data ) {

  u8 tmphead;

  while( (tmphead = ((UART1_TX_Head + 1 ) & UART1_TX_BUFFER_MASK)) ==
	 UART1_TX_Tail ) {
    // while there is no transmit-buffer space, go into idle mode. we
    // will wake up from idle mode when "UART Data Register Empty
    // interrupt" (UDRE) interrupt is called. the UDRE should be on
    // whenever there is data in the transmit buffer.
    btn_power_idle();
  }

  // enough buffer space: store data in buffer
  UART1_TX_Buf[tmphead] = data;
  // store new index
  UART1_TX_Head = tmphead;

  // enable "UART Data Register Empty interrupt" => we will start
  // sending as soon as interrupt is handled
  // outp(inp(UCSR1B)|(1<<UDRIE), UCSR1B);
  sbi( UCSR1B, UDRIE );

}
*/


// -------------------------------------------------------------------------
// btn_uart1_write
// -------------------------------------------------------------------------
// write count bytes of *data in transmit buffer and start
// transmitting with baudrate set in btn_uart1_init().

s32 btn_uart1_write( u8 *data, s32 count ) {

  s32 i;
  u8 tmphead;

  if( count == 0 ) {
    // if we have nothing to write, bail out here.. we do not want to
    // enable interrupts etc. when having nothing to do
    return 0;
  }

  for( i=0; i<count; i++ ) {
    // calculate buffer index
    tmphead = ( UART1_TX_Head + 1 ) & UART1_TX_BUFFER_MASK;

    if( tmphead != UART1_TX_Tail ) {
      // enough buffer space: store data in buffer
      UART1_TX_Buf[tmphead] = data[i];
      // store new index
      UART1_TX_Head = tmphead;
    } else {
      // we do not have enough buffer space
      // bail out and return number of bytes written
      break;
    }
    CHECK_SP;
  } // end for

#ifdef UART1_RTSCTS
  // lka note: we should check for flow control -> Problem, when do we
  // get back the check again if (bit_is_clear(UART1_CTS_PORT,
  // UART1_CTS)) {}

  //weickert:
  if (bit_is_clear(UART1_CTS_PORT,UART1_CTS)){
#endif // UART1_RTSCTS

  // enable UDRE interrupt => we will start sending as soon as
  // interrupt is handled
  sbi( UCSR1B, UDRIE );

  #ifdef UART1_RTSCTS
  }
  #endif // UART1_RTSCTS

  return i;
}

// -------------------------------------------------------------------------
// s32 btn_uart1_write_blk ( u8 * data, s32 count )
// -------------------------------------------------------------------------

s32 btn_uart1_write_blk( u8 * data, s32 count ) {

  s32 len = count;

  while( count > 0 ) {
    count = count - btn_uart1_write( data + len - count, count );
  } // end while

  return len;
}

/*-------------------------------------------------------------------------
 * btn_uart1_set_baud_rate
 * PRE: CLOCK_FREQUENCY is set correctly
 * PRE: ring buffer and UART0 _TX_Process are initialized
 * ------------------------------------------------------------------------- */
void btn_uart1_set_baud_rate(u32 baudrate)
{
  // prescaler of UART1 for selected Baudrate
  //
  // UBRR1H=0 (always)
  // UBRR1L=
  //              system clock
  //              3.6864 MHz    7.3728 MHz
  // bautrate
  //  14.4K       15            31
  //  28.8K        7            15
  //  57.6K        3             7
  //  76.6K        2             5
  // 115.2K        1             3
  // 230.4K        0             1

  // BAUD = CLOCK_FREQUENCY / (16 * (UBBR + 1))
  // UBBR = CLOCK_FREQUENCY / ( 16 * BAUD) - 1 = ((CLOCK_FREQUENCY / 16 ) / BAUD) - 1

  // use 32 bit arithmetics
  u32 ubrr = CLOCK_FREQUENCY / 16;
  ubrr = ubrr / baudrate - 1;

  // care for ongoing transmissions
  while (UART1_TX_Process)
  {
	asm volatile ("nop");
  }

  // set UBRR
  outp( ubrr & 255, UBRR1L);
  outp( ubrr >> 8, UBRR1H);
 }

/*-------------------------------------------------------------------------
 * btn_uart1_set_parity
 * ------------------------------------------------------------------------- */
void btn_uart1_set_parity(u8 parity)
{
  u8 newParity = inp(UCSR1C) & ( 255 - (1<<UPM1) - (1<<UPM0));
  switch(parity)
  {
	case UART_PARITY_NONE:
       // set odd parity
	   break;
	case UART_PARITY_EVEN:
      // set odd parity
      newParity |= (1<<UPM1);
	  break;
	case UART_PARITY_ODD:
      // set odd parity
      newParity |= (1<<UPM1) | (1<<UPM0);
	  break;
  }

  // care for ongoing transmissions
  while (UART1_TX_Process)
  {
	asm volatile ("nop");
  }

  outp( newParity, UCSR1C);
}


// -------------------------------------------------------------------------
//
// -------------------------------------------------------------------------
void btn_uart1_init( ) {


  // initialize ring-buffer structure
  UART1_RX_Head = 0;
  UART1_RX_Tail = 0;
  UART1_TX_Head = 0;
  UART1_TX_Tail = 0;
  UART1_TX_Process = FALSE;


  // set default baud rate
  btn_uart1_set_baud_rate( B57600 );
  // set parity
  btn_uart1_set_parity( UART_PARITY_NONE );

  // enable receiver
  sbi(UCSR1B,RXEN);
  // enable transmitter
  sbi(UCSR1B,TXEN);

  // enable RX complete interrupt
  sbi(UCSR1B,RXCIE);

#if defined(UART1_RTSCTS)

  // TODO (olli): configure this to be the external edge-triggered
  // interrupt no 4: if we stopped sending because the module cleared
  // the CLEAR TO SEND bit, then when do we get back to check if the
  // CLEAR TO SEND bit has been set in the meanwhile? the int 4 will
  // be triggered if the bluetooth modules sets the CLEAR TO SEND
  // bit. in the interrupt we start sending again (by enabeling the
  // uart1 output register interrupt...)

  // weickert: this will do it.

  sbi(EICRB,ISC51);	//triggered by the falling edge
  cbi(EICRB,ISC50);

  //sbi(EIMSK,INT5);	//enable external interrupt5
  cbi(EIMSK,INT5);	//disable external interrupt5, enable wenn cts was detected as high

#endif // UART1_RTSCTS

  // set up CTS port as input
  cbi (UART1_CTS_PORT_DDR,UART1_CTS);
  // set up RTS port as output
  sbi (UART1_RTS_PORT_DDR,UART1_RTS);
  // unset RTS, allow other side to transmit
  cbi(UART1_RTS_PORT,UART1_RTS);

}



// -------------------------------------------------------------------------
// SIG_UART1_DATA
// -------------------------------------------------------------------------
// Interrupt routine after byte has been moved from data register into the
// the transmit shift register and UART1 data Register UDR is free again
SIGNAL( SIG_UART1_DATA ) {

  u8 tmptail;

  // check if all data is transmitted
  if( UART1_TX_Head != UART1_TX_Tail ) {
    // no, more to transmit

	#ifdef UART1_RTSCTS
		// check if the other side gave us a "clear to send"
		if( bit_is_set(UART1_CTS_PORT,UART1_CTS) ) {
		  // "clear to send" is set: i must not send.  disable "USART data
		  // register empty interrupt".  enable again when CTS changes to
		  // 0
		  cbi(UCSR1B,UDRIE);
		  sbi(EIMSK,INT5);	//enable external interrupt5
		}
		else
		{
	#endif // UART1_RTSCTS

		// ongoing transmission
		UART1_TX_Process = TRUE;

		// calculate buffer index
		tmptail = ( UART1_TX_Tail + 1 ) & UART1_TX_BUFFER_MASK;
		// store new index
		UART1_TX_Tail = tmptail;
		// start transmition of next byte
		outp( UART1_TX_Buf[tmptail], UDR1 );

		// last time?
		if( UART1_TX_Head == UART1_TX_Tail ) {
			// disable "USART data register empty interrupt"
			cbi(UCSR1B,UDRIE);
		}

		// clear TXC flag
		cbi(UCSR1A, TXC);
		// enable TXC interrupt
		sbi(UCSR1B, TXCIE);

		CHECK_SP;

	#ifdef UART1_RTSCTS
		}
	#endif // UART1_RTSCTS
  }
}

// -------------------------------------------------------------------------
// SIG_UART1_TRANS
// -------------------------------------------------------------------------
// Interrupt routine is called after last byte has been transmitted,
// no new data is in data register
SIGNAL( SIG_UART1_TRANS ) {

	// trasnmission finished
	UART1_TX_Process = FALSE;
	// clear interrupt

	// disable TXC interrupt
	sbi(UCSR1B, TXCIE);
}

// -------------------------------------------------------------------------
// SIG_UART1_RECV
// -------------------------------------------------------------------------
// Interrupt routine for incoming byte on HW UART1

SIGNAL( SIG_UART1_RECV ) {

  u8 data;
  u8 tmphead;
  // read the received data
  data = inp(UDR1);

#ifdef USE_DISPATCHER
    // ...generate a new dispatcher event only if its empty
    if( UART1_RX_Head == UART1_RX_Tail ) {
      btn_disp_put_event( UART1_RCV_EV, 1 );
    }
#endif // USE_DISPATCHER

  // calculate buffer index
  tmphead = ( UART1_RX_Head + 1 ) & UART1_RX_BUFFER_MASK;
  // store new index
  UART1_RX_Head = tmphead;

  if ( tmphead == UART1_RX_Tail ) {
    // ERROR: Receive buffer overflow
    D_ERRNO(BTN_ERROR_UART1_RCV_BUFFER_OVERFLOW);
  } else {
    // so there is enough space in buffer...

    // ...then store the received data in buffer...
    UART1_RX_Buf[tmphead] = data;


#ifdef UART1_RTSCTS
    // check to see if we have enough buffer space for incoming data
    if( btn_uart1_read_pending() > UART1_RX_BUFFER_HIGH_WATERMARK ) {
      // over watermark: we are low on buffer -> signal to other party
      // to stop sending
      sbi( UART1_RTS_PORT, UART1_RTS );
    }
#endif // UART1_RTSCTS

    CHECK_SP;
  }
} // end SIGNAL()

#ifdef UART1_RTSCTS
SIGNAL( SIG_INTERRUPT5 )	//enable "USART data register empty interrupt", USART can send again
{
	u8 tmptail;

	// ongoing transmission
	UART1_TX_Process = TRUE;

	// calculate buffer index
	tmptail = ( UART1_TX_Tail + 1 ) & UART1_TX_BUFFER_MASK;
	// store new index
	UART1_TX_Tail = tmptail;
	// start transmition of next byte
	outp( UART1_TX_Buf[tmptail], UDR1 );

	// last time?
	if( UART1_TX_Head == UART1_TX_Tail ) {
		// disable "USART data register empty interrupt"
		cbi(UCSR1B,UDRIE);
	}
	else
		sbi(UCSR1B,UDRIE);

	// clear TXC flag
	cbi(UCSR1A, TXC);
	// enable TXC interrupt
	sbi(UCSR1B, TXCIE);
	// disable extint5
	cbi(EIMSK,INT5);

	CHECK_SP;

}
#endif // UART1_RTSCTS
