|
/*
* Author: Michael Albert * 11.03.2008 * * 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! * * Changes: * 11.04.2008 Michael Albert V1.1 Option to start the box delayed after power is connected. */ /* 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 // 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 // Input PIN for Press Powerbutton after xx Seconds wenn Powersupply is connected to electricity network. // atmega8 Pin 26, is Low Active, means Powerbutton would only pressed wenn PIN26 is conntect to GND #define IN_AUTO_PRESS_POWERBUTTON_STARTUP PINC3 // When AUTO_PRESS_POWERBUTTON_STARTUP how much seconds should we wait #define AUTO_PRESS_POWERBUTTON_STARTUP_WAIT_TIME 15 // 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; // Auto Press Counter long iPressCounterForAutoStart=0; // 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); 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.1 \r\n"); // init bSringComplete=FALSE; bStartBox=FALSE; 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) ){ } // No data else if(iReceive & UART_NO_DATA){ // Do nothing } // Data available else{ // 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');} } 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){ // 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++; iSecondsToPowerOn=0; // Try to convert string to long iSecondsToPowerOn=strtol(sStrPos,&pStrErrPos,10); if (*pStrErrPos=='\0'){ fPrintCounterState(); } else{ iSecondsToPowerOn=0; uart_puts("Convert error at char: "); uart_puts(pStrErrPos); uart_puts("\r\n"); } 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; } } // No AT command else{ } // String reset strcpy(sReceived,""); // bSringComplete=FALSE; } // End string is complete received // Any actions? // Must we press the power button? // Either on Active Counter or at box startup 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; CLEAR_LED(PORTC,COUNTER_ACTIVE_LED); } } // end loop return(0); } // END MAIN // 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); } } // 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 |= (1<<AS2); // Clock/128 for 0,5Hz blinking and timer overflow every 1 second TCCR2 |= (1<<CS22) | (1<<CS20); // Clock/64=2Hz for 1Hz blinking with toogle_bit TCNT2 = 0; // Timer2(8Bit) Overflow Interrupt enabled (256) 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 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 bStartBox=TRUE; } } // Timer is inactive, we do nothing /* else{ CLEAR_LED(PORTC,COUNTER_ACTIVE_LED); }*/ // AutoStartCounter // IN_AUTO_PRESS_POWERBUTTON_STARTUP = Low(0V) and Counter < Wait Time if ((~PINC & (1<<IN_AUTO_PRESS_POWERBUTTON_STARTUP)) && (iPressCounterForAutoStart<=AUTO_PRESS_POWERBUTTON_STARTUP_WAIT_TIME)){ if (iPressCounterForAutoStart==AUTO_PRESS_POWERBUTTON_STARTUP_WAIT_TIME){ bStartBox=TRUE; } TOGGLE_LED(PORTC,COUNTER_ACTIVE_LED); iPressCounterForAutoStart++; } } // 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); } |
#!/usr/bin/perl
###############################################################################
# Gets the /proc/acpi/alarm or clear string from vdr and send it to the S100 atmega8 wakeup board
# Commandline arguments:
# 1. Wakeuptime as ACPI Time String (2006-02-09 23:05:00) or UNIX Systemdate (1141941900)
# or via STDIN
#
# 25.03.2008
# changes
#
# Michael Albert
# Comments to michael@albert-hetzles.de
# 1. FCN forever http://www.fcn.de
###############################################################################
use Time::Local;
use File::Basename;
use Sys::Syslog;
# S100 Serial port
$sSerialPort="/dev/ttyS0";
#$sSerialPort="/tmp/ATx.txt";
# Script messages to syslog
$bUseSysLog=1;
# Set system time
$bSetSystemTime=0;
# Time Servers
@aTimeServer=("ptbtime1.ptb.de","ptbtime2.ptb.de");
# ntpbin
$sNTPDate="sudo /usr/sbin/ntpdate -u ";
# Setup /InitSerialPort
$bSetupSerial=1;
# stty exe string, BAUD 2400, Bits 8, Parity None, 1 Stopbit, noflowcontrol, no hardware handshake
$ssttyBin="stty -F $sSerialPort 2400 cs8 -cstopb -crtscts -ixon -ixoff";
# $sArg=Variable to store first command line parameter
# $iACPIStartTime=Variable to store in systemtime (1141941900)
my ($sArg,$iACPIStartTime,$sMessage);
$sMessage=" Starting VDR wakeup...";
print $sMessage."\n";
($bUseSysLog) && &fWriteSyslog($sMessage);
# Set time
if ($bSetSystemTime){
foreach (@aTimeServer){
$sMessage="Set systemtime from ntpserver $_\n";
print $sMessage."\n";
($bUseSysLog) && &fWriteSyslog($sMessage);
$iResult=system($sNTPDate.$_);
if ($iResult){
$sMessage="Error while setting systemtime $iResult\n";
print $sMessage."\n";
($bUseSysLog) && &fWriteSyslog($sMessage);
}
}
}
# Getting parameter
if (@ARGV[0]) {
# Get command line parameter
$sArg=@ARGV[0];
}
else{
# Or from stdin
$sArg=<STDIN>;
}
# cut \n
chomp($sArg);
# Check if format is already UNIX systemtime
if ($sArg=~/^[0-9]+$/){
# Yes, cool
$sMessage=" Get UNIX system time \($sArg\) via command line.";
print $sMessage."\n";
($bUseSysLog) && &fWriteSyslog($sMessage);
$iACPIStartTime=$sArg;
}
else{
# No, we must convert it.
$sMessage=" Get /proc/acpi/alarm formated string \($sArg\) via command line.";
print $sMessage."\n";
($bUseSysLog) && &fWriteSyslog($sMessage);
# Convert it to system time format. 2006-02-09 23:05:00 -> 1141941900
$iACPIStartTime=&fGetSystemTimeFromACPIStartTime($sArg);
}
if ($iACPIStartTime){
($bSetupSerial) && system($ssttyBin);
my ($iTimeNow,$iTimeDiff);
# print "ACPI Time: $iACPIStartTime\n";
# Calculating difference between Starttime and now in seconds
$iTimeDiff=$iACPIStartTime-time;
if ($iTimeDiff>0){
$sMessage=" Starting VDR in $iTimeDiff seconds.";
print $sMessage."\n";
($bUseSysLog) && &fWriteSyslog($sMessage);
# send command string to Board via serial port
#open(hSTTY,">$sSerialPort")||die "Can't open $sSerialPort\n";
print 'echo -e "\\rATS'.$iTimeDiff.'\\r" > '.$sSerialPort;
system('echo -e "\\rATS'.$iTimeDiff.'\\r" > '.$sSerialPort);
#close(hSTTY);
}
else{
# Think positive :-)
$iTimeDiff*=-1;
$sMessage=" VDR starting time is $iTimeDiff seconds in the past\! Resetting timer.";
warn $sMessage."\n";
($bUseSysLog) && &fWriteSyslog($sMessage);
system('echo -e "\\rATC\\r" > '.$sSerialPort);
}
}
else{
warn " Unknown command or time format\n";
}
###############################################################################
# 1. Parameter ACPI Time (Format: 2006-02-09 23:05:00)
# Return systemtime
sub fGetSystemTimeFromACPIStartTime(){
my ($sACPIStartTime,$sDate,$sTime,$sSec,$sMin,$sHour,$sDay,$sMon,$sYear);
$sACPIStartTime=shift;
($sDate,$sTime)=split(/ /,$sACPIStartTime);
($sHour,$sMin,$sSec)=split(/\:/,$sTime);
($sYear,$sMon,$sDay)=split(/\-/,$sDate);
# print"$sSec,$sMin,$sHour,$sDay,$sMon,$sYear\n";
# timelocal wants Month from 0..11
$sMon-=1;
# We try to convert it
eval{
$iACPISysTime = timelocal($sSec,$sMin,$sHour,$sDay,$sMon,$sYear);
};
# successfully?
if ($@){
# No
my $sErrorMessage;
$sErrorMessage=$@;
chomp($sErrorMessage);
warn " ERROR $sErrorMessage.\n Cannot convert \"$sACPIStartTime\". Wrong format or incorrect date.\n";
($bUseSysLog) && &fWriteSyslog(" ERROR $sErrorMessage.\n Cannot convert \"$sACPIStartTime\". Wrong format or incorrect date.\n");
return(0);
}
else{
# Yes
return($iACPISysTime);
}
}
# 1. Parameter Text write to syslog
sub fWriteSyslog(){
my $sText;
$sText = @_[0];
openlog($program . basename($0), 'pid', 'user');
syslog('info', $sText);
#syslog('mail|warning', 'this is a better test: %d', time);
closelog();
}
|