/*
* Author: Michael Albert
* 11.03.2008

* Debug Version 
*
* Configure your ttyS0 to 2400 8N1
* Wakes an ATX PC in xx Seconds transmitted by uart
*
* Unterstands 3 commands:
* ATC resets/deletes an active wakeup
* ATS1234 starts PC in 1234 seconds
* ATP prints out the Timer state
*
* Editor/avr-gcc WinAVR 20071221
* License:  GNU General Public License 

* LICENSE:
*    Copyright (C) 2008 Michael Albert
*
*    This program 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
*    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.
*
* Feel free to modify!
*
*/

/* TODO INTERRUPT */
#include <avr/io.h>
#include <avr/interrupt.h> 
#include <string.h>
#include <stdlib.h>
#include <util/delay.h>
// Peter fleury's uart library
#include "uart.h"

// For bool variables
#define TRUE 1
#define FALSE 0

// With Debugcode?
#define DEBUG 1
// 9600 does not work for my atmega8 ????
#define BAUD_RATE 2400
// Should we echo each received byte back to uart?
#define UART_ECHO 1

// Define my Port BIT Names 
// Timer running PortC 2, atmega8 Pin 25  
#define COUNTER_ACTIVE_LED PC2 
// Board running PortC 1, atmega8 Pin 24  
#define ACTIVE_LED PC1 
//  PIN for POWER button, atmega8 Pin 23  
#define POWER_PIN PC0
// Input PIN for 5V VDC, atmega8 Pin 28
#define PIN_5VDC PINC5
// If this Input PIN is connected to low, Debug Messages are print to uart, atmega8 Pin 27
// Must be connected at power on 
#if DEBUG
#define PIN_DEBUG PINC4
#endif

// Macros
// Toogles a LED/Bit at Port and pin
#define TOGGLE_LED(_port,_pin){((_port) & (1<<(_pin)))?((_port)&=~(1<<(_pin))):((_port)|=(1<<(_pin)));}
// Clear LED at Port and pin = VOltage to High 5V
#define CLEAR_LED(_port,_pin){((_port)|=(1<<(_pin)));}
// Set LED on at Port and pin = VOltage to Low 0V  
#define SET_LED(_port,_pin){((_port)&=~((1<<(_pin))));}
// Press powerbutton for 200ms  0V, wait 200ms, 5V
// #define PRESS_POWERBUTTON(_port,_pin){((_port)&=~(1<<(_pin)));(_delay_ms(200));((_port)|=(1<<(_pin)));}
#define PRESS_POWERBUTTON {((PORTC)&=~(1<<(POWER_PIN)));(_delay_ms(200));((PORTC)|=(1<<(POWER_PIN)));}
// Is powersupply still on
#define IS_POWER_ON ((PINC) & (1<<PIN_5VDC))

// Prefix of the commands, 2 chars
char sATCommandPrefix[3]="AT";
// Complete String which is received from uart
char sReceived[30]="";
// Position of Pointer when we parse the string
charsStrPos
// Position of Errorpointer when we convert string to long
charpStrErrPos
// Receives 2Bytes from uart, lower byte data, higher byte stat
unsigned int iReceive;
// Is a complete string received ?
uint8_t  bSringComplete;
// Seconds to start my PC
// As long -1=Timer inactive
long iSecondsToPowerOn=-1;
// Should we start the box?
uint8_t bStartBox;
#if DEBUG
uint8_t bPrintDebugMessages=FALSE;
#endif


// Function prototypes
static int  is_at_command(char *sCom,char *sATPrefix);
static void init_ioports(void);
static void init_counter(void);
static void fPrintCounterState(void);
#if DEBUG
static void print_debug(char *sMessage1,char *Message2);
static void print_debug_long(char *sMessage1long iNumber);
#endif


