/*****************************************************
This program was produced by the
CodeWizardAVR V1.24.6 Standard
Automatic Program Generator
© Copyright 1998-2005 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
e-mail:office@hpinfotech.com

Project : PDK-I sample
Version : c
Date    : 4/8/2006
Author  : Tim Gilbert                     
Company : JEM Innovation                  
Comments:   THIS SAMPLE CODE IS PROVIDED WITHOUT ANY WARRANTEE OF ANY KIND; 
            YOU ARE FREE TO USE IT AT YOUR OWN RISK.  It is only intended to 
            demonstrate the PDK's basic features.


Chip type           : ATmega128
Program type        : Application
Clock frequency     : 8.000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 1024   
            
Fuse settings:
To select the internal 8.0 MHz clock, program the fuses as follows:

    CKSEL0 =  0     // checked
    CKSEL1 =  0     // checked
    CKSEL2 =  1     // UNCHECKED
    CKSEL3 =  0     // checked

*****************************************************/

#include <mega128.h>
#include "delay.h" 
#include "stdlib.h"  
#include "stdio.h"                      
#include "string.h"

// Standard Input/Output functions
#include <stdio.h>

// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x1B ;PORTA
#endasm
#include <lcd.h>

#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7   

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)       

#define ADC_VREF_TYPE 0x40

// global variables     
int G_seconds = 0;             

eeprom char ver[] = "ver 0.000";


// simple way to make noise 
#define BEEP_OFF TCCR3A &= 0x3F;  // turn off the noise
#define BEEP_ON  TCCR3A |= 0x80; // enable pwm mode to turn on the beeper   

// USART0 Receiver buffer
#define RX_BUFFER_SIZE0 8
char rx_buffer0[RX_BUFFER_SIZE0];         

typedef unsigned char byte;


#if RX_BUFFER_SIZE0<256
unsigned char rx_wr_index0,rx_rd_index0,rx_counter0;
#else
unsigned int rx_wr_index0,rx_rd_index0,rx_counter0;
#endif

// This flag is set on USART0 Receiver buffer overflow
bit rx_buffer_overflow0;

// USART0 Receiver interrupt service routine
interrupt [USART0_RXC] void usart0_rx_isr(void)
{
char status,data;
status=UCSR0A;
data=UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer0[rx_wr_index0]=data;
   if (++rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0=0;
   if (++rx_counter0 == RX_BUFFER_SIZE0)
      {
      rx_counter0=0;
      rx_buffer_overflow0=1;
      };
   };
}

#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART0 Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter0==0);
data=rx_buffer0[rx_rd_index0];
if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0=0;
#asm("cli")
--rx_counter0;
#asm("sei")
return data;
}
#pragma used-
#endif

/* USART0 Transmitter buffer
#define TX_BUFFER_SIZE0 8
char tx_buffer0[TX_BUFFER_SIZE0];

#if TX_BUFFER_SIZE0<256
unsigned char tx_wr_index0,tx_rd_index0,tx_counter0;
#else
unsigned int tx_wr_index0,tx_rd_index0,tx_counter0;
#endif

// USART0 Transmitter interrupt service routine
interrupt [USART0_TXC] void usart0_tx_isr(void)
{
if (tx_counter0)
   {
   --tx_counter0;
   UDR0=tx_buffer0[tx_rd_index0];
   if (++tx_rd_index0 == TX_BUFFER_SIZE0) tx_rd_index0=0;
   };
}

#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART0 Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while (tx_counter0 == TX_BUFFER_SIZE0);
#asm("cli")
if (tx_counter0 || ((UCSR0A & DATA_REGISTER_EMPTY)==0))
   {
   tx_buffer0[tx_wr_index0]=c;
   if (++tx_wr_index0 == TX_BUFFER_SIZE0) tx_wr_index0=0;
   ++tx_counter0;
   }
else
   UDR0=c;
#asm("sei")
}
#pragma used-
#endif     
*/

// USART1 Receiver buffer
#define RX_BUFFER_SIZE1 8
char rx_buffer1[RX_BUFFER_SIZE1];

#if RX_BUFFER_SIZE1<256
unsigned char rx_wr_index1,rx_rd_index1,rx_counter1;
#else
unsigned int rx_wr_index1,rx_rd_index1,rx_counter1;
#endif

