|
|
@ -0,0 +1,159 @@ |
|
|
|
/*************************************************************************** |
|
|
|
* Copyright (C) 04/2011 by Olaf Rempel * |
|
|
|
* razzor@kopf-tisch.de * |
|
|
|
* * |
|
|
|
* 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; version 2 of the License, * |
|
|
|
* * |
|
|
|
* 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. * |
|
|
|
* * |
|
|
|
* You should have received a copy of the GNU General Public License * |
|
|
|
* along with this program; if not, write to the * |
|
|
|
* Free Software Foundation, Inc., * |
|
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
|
|
|
***************************************************************************/ |
|
|
|
#include <avr/io.h> |
|
|
|
#include <avr/interrupt.h> |
|
|
|
#include <avr/eeprom.h> |
|
|
|
#include <avr/sleep.h> |
|
|
|
|
|
|
|
/* |
|
|
|
* attiny24: (no self programming, 2.7V BOD, 8MHz internal RC Osz) |
|
|
|
* LFUSE = 0xC2 |
|
|
|
* HFUSE = 0xDD |
|
|
|
* EFUSE = 0xFF |
|
|
|
* |
|
|
|
* RC5 Input on PB2 (INT0) |
|
|
|
* PROGMODE Jumper (active low) on PB1 |
|
|
|
* OUTPUT (active low) on PB0 |
|
|
|
*/ |
|
|
|
|
|
|
|
/* RC5 bitlength is 1778us +/-10% convert to time0 ticks (8us) */ |
|
|
|
#define BITWIDTH (1778 / 8) |
|
|
|
#define BITWIDTH_MIN (BITWIDTH - (BITWIDTH / 10)) |
|
|
|
#define BITWIDTH_MAX (BITWIDTH + (BITWIDTH / 10)) |
|
|
|
|
|
|
|
#define RC5_BITCNT 14 |
|
|
|
#define RC5_CMD_MASK 0x37FF |
|
|
|
#define RC5_COMPLETE 0x8000 |
|
|
|
|
|
|
|
#define PROGMODE_CHECK() (!(PINB & (1<<PINB1))) |
|
|
|
#define OUTPUT_ON() { PORTA &= ~(1<<PORTA0); } |
|
|
|
#define OUTPUT_OFF() { PORTA |= (1<<PORTA0); } |
|
|
|
|
|
|
|
struct ee_param { |
|
|
|
uint16_t rc5cmd; |
|
|
|
uint8_t state; |
|
|
|
}; |
|
|
|
|
|
|
|
struct ee_param params; |
|
|
|
struct ee_param params_in_eeprom EEMEM = { |
|
|
|
.rc5cmd = 0x350C, |
|
|
|
.state = 0x00, |
|
|
|
}; |
|
|
|
|
|
|
|
static uint8_t bitcnt; |
|
|
|
static volatile uint16_t value; |
|
|
|
|
|
|
|
ISR(EXT_INT0_vect) |
|
|
|
{ |
|
|
|
if (bitcnt == 0) |
|
|
|
value = 0; |
|
|
|
|
|
|
|
bitcnt++; |
|
|
|
|
|
|
|
value = (value << 1); |
|
|
|
if (!(PINB & (1<<PINB2))) |
|
|
|
value |= 0x0001; |
|
|
|
|
|
|
|
/* setup sample window for next edge */ |
|
|
|
OCR0A = TCNT0 + BITWIDTH_MIN; |
|
|
|
OCR0B = TCNT0 + BITWIDTH_MAX; |
|
|
|
|
|
|
|
/* clear and enable COMPA / COMPB */ |
|
|
|
TIFR0 = (1<<OCF0A) | (1<<OCF0B); |
|
|
|
TIMSK0 |= (1<<OCIE0A) | (1<<OCIE0B); |
|
|
|
|
|
|
|
/* disable INT0 until COMPA hits */ |
|
|
|
GIMSK &= ~(1<<INT0); |
|
|
|
} |
|
|
|
|
|
|
|
ISR(TIM0_COMPA_vect) |
|
|
|
{ |
|
|
|
/* clear and enable INT0 */ |
|
|
|
GIFR = (1<<INTF0); |
|
|
|
GIMSK |= (1<<INT0); |
|
|
|
} |
|
|
|
|
|
|
|
ISR(TIM0_COMPB_vect) |
|
|
|
{ |
|
|
|
/* disable sample window */ |
|
|
|
TIMSK0 &= ~((1<<OCIE0A) | (1<<OCIE0B)); |
|
|
|
|
|
|
|
/* final bit received? */ |
|
|
|
if (bitcnt >= RC5_BITCNT) |
|
|
|
value |= RC5_COMPLETE; |
|
|
|
|
|
|
|
bitcnt = 0; |
|
|
|
} |
|
|
|
|
|
|
|
int main(int argc, char *argv[]) |
|
|
|
{ |
|
|
|
/* pullup on RC5IN and PROGMEM, OUTPUT is low active */ |
|
|
|
PORTB = (1<<PORTB2) | (1<<PORTB1) | (1<<PORTB0); |
|
|
|
|
|
|
|
/* INT0: both edges generate interrupt */ |
|
|
|
MCUCR = (1<<ISC00); |
|
|
|
GIMSK = (1<<INT0); |
|
|
|
|
|
|
|
/* Timer0: 8Mhz/64 */ |
|
|
|
TCCR0B = (1<<CS01) | (1<<CS00); |
|
|
|
|
|
|
|
/* load configuration, restore state */ |
|
|
|
eeprom_read_block(¶ms, ¶ms_in_eeprom, sizeof(struct ee_param)); |
|
|
|
if (params.state) { |
|
|
|
OUTPUT_ON(); |
|
|
|
} else { |
|
|
|
OUTPUT_OFF(); |
|
|
|
} |
|
|
|
|
|
|
|
/* all interrupts can wake up */ |
|
|
|
set_sleep_mode(SLEEP_MODE_IDLE); |
|
|
|
sei(); |
|
|
|
|
|
|
|
uint16_t old_value = 0x0000; |
|
|
|
|
|
|
|
while (1) { |
|
|
|
/* wait for next interrupt */ |
|
|
|
sleep_mode(); |
|
|
|
|
|
|
|
if (value & RC5_COMPLETE) { |
|
|
|
/* PROGMODE jumper set? */ |
|
|
|
if (PROGMODE_CHECK()) { |
|
|
|
params.rc5cmd = (value & RC5_CMD_MASK); |
|
|
|
eeprom_write_block(¶ms, ¶ms_in_eeprom, sizeof(struct ee_param)); |
|
|
|
|
|
|
|
/* current command matches stored one */ |
|
|
|
} else if (params.rc5cmd == (value & RC5_CMD_MASK) && value != old_value) { |
|
|
|
if (params.state) { |
|
|
|
params.state = 0; |
|
|
|
OUTPUT_OFF(); |
|
|
|
} else { |
|
|
|
params.state = 1; |
|
|
|
OUTPUT_ON(); |
|
|
|
} |
|
|
|
|
|
|
|
eeprom_write_block(¶ms, ¶ms_in_eeprom, sizeof(struct ee_param)); |
|
|
|
old_value = value; |
|
|
|
} |
|
|
|
|
|
|
|
value = 0x0000; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |