/*
* 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
char* sStrPos;
// Position of Errorpointer when we convert string to long
char* pStrErrPos;
// 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 *sMessage1, long 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 *sMessage1, long 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);
}