// This flag is set on USART1 Receiver buffer overflow
bit rx_buffer_overflow1;

// USART1 Receiver interrupt service routine
interrupt [USART1_RXC] void usart1_rx_isr(void)
{
char status,data;
status=UCSR1A;
data=UDR1;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer1[rx_wr_index1]=data;
   if (++rx_wr_index1 == RX_BUFFER_SIZE1) rx_wr_index1=0;
   if (++rx_counter1 == RX_BUFFER_SIZE1)
      {
      rx_counter1=0;
      rx_buffer_overflow1=1;
      };
   };
}

// Get a character from the USART1 Receiver buffer
#pragma used+
char getchar1(void)
{
char data;
while (rx_counter1==0);
data=rx_buffer1[rx_rd_index1];
if (++rx_rd_index1 == RX_BUFFER_SIZE1) rx_rd_index1=0;
#asm("cli")
--rx_counter1;
#asm("sei")
return data;
}
#pragma used-
// USART1 Transmitter buffer
#define TX_BUFFER_SIZE1 8
char tx_buffer1[TX_BUFFER_SIZE1];

#if TX_BUFFER_SIZE1<256
unsigned char tx_wr_index1,tx_rd_index1,tx_counter1;
#else
unsigned int tx_wr_index1,tx_rd_index1,tx_counter1;
#endif

// USART1 Transmitter interrupt service routine
interrupt [USART1_TXC] void usart1_tx_isr(void)
{
if (tx_counter1)
   {
   --tx_counter1;
   UDR1=tx_buffer1[tx_rd_index1];
   if (++tx_rd_index1 == TX_BUFFER_SIZE1) tx_rd_index1=0;
   };
}

// Write a character to the USART1 Transmitter buffer
#pragma used+
void putchar1(char c)
{
while (tx_counter1 == TX_BUFFER_SIZE1);
#asm("cli")
if (tx_counter1 || ((UCSR1A & DATA_REGISTER_EMPTY)==0))
   {
   tx_buffer1[tx_wr_index1]=c;
   if (++tx_wr_index1 == TX_BUFFER_SIZE1) tx_wr_index1=0;
   ++tx_counter1;
   }
else
   UDR1=c;
#asm("sei")
}
#pragma used-

// update the real time clock
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{ 

G_seconds++;  // count the time    

}  // end of rtc update             



// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input|ADC_VREF_TYPE;
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}                                                                                       

//**************************************************************************************
// application routine start here      
   
//--------------------------------------------------------------------------------------
// routine to get temperature can convert to Celsius  
// probably should do some averaging but that is left to the user
float get_temperature (void)
{   
 float temp;    

 temp = read_adc(0);    // get the temperature
  
 // convert to voltage using Vcc as the reference
 temp = (temp/1024) * 5; // assumes a 5 volt supply
 
 // convert to C using the approximation: T = V*100 - 600
 temp = temp*100 - 60;
 
 return (temp);
 
 } // end of get_temperature

//--------------------------------------------------------------------------
// routine to read temperature and update screen
void show_temperature(void)
{
 char str[16];           
 
 lcd_gotoxy(0,0);   
 lcd_putsf ("                ");       
 
 // Note: we're using the itoa rather than the ftoa since it uses less memory 
 itoa(get_temperature(), str); 
 
 // this would be easier using a sprintf statement but that exceeds the demo memory size.

 lcd_gotoxy(0,0);
 lcd_putsf("Temperature:");
 lcd_puts (str);      

}   // end of show_temperature

//-----------------------------------------------------------------------------
void tx_temperature(void)
{
char str[20] = "Temperature: "; 
char tstr[5]; 
byte i;

 // Note: Again, we're using the itoa rather than the ftoa since it uses less memory 
 
 itoa(get_temperature(), tstr); 
 strcat(str,tstr);                          
 strcatf(str, " C\n\r");
 
 for (i=0; str[i]!=0;i++) putchar1 (str[i]);   
 
}   // end of tx_temperature
  
          
//----------------------------------------------------------------------------------
// this is a basic routine that scans a 3x3 keypad     
// flag == 1 will force the routine to run until a key is pressed  
/*  note that our default keypad is laid out like this:       
        |       |
    1   |   2   |   3
   ---------------------
    4   |   5   |   6
   -----|-------|-------
    7   |   8   |   9
        |       |

of course you can print your own placard and change the decoded return values  */

