trennfix/sw: Single timer version
authorPhilipp Hachtmann <hachti@hachti.de>
Mon, 6 Feb 2017 00:37:59 +0000 (01:37 +0100)
committerPhilipp Hachtmann <hachti@hachti.de>
Sun, 12 Feb 2017 17:03:58 +0000 (18:03 +0100)
Single timer version. For debugging only.

Signed-off-by: Philipp Hachtmann <hachti@hachti.de>
trennfix/sw/config.make
trennfix/sw/hardware.h [new file with mode: 0644]
trennfix/sw/main.c
trennfix/sw/mm_lookup.h [deleted file]
trennfix/sw/mm_switch.c [new file with mode: 0644]
trennfix/sw/mm_switch.h [new file with mode: 0644]
trennfix/sw/pin_magic.h

index 303a371ea5bc657e9a207bac9c8352ae72fc51e3..17f249d2f1ec074e8f3487f65107f43058fea7a7 100644 (file)
@@ -1,5 +1,5 @@
 
-SRC = main.c
+SRC = main.c mm_switch.c
 
 ################################################################################
 ################################################################################
diff --git a/trennfix/sw/hardware.h b/trennfix/sw/hardware.h
new file mode 100644 (file)
index 0000000..edcd7ff
--- /dev/null
@@ -0,0 +1,68 @@
+#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
index d2111f786f99b4b9e18bdec5ee0266f27aed7dc0..4ae273a383ca19faac52497c85f4d63eb290d5cc 100644 (file)
 #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
@@ -237,44 +260,91 @@ ISR(PCINT0_vect)
  */
 
 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 :-)
  */
diff --git a/trennfix/sw/mm_lookup.h b/trennfix/sw/mm_lookup.h
deleted file mode 100644 (file)
index be68dfb..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __MM_LOOKUP_H
-#define __MM_LOOKUP_H
-
-/*
- * 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;
-        }
-}
-
-
-#endif
diff --git a/trennfix/sw/mm_switch.c b/trennfix/sw/mm_switch.c
new file mode 100644 (file)
index 0000000..74939bf
--- /dev/null
@@ -0,0 +1,320 @@
+/******************************************************************************
+ *
+ *  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 :-)
+ */
+
+
+
diff --git a/trennfix/sw/mm_switch.h b/trennfix/sw/mm_switch.h
new file mode 100644 (file)
index 0000000..c307766
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef MM_SWITCH_H
+#define MM_SWITCH_H
+
+#include <stdint.h>
+
+/*
+ * mm_switch_command - Callback function!
+ *
+ * This function must be defined whenever the mm_switch module is used.
+ * It will be called from interrupt context whenever a new valid command
+ * has arrived.
+ *
+ * decoder is in the range from 1 to 25. Other values will not occur.
+ * 
+ * key is in the range from 0 to 8:
+ *
+ *   1 - key1 green pressed
+ *   2 - key1 red pressed
+ *   3 - key2 green pressed
+ *   4 - key2 red pressed
+ *   ...
+ *   0 - all keys up
+ * 
+ */
+void mm_switch_command(uint8_t decoder, uint8_t key);
+
+void mm_pinchange_handler(void);
+
+void mm_init(void);
+
+
+
+
+
+#endif
index f335e14a7f9feb3b09545bad6ea1f18883f09066..a6d0b4bb29a8e54c7ebb262ea67995629c53f6c6 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __HACHTIS_PIN_MAGIC_H
 #define __HACHTIS_PIN_MAGIC_H
 
+#include <avr/io.h>
+
 struct __ph_pin__ {
        volatile uint8_t *addr;
        uint8_t bitno;
@@ -8,8 +10,6 @@ struct __ph_pin__ {
 
 #define _PIN(port, bit) ((volatile struct __ph_pin__){&port, bit})
 
-#define LED _PIN(PORTB, PORTB2)
-
 #define OUTPUT_PIN(pin) (*(pin.addr - 1) |= _BV(pin.bitno))
 #define INPUT_PIN(pin)  (*(pin.addr - 1) &= ~_BV(pin.bitno))