/**************************************************************************************************
---------------------------------------------------------------------------------------------------
	Copyright (c) 2004-2007, Jonathan Bagg
	All rights reserved.

	 Redistribution and use in source and binary forms, with or without modification, are permitted 
	 provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of 
	  conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of 
	  conditions and the following disclaimer in the documentation and/or other materials provided 
	  with the distribution.
    * Neither the name of Jonathan Bagg nor the names of its contributors may be used to 
	  endorse or promote products derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------------------------------
   Project name : Infidigm AVR Drivers
   Processor	: Any AVR with a UART or USART
   Compiler		: WinAVR (GCC 4.1.2)
   File name    : uart.h
---------------------------------------------------------------------------------------------------
   Modifications: 

   Revision 1.0  2004/06/17 	Bagg
   - Cleaned up for release
   
   Revision 2.0  2007/09/29 	Bagg
   - added broad support of avr micros
   - added disabling of printing types
   - added print_hex()
   - added rx buffer & functions to read it
   - added "string mode" --> allows pointers to strings to be placed on the tx buffer instead of
		of the ascii characters.
   - added selection between UARTs 0,1,2 and 3 on parts that have them available
   - added optional HOLD THREAD y/n feature
   - added function to read the space left on the TX buffer
   - added the ability to have a tx buffer that is greater than 128 bytes
   - changed global interrupt en/disable in txbyte() to en/disable TX interrupt only
   - added support for lower buad rates by setting up UBRRH
   
---------------------------------------------------------------------------------------------------
	Release Notes:
	
	Processor/Family	Compiles for	Tested		Notes

	attiny2313				Yes				No
	atmega8					Yes				No
	atmega48/88/168			Yes				Yes
	atmega649				Yes				No
	atmega169				Yes				No
	at90pwm2/3				Yes				No
	at90usb1286/1287		Yes				No		only uart 1
	atmega64/128			Yes				Yes
	at90can32/64/128		Yes				Yes
	atmega1281/2561			Yes				Yes
	atmega1280/2560			Yes				No
	
	Size: 356 to 1374 bytes depending on options selected
   
---------------------------------------------------------------------------------------------------
   Created      : 20 Jan 2004     	           Author(s) : Jonathan Bagg
---------------------------------------------------------------------------------------------------
   UART Interrupt driver with HyperTerminal Display I/O functions
---------------------------------------------------------------------------------------------------
**************************************************************************************************/

#include <avr/pgmspace.h>

/**************************************************************************************************
*   Use UART 0,1,2 or 3 (1,2 or 3 only on select processors)
**************************************************************************************************/
#define	USING_UART	0

/**************************************************************************************************
*   Available printing Options - uncomment / define to enable
**************************************************************************************************/
#define	USE_UNSIGNED_INT
//#define	USE_SIGNED_INT
//#define	USE_HEX
#define	USE_ROM_STRING
#define USE_INT_SCAN			//used to type in signed/unsigned int values from a terminal

/**************************************************************************************************
*   String Mode setting
*		0 	print_str() copies entier string from FLASH to tx buffer - UART driver is smaller
*		1	print_str() copies a pointer to the string in FLASH to tx buffer - UART driver is larger
**************************************************************************************************/
#define STRING_MODE		1

/**************************************************************************************************
*   Use Large String setting - only valid if String mode = 1
*		0 	print_str() strings must be smaller than 255 bytes each
*		1	print_str() can handle strings larger than 255 bytes (requires extra 30 bytes of Flash)
**************************************************************************************************/
#define LARGE_STRING		1

/**************************************************************************************************
*   Hold thread setting
*		0 	dumps new data if the  buffer if is full.
*		1	freezes the calling thread until their is room on the buffer
**************************************************************************************************/
#define HOLD_THREAD		1

/**************************************************************************************************
*   UART0 HyperTerminal Definitions
**************************************************************************************************/
#define UART_BAUD_RATE      19200        	// set baud rate
#define UART_BAUD_SELECT	(F_CPU/(UART_BAUD_RATE*16l)-1)
#define TXSIZE				64			//Transmit Buffer Size, can be 2^n where n=3 to 11
#define RXSIZE				8			//Receiver Buffer Size, can be 2^n where n=1 to 7

#if !(TXSIZE==8 || TXSIZE==16 || TXSIZE==32 || TXSIZE==64 || TXSIZE==128 || TXSIZE==256 \
	 || TXSIZE==512  || TXSIZE==1024 || TXSIZE==2048)
	#warning:Incorect TX Buffer Size
#endif
#if !(RXSIZE==2 || RXSIZE==4 || RXSIZE==8 || RXSIZE==16 || RXSIZE==32 || RXSIZE==64 || RXSIZE==128)
	#warning:Incorect RX Buffer Size
#endif

#if (TXSIZE > 128)
	typedef unsigned int TXTYPE;
#else
	typedef unsigned char TXTYPE;
#endif

/**************************************************************************************************
*	Compatibility - Dot Not Change in this section
**************************************************************************************************/
#if USING_UART == 0
	#if defined UBRR0L
		#define	UR_H		UBRR0H
		#define	UR_L		UBRR0L
		#define	UR_A		UCSR0A
		#define	UR_B		UCSR0B
		#define	RX_INT_EN	RXCIE0
		#define	TX_INT_EN	TXCIE0
		#define	RX_EN		RXEN0
		#define	TX_EN		TXEN0
		#define UDR			UDR0
	#else
		#define	UR_H		UBRRH
		#define	UR_L		UBRRL
		#define	UR_A		UCSRA
		#define	UR_B		UCSRB
		#define	RX_INT_EN	RXCIE
		#define	TX_INT_EN	TXCIE
		#define	RX_EN		RXEN
		#define	TX_EN		TXEN
	#endif
	
	#if defined SIG_UART0_TRANS
		#define DSIG_UART_TX_ISR	SIG_UART0_TRANS
	#elif defined SIG_USART0_TRANS
		#define DSIG_UART_TX_ISR	SIG_USART0_TRANS
	#elif defined SIG_USART_TRANS
		#define DSIG_UART_TX_ISR	SIG_USART_TRANS
	#else
		#define DSIG_UART_TX_ISR	SIG_UART_TRANS
	#endif
	#if defined SIG_UART0_RECV
		#define DSIG_UART_RX_ISR	SIG_UART0_RECV
	#elif defined SIG_USART0_RECV
		#define DSIG_UART_RX_ISR	SIG_USART0_RECV
	#elif defined SIG_USART_RECV
		#define DSIG_UART_RX_ISR	SIG_USART_RECV
	#else
		#define DSIG_UART_RX_ISR	SIG_UART_RECV
	#endif
	
#elif USING_UART == 1
	#define	UR_H		UBRR1H
	#define	UR_L		UBRR1L
	#define	UR_A		UCSR1A
	#define	UR_B		UCSR1B
	#define	RX_INT_EN	RXCIE1
	#define	TX_INT_EN	TXCIE1
	#define	RX_EN		RXEN1
	#define	TX_EN		TXEN1
	#define UDR	UDR1
	
	#if defined SIG_UART1_TRANS
		#define DSIG_UART_TX_ISR	SIG_UART1_TRANS
	#elif defined USART1_TX_vect
		#define DSIG_UART_TX_ISR	USART1_TX_vect		//for 90USB128x
	#else
		#define DSIG_UART_TX_ISR	SIG_USART1_TRANS
	#endif
	
	#if defined SIG_UART1_RECV
		#define DSIG_UART_RX_ISR	SIG_UART1_RECV
	#elif defined USART1_RX_vect
		#define DSIG_UART_RX_ISR	USART1_RX_vect		//for 90USB128x
	#else
		#define DSIG_UART_RX_ISR	SIG_USART1_RECV
	#endif
	
#elif USING_UART == 2
	#define	UR_H		UBRR2H
	#define	UR_L		UBRR2L
	#define	UR_A		UCSR2A
	#define	UR_B		UCSR2B
	#define	RX_INT_EN	RXCIE2
	#define	TX_INT_EN	TXCIE2
	#define	RX_EN		RXEN2
	#define	TX_EN		TXEN2
	#define UDR	UDR2
	
	#define DSIG_UART_TX_ISR	SIG_USART2_TRANS
	#define DSIG_UART_RX_ISR	SIG_USART2_RECV
	
#elif USING_UART == 3
	#define	UR_H		UBRR3H
	#define	UR_L		UBRR3L
	#define	UR_A		UCSR3A
	#define	UR_B		UCSR3B
	#define	RX_INT_EN	RXCIE3
	#define	TX_INT_EN	TXCIE3
	#define	RX_EN		RXEN3
	#define	TX_EN		TXEN3
	#define UDR	UDR3
	
	#define DSIG_UART_TX_ISR	SIG_USART3_TRANS
	#define DSIG_UART_RX_ISR	SIG_USART3_RECV
	
#endif

/**************************************************************************************************
*
*   Function          : start_UART
*
*   Description       : Sets up UART for interrupt based tx / rx; sets up BUAD rate and UART mode
*
*   Parameters        : None
*
*   Functions Called  : None
*
*   Returns           : None
*
**************************************************************************************************/
void start_UART(void);

/**************************************************************************************************
*
*   Function          : UART_PrintfProgStr #define as print_str (string)
*
*   Description       : Sends a String of Characters from Program Memory out to UART0
*
*   Parameters        : Pointer to the String in Program memory
*
*   Functions Called  : pgm_read_byte_nearB(), txbyte()
*
*   Returns           : None
*
*	Usage			  :	print_str("Hello World");
*
**************************************************************************************************/
#ifdef USE_ROM_STRING
#define print_str(string) 		(UART_PrintfProgStr(PSTR(string)))
extern void UART_PrintfProgStr(const char* pBuf);
#endif

/**************************************************************************************************
*
*   Function          : prints16
*
*   Description       : Prints a signed int using UART0 in Hyperterminal
*
*   Parameters        : signed data word
*
*   Functions Called  : txbyte();
*
*   Returns           : None
*
**************************************************************************************************/
#ifdef USE_SIGNED_INT
void prints16(unsigned int x);
#endif