byte keyin (byte flag)
{   
byte row, col=0, key;

col = 0x08;  // keypad is only 3 x 3 

if (flag) 	
    do  // we will run this loop until a key is pressed
	{ 
    PORTC = ~col;    // output inverted row; leave pullups on 
	delay_ms (20);
	row = PINC & 0x07;  	// read rows and ignore upper bits     
    key = col + row;	

    col <<=1;               // shift left for next row  
	if (col >= 0x40) col = 0x08; // if past columns then reset
	
 	} while (row == 0x07);  // stop when you find the key 

       
else //scan keypad once
    {
    do
	    {
	    PORTC = ~col; // shift left 1 bit after evalation  
        delay_ms (20);	    
	    row = PINC & 0x07;	 
        key = row + col; // combine the two to build the code   	       
        
	    col <<= 1;       

	    } while ((row == 0x07) && (col < 0x40));   //until key pressed or col finished    
    } // end else	                
	    
    PORTC = 0xFF; // turn them all off (negative logic)        
      
switch (key)
    {
	case 0xb : return ('1');    
	case 0x13 : return ('2');
	case 0x23 : return ('3');
	case 0xD : return ('4');
	case 0x15 : return ('5');
	case 0x25 : return ('6');
	case 0xE : return ('7');
	case 0x16 : return ('8');
	case 0x26 : return ('9');
	
	default :   return ('X');
                 
	} // end of case	  
	
} // end of keyin  


//----------------------------------------------------------------------    
// routine key released       
 void keyrel (void)                             
{  
 PORTC = 0x07;   // all outputs low; leave pullups on  
 delay_ms(5);	// need to let the outputs settle; this is overkill
 // now run this loop until the key is released
 while ( (PINC & 0x07) != 0x07);  // do nothing
 
 } // end of function nokey    

//----------------------------------------------------------------------                          
byte get_key(byte cmd)
{       // cmd == 0 we only scan the keypad once
        // cmd == 1 we wait for a key press

        byte k;

		if ((k = keyin(cmd)) != 'X')     //nothing pressed
   		{   
			delay_ms(30);  //wait a bit
	
			if (k == keyin(0) )   // make sure it's the same key
				{          
				BEEP_ON;
				keyrel(); 			// wait for release
				BEEP_OFF;
				return (k);       // send it out
    			}
 		} 	// end of if    
 		
return ('X'); // nothing 		

 }


//////////////////////////////////////////////////////////////////////////
// set contrast via the digital potentiometer    
// first it cranks the value to 0; then counts it up
// this was done to simplify the "power off" reset vs the reset going low 
// since the digital pot doesn't see the reset line.
// Yes, there are more elegant ways to do this!            
// NOTE: due to the memory structure of the ATMEGA128 we cannot use the 
// PORTn.x = y; syntax for ports F and G.      
// bit 0 == up/down
// bit 1 == chip select
// bit 2 == Increment
//              
// higher values of 'contrast' will result in a lighter display
// lower values of 'contrast' results in a darker display
void set_contrast(byte contrast)           