int main(void){
        // IO port init
        init_ioports();
        // counter init with external 32,768khz xtal
        init_counter();
        // UART Init
        uart_init(UART_BAUD_SELECT(BAUD_RATE,F_CPU));
        //Interrupts On
        sei();
        // We say hello  ;-)
        uart_puts("\rS100 Wakeup V1.0 \r\n");
        // init
        bSringComplete=FALSE;
        bStartBox=FALSE;
#if DEBUG
        // Set debug mode if Debug pin is connected to low
        if (~PINC & (1<<PIN_DEBUG)){bPrintDebugMessages=TRUE;}
        else{bPrintDebugMessages=FALSE;}
#endif
        for(;;){
                /*************************** begin read string from uart ***********************/
                // Get data from uart
                iReceive=uart_getc();
                // Errors
                if ( iReceive & (UART_FRAME_ERROR | UART_OVERRUN_ERROR | UART_BUFFER_OVERFLOW)  ){
#if DEBUG               
                        if (bPrintDebugMessages){
                                char sErrorNumber[6]="";
                                ltoa(16,sErrorNumber,iReceive);
                                print_debug("\r\nNo Data or error: ",sErrorNumber);
                        }
#endif
                }
                // No data
                else if(iReceive & UART_NO_DATA){
                        // Do nothing
                }
                // Data available
                else{
#if DEBUG                       
                        /*
                                char cTmp;
                                cTmp=(char)iReceive;
                                print_debug_long("Char received: ",(int)cTmp);
                        */

#endif          
                        // echo char
                        if (UART_ECHO){uart_putc((char)iReceive);}
                        // ...until Return Character is 0x0d = 13 is received
                        if ((char)iReceive=='\r'){
                                bSringComplete=TRUE;
                                if (UART_ECHO){uart_putc('\n');}
#if DEBUG                       
                                if (bPrintDebugMessages){uart_puts("\r\nString complete received.\n\r");}
#endif                          
                        }
                        else {
                                // Only if enough space in sReceived free
                                if(sizeof(sReceived)>strlen(sReceived)){
                                        // Concatinate all characters to a string....., we need only the lower byte. 
                                        // Valid character or return??
                                        if ((((uint8_t)iReceive >= 32)&&((uint8_t)iReceive <= 126)) || ((uint8_t)iReceive==13)){
                                                strcat(sReceived,(char*)&iReceive);
                                        }
                                }
                        }
                }
                /*************************** end read string from uart ***********************/
                // When string is now completed
                if (bSringComplete){
#if DEBUG               
                                if (bPrintDebugMessages){print_debug("String: ",sReceived);}
#endif                          
                                // Is an AT Command
                                if (is_at_command(sReceived,sATCommandPrefix)){
                                        sStrPos=sReceived;
                                        // String pointer to 3rd Character
                                        sStrPos+=2;
                                        // Which AT command, allowed are S,P and C
                                        switch (*sStrPos) {
                                        case 'S':
                                                // String pointer to 4th Character
                                                sStrPos++;
#if DEBUG                                                       
                                                if (bPrintDebugMessages){print_debug(" Seconds: ",sStrPos);}
#endif                                  
                                                iSecondsToPowerOn=0;
                                                // Try to convert string to long
                                                iSecondsToPowerOn=strtol(sStrPos,&pStrErrPos,10);
                                                if (*pStrErrPos=='\0'){
                                                        fPrintCounterState();
#if DEBUG
                                                        if (bPrintDebugMessages){print_debug_long(" Convert ok: ",iSecondsToPowerOn);}
#endif
                                                }
                                                else{
                                                        iSecondsToPowerOn=0;
                                                        uart_puts("Convert error at char: ");
                                                        uart_puts(pStrErrPos);
                                                        uart_puts("\r\n");
#if DEBUG
                                                        if (bPrintDebugMessages){print_debug(" Convert error at char: ",pStrErrPos);}
#endif
                                                }

                                                break;
                                        case 'C':
                                                //Clear Counter
                                                iSecondsToPowerOn=-1;
                                                break;
                                        case 'P':
                                                // We print the Timer state
                                                if (iSecondsToPowerOn>=0){
                                                        // Timer is active
                                                        fPrintCounterState();
                                                }
                                                else{
                                                        // Timer is  inactive
                                                        uart_puts("Timer inactive\n\r");
                                                }
                                                break;

#if DEBUG                               
                                        default:
                                                if (bPrintDebugMessages){print_debug("Unknown AT command: ",sReceived);}
#endif                                  
                                        }       
                                }
                                // No AT command
                                else{
#if DEBUG                               
                                        if (bPrintDebugMessages){print_debug("Unknown command: ",sReceived);}
#endif                                  
                                }
                                // String reset
                                strcpy(sReceived,"");
                                // 
                                bSringComplete=FALSE;
                }
                // End string is complete received
                // Any actions?
                // Must we press the power button?
                 
                if (bStartBox){
                        if (! IS_POWER_ON){                     
                                uart_puts("Pressing powerbutton.\r\n");
                                PRESS_POWERBUTTON;
                        }
                        else{
                                uart_puts("Pressing powerbutton canceled. Power is active.\r\n");
                        }
                        // Waiting for next
                        bStartBox=FALSE;
                }
                
        }               
        // end loop 
        return(0);
}