/**************************************************************************************************
*
*   Function          : printu16
*
*   Description       : Prints a unsigned int using UART0 in Hyperterminal
*
*   Parameters        : unsigned data word
*
*   Functions Called  : txbyte();
*
*   Returns           : None
*
**************************************************************************************************/
#ifdef USE_UNSIGNED_INT
void printu16(unsigned int x);
#endif

/**************************************************************************************************
*
*   Function          : print_hex
*
*   Description       : Prints a char in hexidecimal
*
*   Parameters        : unsigned data char
*
*   Functions Called  : txbyte();
*
*   Returns           : None
*
**************************************************************************************************/
#ifdef USE_HEX
void print_hex(unsigned char x);
#endif

/**************************************************************************************************
*
*   Function          : txbyte
*
*   Description       : Sends one byte out UART0
*
*   Parameters        : data byte
*
*   Functions Called  : None
*
*   Returns           : None
*
**************************************************************************************************/
void txbyte(char data );

/**************************************************************************************************
*
*   Function          : read_tx_buff_space()
*
*   Description       : Used for reading how much space is left on the TX buffer.  Application can
*						use this function to prevent the thread from being held up or from data
*						being lost, depending on HOLD_THREAD setting, if their is not enought 
*						room on	the TX buffer.
*
*   Parameters        : None
*
*   Functions Called  : None
*
*   Returns           : Space left on buffer
*
**************************************************************************************************/
TXTYPE read_tx_buff_space(void);

/**************************************************************************************************
*
*   Signal	          : DSIG_UART_TX_ISR
*
*   Description       : UART TX complete Interrupt Service Routine.  Moves the next byte
*						in the tx buffer to the tx register to be transmitted.  Shuts itself down
*						and flags when the tx buffer is empty.  In STRING_MODE==1 the ISR 
*						determines if the data on the tx buffer is data or a pointer to a string in
*						ROM.  If a pointer to a string in ROM, it sends the string to the tx 
*						register until if finds a NULL, then goes onto the next byte on the buffer.
*
*   Parameters        : None
*
*   Functions Called  : None
*
*   Returns           : None
*
**************************************************************************************************/

/**************************************************************************************************
*
*   Signal	          : DSIG_UART_RX_ISR
*
*   Description       : UART RX complete Interrupt Service Routine.  Move the received byte onto
*						the receiver buffer.  Stops buffer fill up if buffer is full.
*
*   Parameters        : None
*
*   Functions Called  : None
*
*   Returns           : None
*
**************************************************************************************************/

/**************************************************************************************************
*
*   Function          : scan
*
*   Description       : Used for Enterring a signed or unsigned int in Hyperterminal using UART.
*
*   Parameters        : Pressed Key
*
*   Functions Called  : txbyte();
*
*   Returns           : Value of entry after ENTER pressed
*
*	Example
*					service_rx()
*					{
*					 unsigned char key;
*					 
*					 if (new_uart_rx()) {
*						key = read_uart_rx();
*						if (something to start scanning) {
*							print_string("\rEnter new value :");
*							scan(RESET_SCAN);
*						}
*						else if (key == ENTER) {
*							variable = scan(key);
*					 	}
*					 	else {
*							scan(key);
*					 	}
*					 }
*					}
*
**************************************************************************************************/
#ifdef USE_INT_SCAN
#define ENTER 				13
#define BACKSPACE 			8
#define RESET_SCAN			' '
signed int scan(char indata);
#endif

#if STRING_MODE == 1
/**************************************************************************************************
*
*   Function          : read_tx_type
*
*   Description       : Looks up if the current address of the tx buffer is a pointer to ROM 
*						or ascii characters
*
*   Parameters        : address - of the data on the tx buffer
*
*   Functions Called  : None
*
*   Returns           : 1 if string pointer, 0 if data
*
**************************************************************************************************/
unsigned char read_tx_type(TXTYPE address);

/**************************************************************************************************
*
*   Function          : write_tx_type
*
*   Description       : Records if the data going onto the tx buffer is a pointer to ROM 
*						or ascii characters
*
*   Parameters        : address - of the data going onto the tx buffer, type - pointer or data
*
*   Functions Called  : None
*
*   Returns           : None
*
**************************************************************************************************/
void write_tx_type(TXTYPE address, unsigned char type);
#endif

/**************************************************************************************************
*
*   Function          : new_uart_rx
*
*   Description       : used to indicate if a new unread byte is on the rx buffer
*
*   Parameters        : None
*
*   Functions Called  : None
*
*   Returns           : 0 if rx buffer is empty, 1 if it is not
*
*	Example
*						for (;;) {
*							if (new_uart_rx()) {
*								data = read_uart_rx();
*							}
*						}
*
**************************************************************************************************/
unsigned char new_uart_rx(void);

/**************************************************************************************************
*
*   Function          : read_uart_rx
*
*   Description       : reads a ascii character off the rx buffer and moves pointer to the next 
*						byte 
*
*   Parameters        : None
*
*   Functions Called  : None
*
*   Returns           : ascii character off the rx buffer
*
**************************************************************************************************/
unsigned char read_uart_rx(void);