{      
byte x;  
// first turn contrast all the way down:  
// this solves the power up vs reset problem
      
    PORTG = 0;      // drop cs for lcd pot
    delay_us (1);
    for (x = 0; x <= 31; x++)
    {
    PORTG = 0b0100; // set the increment bit
    delay_us (1);
    PORTG = 0;      // clear it
    delay_us (1);
    } 

 // need to count up
    PORTG = 0b001;  // count up
    delay_us (1);
    for (x = 0; x <= contrast; x++)
    {
    PORTG = 0b101; // set the increment bit
    delay_us (1);
    PORTG = 0b001;
    delay_us (1);
    }
}
//**********************************************************************************
//**********************************************************************************
void main(void)
{
// Declare your local variables here
byte key = 0;   // used by the main menu loop   
byte baklite = 0; // brightness of backlight  
byte contrast = 5;

char t_str[16]; // general purpose temp string


// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 

DDRC=0x38;   // bits 3, 4, and 5 are keypad outputs  
PORTC=0x00;  // 

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTD=0x00;
DDRD=0x00;

// Port E initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTE=0x00;
DDRE=0x18;       // bit 3 used by the beep function

// Port F initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTF=0x00;
DDRF=0x00;

// Port G initialization
// Func4=In Func3=In Func2=In Func1=In Func0=In 
// State4=T State3=T State2=T State1=T State0=T 
PORTG=0x00;
DDRG=0x07;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
ASSR=0x08;      // enable the TOSC1 and TOSC0 pins; use the 32,768 Hz crystal 
TCCR0=0x05;     // divide by 128; combined with overflow will give 1 sec interrupts
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// OC1C output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
// Compare C Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
OCR1CH=0x00;
OCR1CL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// Timer/Counter 3 initialization
// Clock source: System Clock
// Clock value: 8000.000 kHz
// Mode: Normal top=FFFFh
// Noise Canceler: Off
// Input Capture on Falling Edge
// OC3A output: Toggle
// OC3B output: Discon.
// OC3C output: Discon.
// Timer 3 Overflow Interrupt: On
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
// Compare C Match Interrupt: Off
TCCR3A=0x21;    // Fast PWM for channel B; 
TCCR3B=0x0A;    // CTC mode and divide by 8
TCNT3H=0x00;
TCNT3L=0x00;
ICR3H=0x00;
ICR3L=0x00;
OCR3AH=0x00;
OCR3AL=0x7F;    // this value sets the tone of the beep
OCR3BH=0x00;
OCR3BL=0x00;    // determines the backlight brightness
OCR3CH=0x00;
OCR3CL=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
// INT3: Off
// INT4: Off
// INT5: Off
// INT6: Off
// INT7: Off
EICRA=0x00;
EICRB=0x00;
EIMSK=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;     // enable overflow for timer0
ETIMSK=0x00;

// USART0 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART0 Receiver: On
// USART0 Transmitter: On
// USART0 Mode: Asynchronous
// USART0 Baud rate: 9600
UCSR0A=0x00;
UCSR0B=0xD8;
UCSR0C=0x06;
UBRR0H=0x00;
UBRR0L=0x33;

// USART1 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART1 Receiver: On
// USART1 Transmitter: On
// USART1 Mode: Asynchronous
// USART1 Baud rate: 9600
UCSR1A=0x00;
UCSR1B=0xD8;
UCSR1C=0x06;
UBRR1H=0x00;
UBRR1L=0x33;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC Clock frequency: 125.000 kHz
// ADC Voltage Reference: AVCC pin
ADMUX=ADC_VREF_TYPE;
ADCSRA=0x86;

// LCD module initialization
lcd_init(16);

// Global enable interrupts
#asm("sei")
               
set_contrast(5);
                             
lcd_putsf ("JEM Innovation");   // advertise     
lcd_gotoxy(0,1);
lcd_putsf (" PDK Solutions ");

BEEP_ON;
delay_ms(500);
BEEP_OFF;  

while (1)
      {
        key = get_key(1);  // get a key
        switch (key)
        {
            case '1':   if (baklite < 244) baklite += 10;
                        OCR3BL = baklite;
                        break;
                        
            case '2':   if (baklite >= 10) baklite -= 10;
                        OCR3BL = baklite;
                        break;
                        
            case '3':   break;
            
            case '4':   if (contrast < 31) contrast++;
                        set_contrast (contrast);
                        break;   
                        
            case '5':   if (contrast > 0) contrast--;
                        set_contrast (contrast);
                        break;
                          
            case '6':   break;
            
            case '7':   show_temperature();
                        break;
                        
            case '8':   tx_temperature();
                        break;  
                        
            case '9':   lcd_gotoxy (0,3);
                        lcd_putsf ("                ");  // blank the line
                        lcd_gotoxy(0,3);
                        itoa (G_seconds, t_str);        // display the total seconds
                        lcd_puts (t_str);
                        break;
            
            default :   break;
            
        }       // end of switch              
 
      }     // end of while 
      
} // end of main

