--- /dev/null
+#ifndef __HARDWARE_H
+#define __HARDWARE_H
+
+
+#include "pin_magic.h"
+
+#define PIN_LED _PIN(PORTB, PORTB2)
+#define PIN_SENSE _PIN(PORTB, PORTB4)
+#define PIN_DRIVE _PIN(PORTB, PORTB3)
+#define PIN_BTN _PIN(PORTB, PB1)
+
+#define MM_SENSE (!PINVAL(PIN_SENSE))
+#define BTN_PRESSED (!PINVAL(PIN_BTN))
+
+#define START_TIMER0 ({TCNT0 = 0; TCCR0B = 2;})
+#define START_TIMER1 ({TCNT1 = 1; TCCR1 = 7; GTCCR |= 2;})
+#define STOP_TIMER1 ({TCCR1 = 0; TCNT1 = 1;})
+
+
+static inline void setup_hw(void)
+{
+ /* Turn off the 1/8 clock prescaler - now running at 16MHz*/
+ CLKPR = (1 << CLKPCE);
+ CLKPR = 0;
+
+ INPUT_PIN(PIN_SENSE);
+ INPUT_PIN(PIN_BTN);
+ OUTPUT_PIN(PIN_DRIVE);
+ OUTPUT_PIN(PIN_LED);
+ setpin(PIN_BTN, 1); /* Need pullup */
+
+ GIMSK |= _BV(PCIE); /* Enable pin change interrupt for sense port */
+ PCMSK |= _BV(PCINT4); /* PB4, Rail sense input */
+
+ /* Change interrupt for button */
+ PCMSK |= _BV(PCINT1); /* PB1 */
+
+ /* Setup timer 0, used for mm_switch */
+ TCCR0A = 0; /* Normal mode */
+ TCCR0B = 0; /* Timer off */
+ TIMSK |= _BV(OCIE0A); /* Get a match interrupt */
+
+ /* We need 13 + 45,5 us delay, That's 464 clocks @8MHz*/
+ //OCR0A = 91; /* Prescaler 8 is used */
+
+ /* Timer 1 for timeout */
+ /* We set it to 1024us by prescaler 64 and running full 256 */
+ // TCCR1 = 7;
+ // TIMSK |= _BV(TOIE1); /* Overflow interrupt */
+}
+
+/* deprecated */
+#define START_TIMER0 ({TCNT0 = 0; TCCR0B = 2;})
+#define START_TIMER1 ({TCNT1 = 1; TCCR1 = 7; GTCCR |= 2;})
+#define STOP_TIMER0 (TCCR0B = 0)
+#define STOP_TIMER1 ({TCCR1 = 0; TCNT1 = 1;})
+
+#define TSTART_CLK_TO_SAMPLE_FAST ({TCNT0 = 0; GTCCR |= 1; OCR0A = 110; TCCR0B = 2;})
+#define TSTART_CLK_TO_SAMPLE_SLOW ({TCNT0 = 0; GTCCR |= 1; OCR0A = 220; TCCR0B = 2;})
+
+//#define TSTART_CLK_TO_SAMPLE_FAST ({TCNT0 = 0; GTCCR |= 1; OCR0A = 91; TCCR0B = 2;})
+//#define TSTART_CLK_TO_SAMPLE_SLOW ({TCNT0 = 0; GTCCR |= 1; OCR0A = 182; TCCR0B = 2;})
+
+#define TSTOP ({TCCR0B = 0;})
+
+
+
+#endif
#include <util/delay.h>
#include <stdint.h>
-#include "pin_magic.h"
-#include "mm_lookup.h"
-
-#define LED _PIN(PORTB, PORTB2)
-#define SENSE _PIN(PORTB, PORTB4)
-#define DRIVE _PIN(PORTB, PORTB3)
-#define BTN _PIN(PORTB, PB1)
-
-#define SIGIN (!PINVAL(SENSE))
-#define BTN_PRESSED (!PINVAL(BTN))
+#include "mm_switch.h"
+#include "hardware.h"
// #define DEBUG_TIMEOUT
#ifdef DEBUG_TIMEOUT
#define MON_TIMEOUT(xx) ({0;})
#endif
-uint8_t EEMEM ee_our_decoder;
-uint8_t EEMEM ee_our_key;
-
-static void setup_hw(void)
-{
- /* Get rid of the 1/8 clock prescaler */
- CLKPR = (1 << CLKPCE);
- CLKPR = 0;
-
- INPUT_PIN(SENSE);
- INPUT_PIN(BTN);
- OUTPUT_PIN(DRIVE);
- OUTPUT_PIN(LED);
- setpin(BTN, 1); /* Need pullup */
- _delay_ms(1); /* Let the line rise */
-
-
- GIMSK |= _BV(PCIE); /* Enable pin change interrupt */
- PCMSK = _BV(PCINT4); /* PB4, Rail sense input */
-
- TCCR0A = 0; /* This is normal mode */
- TCCR0B = 0; /* Timer off */
- TIMSK |= _BV(OCIE0A); /* Get a match interrupt */
- TIMSK |= _BV(TOV0); /* Overflow interrupt */
-
- /* We need 13 + 45 us delay, That's 464 clocks @8MHz*/
- OCR0A = 91; /* Prescaler 8 is used */
-
- /* Timer 1 for timeout */
- /* We set it to 1024us by prescaler 64 and running full 256 */
- TCCR1 = 7;
- TIMSK |= _BV(TOIE1); /* Overflow interrupt */
-}
-
-static uint8_t ctr = 0;
-
-static volatile uint8_t shift_sub;
-static volatile uint8_t shift_zero;
-static volatile uint8_t shift_decoder;
-static volatile uint8_t shift_sub_first;
-static volatile uint8_t shift_decoder_first;
-
-/* We will shift from right to left.
- * XXXXXXXX XX XXXXXXXX
- * shift_decoder shift_zero shift_sub
- *
- * The bits 7 downto 2 of shift_zero are ignored.
- */
-
-#define STOP_TIMER0 (TCCR0B = 0)
-
-volatile uint8_t bitno = 0;
-
-
-static void zero(void)
+#define EE_MAGIC 0xab
+
+enum op_mode {
+ OM_MOMENTARY, /* on as long as "key on" pressed */
+ OM_DOUBLE, /* On off with "on" and "off" keys */
+ OM_TOGGLE, /* toggle on "key on" pressed */
+ OM_ERASED = 0xff /* EEPROM erased, need setup */
+};
+
+enum learn_mode {
+ LM_OFF = 0,
+ LM_LEARN_ON_KEY, /* Learn primary key */
+ LM_LEARN_OFF_KEY, /* Learn secondary key, relevant for OM_DOUBLE */
+ LM_LEARN_INITIAL, /* Learn initial pulse length, 10ms steps */
+ LM_LEARN_DUTY, /* Learn duty cycle 0-10 */
+ LM_LEARN_OP_MODE, /* Learn operation mode */
+ LM_END, /* Only a label */
+};
+
+struct config {
+ uint8_t magic; /* Magic value */
+ enum op_mode op_mode;
+ uint8_t decoder_on;
+ uint8_t key_on;
+ uint8_t decoder_off;
+ uint8_t key_off;
+ uint8_t initial_pulse; /* Lenghth of initial pulse in 10ms steps */
+ uint8_t on_duty_cycle; /* Duty cycle for on. 0-10 */
+};
+
+static struct EEMEM config ee_config;
+static struct config config;
+static volatile enum learn_mode learn_mode = LM_LEARN_ON_KEY;
+
+static void load_config(void)
{
- setpin(LED, 1);
- _delay_ms(20);
- setpin(LED, 0);
- _delay_ms(980);
- GIFR |= _BV(PCIF);
+ eeprom_read_block(&config, &ee_config, sizeof(config));
}
-
-static void one(void)
+static void save_config(void)
{
- setpin(LED, 1);
- _delay_ms(20);
- setpin(LED, 0);
- _delay_ms(160);
- setpin(LED, 1);
- _delay_ms(20);
- setpin(LED, 0);
- _delay_ms(800);
- GIFR |= _BV(PCIF);
+ eeprom_write_block(&config, &ee_config, sizeof(config));
}
-static void trigger(void)
-{
- return;
- setpin(DRIVE, 1);
- _delay_us(20);
- setpin(DRIVE, 0);
-}
-
-static volatile uint8_t our_decoder = 3;
-static volatile uint8_t our_key = 5;
-static volatile uint8_t learn_mode = 0;
static volatile uint8_t drive_on = 0;
-ISR(TIMER0_COMPA_vect) {
-
- STOP_TIMER0;
-
- shift_decoder <<= 1;
- if (shift_zero & 2)
- shift_decoder |= 1;
- shift_zero <<= 1;
- if (shift_sub & 0x80)
- shift_zero |= 1;
- shift_sub <<= 1;
- if (SIGIN)
- shift_sub |= 1;
-
- bitno++;
-
- if (bitno == 18) { /* Save first received word */
- shift_sub_first = shift_sub;
- shift_decoder_first = shift_decoder;
- } else if (bitno == 36) {
-
- if ((shift_sub == shift_sub_first) &&
- (shift_decoder == shift_decoder_first)) {
- uint8_t decoder = lookup_decoder(shift_decoder);
- uint8_t command = lookup_command(shift_sub);
- if (decoder) {
- /* Congratulations, we have a valid command */
- trigger();
-
- if (learn_mode) {
- if (command) {
- our_decoder = decoder;
- our_key = command;
- learn_mode = 0;
- eeprom_write_byte(&ee_our_decoder, our_decoder);
- eeprom_write_byte(&ee_our_key, our_key);
- }
- } else {
- if (decoder == our_decoder) {
- if (command == our_key)
- drive_on = 1;
- if (command == 0)
- drive_on = 0;
- }
- }
- }
- }
- }
-}
-#define START_TIMER0 ({TCNT0 = 0; TCCR0B = 2;})
-#define START_TIMER1 ({TCNT1 = 1; TCCR1 = 7; GTCCR |= 2;})
-#define STOP_TIMER1 ({TCCR1 = 0; TCNT1 = 1;})
+ISR(PCINT0_vect){
+ static uint8_t btn_last = 0;
+ mm_pinchange_handler();
-ISR(TIM1_OVF_vect)
-{
- STOP_TIMER1;
- // if (!SIGIN)
- // setpin(LED, 1);
- bitno = 0;
- MON_TIMEOUT(1);
+ if (BTN_PRESSED && !btn_last) {
+ learn_mode++;
+ learn_mode %= LM_END;
+ }
+ btn_last = BTN_PRESSED;
}
-ISR(TIM0_OVF_vect)
+void mm_switch_command(uint8_t decoder, uint8_t command)
{
- while(1) {
- setpin(LED, 1);
- _delay_ms(30);
- setpin(LED, 1);
- _delay_ms(30);
- }
-
-}
+ static uint8_t toggle_lock = 0;
+ switch(learn_mode) {
+
+ case LM_OFF:
+ default:
+ if ((decoder == config.decoder_on) &&
+ (command == config.key_on)) { /* Primary key pressed */
+ switch(config.op_mode) {
+ case OM_MOMENTARY:
+ case OM_DOUBLE:
+ drive_on = 1;
+ break;
+ case OM_TOGGLE:
+ if (!toggle_lock) {
+ drive_on = !drive_on;
+ toggle_lock = 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
-/* Shortest element seen 184 clocks */
-/* Officially 208 clocks */
-/* (1 + 7) * 208 clocks */
+ if ((decoder == config.decoder_on) &&
+ (command == 0)) { /* Primary key released */
+ switch(config.op_mode) {
+ case OM_MOMENTARY:
+ drive_on = 0;
+ break;
+ case OM_TOGGLE:
+ toggle_lock = 0;
+ break;
+ default:
+ break;
+ }
+ }
-/* Pin change interrupt vector */
-ISR(PCINT0_vect)
-{
- START_TIMER1;
- MON_TIMEOUT(0);
+ if ((decoder == config.decoder_off) &&
+ (command == config.key_off)) { /* Secondary "off" key pressed */
+ switch(config.op_mode) {
+ case OM_DOUBLE:
+ drive_on = 0;
+ break;
+ case OM_TOGGLE:
+ case OM_MOMENTARY:
+ default:
+ break;
+
+ }
+ }
+ break;
+
+ case LM_LEARN_ON_KEY:
+ if (command) {
+ config.decoder_on = decoder;
+ config.key_on = command;
+ save_config();
+ if (config.op_mode == OM_DOUBLE)
+ learn_mode = LM_LEARN_OFF_KEY;
+ else
+ learn_mode = LM_OFF;
+ }
+ break;
+
+ case LM_LEARN_OFF_KEY:
+ if (command) {
+ config.decoder_off = decoder;
+ config.key_off = command;
+ save_config();
+ learn_mode = LM_OFF;
+ }
+ break;
+
+ case LM_LEARN_INITIAL:
+ if (drive_on) {
+ if (command == 0)
+ drive_on = 0;
+
+ } else {
+ switch(command) {
+ case 1:
+ if (config.initial_pulse >= 10)
+ config.initial_pulse -= 10;
+ else
+ config.initial_pulse = 0;
+ save_config();
+ drive_on = 1;
+ break;
+ case 2:
+ if (config.initial_pulse <= 245)
+ config.initial_pulse += 10;
+ else
+ config.initial_pulse = 255;
+ save_config();
+ drive_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
- if (SIGIN) {
- START_TIMER0;
+ case LM_LEARN_DUTY:
+ if (drive_on) {
+ if (command == 0)
+ drive_on = 0;
+ } else {
+ switch(command) {
+ case 1:
+ if (config.on_duty_cycle > 0)
+ config.on_duty_cycle -= 1;
+ save_config();
+ drive_on = 1;
+ break;
+ case 2:
+ if (config.on_duty_cycle < 10)
+ config.on_duty_cycle += 1;
+ save_config();
+ drive_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case LM_LEARN_OP_MODE:
+ switch(command) {
+ case 1:
+ config.op_mode = OM_MOMENTARY;
+ save_config();
+ learn_mode = LM_OFF;
+ break;
+ case 3:
+ config.op_mode = OM_DOUBLE;
+ save_config();
+ learn_mode = LM_OFF;
+ break;
+ case 5:
+ config.op_mode = OM_TOGGLE;
+ save_config();
+ learn_mode = LM_OFF;
+ break;
+ default:
+ break;
+ }
+ break;
+
}
}
-
/******************************************************************************
*
* main() - The main routine
*/
int main(void) {
- uint8_t duty = 30;
- uint8_t old_drive = 0;
+ uint8_t learn_mode_off;
+ uint8_t drive_last = 0;
+ uint8_t drive_slope = 0;
+ uint8_t i;
+
setup_hw();
- our_decoder = eeprom_read_byte(&ee_our_decoder);
- our_key = eeprom_read_byte(&ee_our_key);
- if (our_decoder == 0xff)
- learn_mode = 1;
+ load_config();
+
+ if (config.op_mode == OM_ERASED || config.magic != EE_MAGIC) {
+ config.magic = EE_MAGIC;
+ config.op_mode = OM_MOMENTARY;
+ // config.decoder_on = 1;
+ // config.key_on = 1;
+ config.decoder_off = 1;
+ config.key_off = 2;
+ config.initial_pulse = 10;
+ config.on_duty_cycle = 5;
+ learn_mode = LM_LEARN_ON_KEY;
+ }
sei();
- uint8_t i;
+
while (1) {
- if (!learn_mode) {
- if (old_drive == 0 && drive_on) {
- setpin(DRIVE, 1);
- _delay_ms(100);
+
+ drive_start:
+
+ cli();
+ if (!drive_last && drive_on)
+ drive_slope = 1;
+ else
+ drive_slope = 0;
+ drive_last = drive_on;
+ sei();
+ if (drive_on) {
+ if (drive_slope) {
+ for (i = 0; i < config.initial_pulse; i++) {
+ setpin(PIN_DRIVE, 1);
+ _delay_ms(10);
+ }
}
- old_drive = drive_on;
- setpin(DRIVE, drive_on);
- for (i = 0; i < duty; i++)
- _delay_us(4);
- for (i = 0; i < (255 - duty); i++) {
- setpin(DRIVE, 0);
- _delay_us(4);
+
+ for (i = 0; i < config.on_duty_cycle; i++) {
+ setpin(PIN_DRIVE, drive_on);
+ _delay_us(2);
}
- if (!PINVAL(BTN))
- learn_mode = 1;
+ for (i = 0; i < (10 - config.on_duty_cycle); i++) {
+ setpin(PIN_DRIVE, 0);
+ _delay_us(2);
+ }
+
} else {
- setpin(LED, 1);
- _delay_ms(30);
- setpin(LED, 0);
- _delay_ms(600);
- }
+ if (!learn_mode)
+ continue;
-/* Main loop here */
+ learn_mode_off = !learn_mode;
+
+ //if (drive_on || (learn_mode && learn_mode_off))
+ // goto drive_start;
+
+ for (i = 0; i < learn_mode; i++) {
+ setpin(PIN_LED, 1);
+ _delay_ms(30);
+ setpin(PIN_LED, 0);
+ _delay_ms(280);
+
+ //if (drive_on || (learn_mode && learn_mode_off))
+ // goto drive_start;
+ //if (drive_on || (learn_mode && learn_mode_off))
+ // goto drive_start;
+ }
+ for (i = 0; i < 15 - learn_mode; i++) {
+ //if (drive_on || (learn_mode && learn_mode_off))
+ // goto drive_start;
+ setpin(PIN_LED, 0);
+ _delay_ms(80);
+ //if (drive_on || (learn_mode && learn_mode_off))
+ // goto drive_start;
+ // _delay_ms(40);
+ }
+ }
}
return 0;
}
+
/******************************************************************************
* The end :-)
*/
--- /dev/null
+/******************************************************************************
+ *
+ * Trennfix firmware - mm_switch.c
+ *
+ * Maerklin Motorola switch command receiver
+ *
+ * Copyright (C) 2017 Philipp Hachtmann
+ *
+ * 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 3 of the License, or
+ * (at your option) 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <avr/io.h>
+#include <avr/eeprom.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+
+#include <util/delay.h>
+#include <stdint.h>
+
+#include "hardware.h"
+#include "mm_switch.h"
+
+ #define DEBUG_TIMEOUT
+#ifdef DEBUG_TIMEOUT
+#define MON(val) setpin(PIN_DRIVE, val)
+#else
+#define MON(xx) ({0;})
+#endif
+
+
+/*
+ * Lookup decoder number.
+ *
+ */
+static uint8_t lookup_decoder(uint8_t mm_byte)
+{
+ switch(mm_byte) {
+ /* 0x00 is invalid */
+ case 0xc0: return 1;
+ case 0x80: return 2;
+ case 0x30: return 3;
+ case 0xf0: return 4;
+ case 0xb0: return 5;
+ case 0x20: return 6;
+ case 0xe0: return 7;
+ case 0xa0: return 8;
+
+ case 0x0c: return 9;
+ case 0xcc: return 10;
+ case 0x8c: return 11;
+ case 0x3c: return 12;
+ case 0xfc: return 13;
+ case 0xbc: return 14;
+ case 0x2c: return 15;
+ case 0xec: return 16;
+ case 0xac: return 17;
+
+ case 0x08: return 18;
+ case 0xc8: return 19;
+ case 0x88: return 20;
+ case 0x38: return 21;
+ case 0xf8: return 22;
+ case 0xb8: return 23;
+ case 0x28: return 24;
+ case 0xe8: return 25;
+
+ default:
+ return 0;
+ }
+}
+
+static uint8_t lookup_command(uint8_t mm_byte)
+{
+ switch(mm_byte) {
+ case 0xc3: return 1;
+ case 0x03: return 2;
+ case 0xf3: return 3;
+ case 0x33: return 4;
+ case 0xcf: return 5;
+ case 0x0f: return 6;
+ case 0xff: return 7;
+ case 0x3f: return 8;
+ default:
+ return 0;
+ }
+}
+
+static void mm_switch_init(void)
+{
+ /* Get rid of the 1/8 clock prescaler */
+ CLKPR = (1 << CLKPCE);
+ CLKPR = 0;
+
+ GIMSK |= _BV(PCIE); /* Enable pin change interrupt */
+ PCMSK = _BV(PCINT4); /* PB4, Rail sense input */
+
+ TCCR0A = 0; /* This is normal mode */
+ TCCR0B = 0; /* Timer off */
+ TIMSK |= _BV(OCIE0A); /* Get a match interrupt */
+ TIMSK |= _BV(TOV0); /* Overflow interrupt */
+
+ /* We need 13 + 45 us delay, That's 464 clocks @8MHz*/
+ OCR0A = 91; /* Prescaler 8 is used */
+
+ /* Timer 1 for timeout */
+ /* We set it to 1024us by prescaler 64 and running full 256 */
+ TCCR1 = 7;
+ TIMSK |= _BV(TOIE1); /* Overflow interrupt */
+}
+
+
+static volatile uint8_t shift_sub;
+static volatile uint8_t shift_zero;
+static volatile uint8_t shift_decoder;
+static volatile uint8_t shift_sub_first;
+static volatile uint8_t shift_decoder_first;
+
+/* We will shift from right to left.
+ * XXXXXXXX XX XXXXXXXX
+ * shift_decoder shift_zero shift_sub
+ *
+ * The bits 7 downto 2 of shift_zero are ignored.
+ */
+
+volatile uint8_t bitno = 0;
+
+static void trigger(void)
+{
+ setpin(PIN_DRIVE, 1);
+ _delay_us(10);
+ setpin(PIN_DRIVE, 0);
+}
+
+enum recstate {
+ IDLE = 0,
+ FIRST_FAST_SAMPLE,
+ FIRST_SLOW_SAMPLE, /* If clock arrives, we stay on the fast path! */
+ FAST_SAMPLE,
+ FAST_WAIT_FOR_CLOCK,
+ SLOW_SAMPLE,
+ SLOW_WAIT_FOR_CLOCK,
+};
+
+static enum recstate recstate = IDLE;
+
+static inline void shift(uint8_t value)
+{
+ shift_decoder <<= 1;
+ if (shift_zero & 2)
+ shift_decoder |= 1;
+ shift_zero <<= 1;
+ if (shift_sub & 0x80)
+ shift_zero |= 1;
+ shift_sub <<= 1;
+ if (value)
+ shift_sub |= 1;
+}
+
+
+ISR(TIMER0_COMPA_vect) {
+
+ static uint8_t patience = 0;
+
+ switch(recstate) {
+ case FIRST_FAST_SAMPLE:
+ recstate = FIRST_SLOW_SAMPLE;
+ TSTART_CLK_TO_SAMPLE_FAST; /* Will not run out in fast! */
+ break;
+
+ case FIRST_SLOW_SAMPLE:
+ bitno = 0;
+
+ case SLOW_SAMPLE:
+ recstate = SLOW_WAIT_FOR_CLOCK;
+ TSTART_CLK_TO_SAMPLE_SLOW;
+ break;
+
+ case FAST_SAMPLE:
+ recstate = FAST_WAIT_FOR_CLOCK;
+ TSTART_CLK_TO_SAMPLE_FAST;
+ break;
+
+ case FAST_WAIT_FOR_CLOCK: /* A timeout! */
+ if (patience) {
+ patience--;
+ TSTART_CLK_TO_SAMPLE_FAST;
+ return;
+ }
+ recstate = IDLE;
+ TSTOP;
+ return;
+
+ case SLOW_WAIT_FOR_CLOCK:
+ if (patience) {
+ patience--;
+ TSTART_CLK_TO_SAMPLE_SLOW;
+ return;
+ }
+ TSTOP;
+ recstate = IDLE;
+ return;
+ }
+
+ shift(MM_SENSE);
+ bitno++;
+
+ if (bitno == 18) { /* Save first received word */
+ shift_sub_first = shift_sub;
+ shift_decoder_first = shift_decoder;
+ patience = 18;
+
+ }
+ if (bitno == 36) {
+ if ((shift_sub == shift_sub_first) &&
+ (shift_decoder == shift_decoder_first)) {
+ uint8_t decoder = lookup_decoder(shift_decoder);
+ uint8_t command = lookup_command(shift_sub);
+ if (recstate == SLOW_WAIT_FOR_CLOCK)
+ trigger();
+ if (decoder) {
+ /* Congratulations, we have a valid command */
+ if (recstate == FAST_WAIT_FOR_CLOCK) {
+ // trigger();
+ mm_switch_command(decoder, command);
+ }
+ }
+ }
+ }
+}
+
+ISR(BADISR_vect)
+{
+ while(1) {
+ /*
+ setpin(PIN_LED, 1);
+ _delay_ms(30);
+ setpin(PIN_LED, 0);
+ _delay_ms(30);
+ setpin(PIN_LED, 1);
+ _delay_ms(30);
+ setpin(PIN_LED, 0);
+ _delay_ms(2000);
+ */
+ }
+}
+
+ISR(TIM0_OVF_vect)
+{
+ return;
+ while(1) {
+ setpin(PIN_LED, 1);
+ _delay_ms(30);
+ setpin(PIN_LED, 0);
+ _delay_ms(300);
+ }
+
+}
+
+
+/* Pin change interrupt vector */
+void mm_pinchange_handler(void)
+{
+ static uint8_t sense_last;
+
+ if (MM_SENSE == sense_last)
+ return;
+ sense_last = MM_SENSE;
+ if (!sense_last)
+ return;
+
+ switch(recstate) {
+ case IDLE:
+ bitno = 0;
+ recstate = FIRST_FAST_SAMPLE;
+ TSTART_CLK_TO_SAMPLE_FAST;
+ break;
+ case FIRST_SLOW_SAMPLE:
+ recstate = FAST_SAMPLE;
+ TSTART_CLK_TO_SAMPLE_FAST;
+ break;
+ case FAST_WAIT_FOR_CLOCK:
+ recstate = FAST_SAMPLE;
+ TSTART_CLK_TO_SAMPLE_FAST;
+ break;
+ case SLOW_WAIT_FOR_CLOCK:
+ recstate = SLOW_SAMPLE;
+ TSTART_CLK_TO_SAMPLE_SLOW;
+ break;
+
+ /* Not expected */
+ case FIRST_FAST_SAMPLE:
+ case FAST_SAMPLE:
+ case SLOW_SAMPLE:
+ default:
+ break;
+ }
+}
+
+/******************************************************************************
+ * The end :-)
+ */
+
+
+