// END MAIN

#if DEBUG       
// print simply 2 strings followed by \r\n to uart
static void print_debug(char *sMessage1,char *Message2){
        char sDebugText[80];
        strcpy(sDebugText,sMessage1);
        strcat(sDebugText,Message2);
        strcat(sDebugText,"\n\r");
        uart_puts(sDebugText);
}
#endif
// Check if first 2 Characters are right prefix
static int is_at_command(char *sCom,char *sATPrefix){
        if (strncmp(sCom,sATPrefix,2)){
                return(0);
        }
        else{
                return(1);
        }
        
}
#if DEBUG
// print simply one strings, an long int  followed by \r\n to uart
static void print_debug_long(char *sMessage1long iNumber){
        char sDebugText[80];
        char sTemp[12];
        strcpy(sDebugText,sMessage1);
        ltoa(iNumber,sTemp,10);
        strcat(sDebugText,sTemp);
        strcat(sDebugText,"\n\r");
        uart_puts(sDebugText);
}
#endif
// Init the oi ports
static void init_ioports(void){
        DDRB  = 0xff;
        
        /*
                Ports definition
                PORTC output:
                        PC0=Power button
                        PC1=Timer active, blinking 1Hz
                        PC2=Counter active, blinking 1Hz
                PORTC input:
                        PC4=Debug Mode, if this connect to GND.
                        PC5=Input +5 VDC PC, to see if the box is already running
        */
 
        // PORT
        // All Output Ports=off=5V, on input pins pullups on
        PORTC = (0xff);
        DDRC  = 0x0f;
}
// init counter
static void init_counter(void){
        // Timer2 clocked by external 32.768kHz
        // ASSR = _BV(AS2);
        ASSR |= (1<<AS2);

        // Clock/128 for 0,5Hz blinking and timer overflow every 1 second
        // TCCR2 = _BV(CS22)|_BV(CS20);
        TCCR2 |= (1<<CS22) | (1<<CS20); 

        // Clock/64=2Hz for 1Hz blinking with toogle_bit
        // TCCR2 = _BV(CS22);
        // TCCR2 |= (1<<CS22); 
        TCNT2 = 0;      
        // Timer2(8Bit) Overflow Interrupt enabled (256)
        // TIMSK = _BV(TOIE2);
        TIMSK |= (1<<TOIE2);
}
// timer overflow, every 1 second
SIGNAL(SIG_OVERFLOW2){
        // toogle led to show the board is alive
        TOGGLE_LED(PORTC,ACTIVE_LED);
        // Counter active when >= 0, decrement counter
        if (iSecondsToPowerOn>=0){
                // dec one second  
#if DEBUG
                if (bPrintDebugMessages){print_debug_long(" Timer active: ",iSecondsToPowerOn);}
#endif
                iSecondsToPowerOn--;
                TOGGLE_LED(PORTC,COUNTER_ACTIVE_LED);
                // Counter = 0, it's time we must start the box
                
                
                if (iSecondsToPowerOn==0){
                        // We press the power button in mainloop, not in interrupt
#if DEBUG                               
                        // print_debug(" Timer 0 set Presspowerbutton","");
#endif                                  
                        bStartBox=TRUE;
                }
                
        }
        // Timer is inactive, we do nothing
        else{
                CLEAR_LED(PORTC,COUNTER_ACTIVE_LED);
        }
}
// Print Counter to uart
static void fPrintCounterState(void){
        char sCounterState[35]="";
        char sCounter[10]="";
        strcpy(sCounterState,"Timer active: ");
        // Long 2 ASCII
        ltoa(iSecondsToPowerOn,sCounter,10);
        strcat(sCounterState,sCounter);
        strcat(sCounterState,"s\n\r");
        // Print the string out
        uart_puts(sCounterState);
}