trennfix/sw: More versatile file structure
authorPhilipp Hachtmann <hachti@hachti.de>
Thu, 9 Feb 2017 12:51:30 +0000 (13:51 +0100)
committerPhilipp Hachtmann <hachti@hachti.de>
Sun, 12 Feb 2017 17:04:25 +0000 (18:04 +0100)
A working state commit. Sources have been reordered.

Signed-off-by: Philipp Hachtmann <hachti@hachti.de>
15 files changed:
trennfix/sw/Makefile
trennfix/sw/README [new file with mode: 0644]
trennfix/sw/config.make [deleted file]
trennfix/sw/config/hardware.h [new file with mode: 0644]
trennfix/sw/config/trennfix_attiny25.h [new file with mode: 0644]
trennfix/sw/config/trennfix_attiny25.mk [new file with mode: 0644]
trennfix/sw/config/trennfix_attiny85.h [new file with mode: 0644]
trennfix/sw/config/trennfix_attiny85.mk [new file with mode: 0644]
trennfix/sw/hardware.h [deleted file]
trennfix/sw/main.c [deleted file]
trennfix/sw/mm/include/mm/mm_switch.h [new file with mode: 0644]
trennfix/sw/mm/src/mm_switch.c [new file with mode: 0644]
trennfix/sw/mm_switch.c [deleted file]
trennfix/sw/mm_switch.h [deleted file]
trennfix/sw/src/main.c [new file with mode: 0644]

index 66135de0fa7880ebd03a2503c00381d819f42fc2..5f3774f61d99464686ecaf70baacefff6be1be7a 100644 (file)
 # To rebuild project do "make clean" then "make all".
 #----------------------------------------------------------------------------
 
-HW?=default
+CONFIG?=trennfix_attiny25
 
-CONFIG ?= config.make
-include ${CONFIG}
+include config/${CONFIG}.mk
 
-#test:
-#      echo ${BOOT_PAGES}
+INCLUDES+=-I mm/include -I include
+SRC+= mm/src/mm_switch.c
+CFLAGS+=-D__HW_CONF_HEADER__="<config/${CONFIG}.h>"
 
 # MCU name
 #MCU ?= atmega328
@@ -51,22 +51,14 @@ FORMAT = ihex
 
 
 # Target file name (without extension).
-TARGET = weiche1
+TARGET = trennfix
 
 # List C source files here. (C dependencies are automatically generated.)
 #SRC ?= main.c
 
 
-# List Assembler source files here.
-#     Make them always end in a capital .S.  Files ending in a lowercase .s
-#     will not be considered source files but generated files (assembler
-#     output from the compiler), and will be deleted upon "make clean"!
-#     Even though the DOS/Win* filesystem matches both .s and .S the same,
-#     it will preserve the spelling of the filenames, and gcc itself does
-#     care about how the name is spelled on its command-line.
 ASRC =
 
-
 # Optimization level, can be [0, 1, 2, 3, s].
 #     0 = turn off optimization. s = optimize for size.
 #     (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
@@ -120,6 +112,7 @@ CFLAGS += -Wall -Wstrict-prototypes
 CFLAGS += -Wa,-adhlns=$(<:.c=.lst)
 CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
 CFLAGS += $(CSTANDARD)
+CFLAGS += $(INCLUDES)
 
 
 #---------------- Assembler Options ----------------
diff --git a/trennfix/sw/README b/trennfix/sw/README
new file mode 100644 (file)
index 0000000..5bda705
--- /dev/null
@@ -0,0 +1 @@
+This is trennfix.
\ No newline at end of file
diff --git a/trennfix/sw/config.make b/trennfix/sw/config.make
deleted file mode 100644 (file)
index 17f249d..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-
-SRC = main.c mm_switch.c
-
-################################################################################
-################################################################################
-
-AVRDUDE_PROGRAMMER = avrisp2
-MCU=attiny25
-F_CPU = 16000000
-
-# Fuse-Bits gibts praktisch bei http://www.engbedded.com/fusecalc !
-# 8 MHz interner RC-Oszillator usw. Brown out 4V
-LFUSE=0x61
-HFUSE=0xdc
-EFUSE=0xff
-
-
-
-
-
-
-
-
-
diff --git a/trennfix/sw/config/hardware.h b/trennfix/sw/config/hardware.h
new file mode 100644 (file)
index 0000000..4f07b0b
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef   __HARDWARE_H_GENERIC__
+#define __HARDWARE_H_GENERIC__
+
+
+#include __HW_CONF_HEADER__
+
+
+
+
+#endif
diff --git a/trennfix/sw/config/trennfix_attiny25.h b/trennfix/sw/config/trennfix_attiny25.h
new file mode 100644 (file)
index 0000000..a995437
--- /dev/null
@@ -0,0 +1,86 @@
+#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 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;})
+
+
+/*
+ * Various sinks for valuable program memory
+ *
+ */
+// #define USE_EEPROM_UPDATE /* 14 bytes */
+//#define INTERPRET_DRIVE_COMMANDS
+#define INTERPRET_DRIVE_SIMPLE
+
+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 */
+}
+
+/*
+ * Function to trigger an oscilloscope on the drive pin
+ *
+ * Can be altered to use the LED.
+ *
+ */
+static void __attribute__((unused)) trigger(void)
+{
+       setpin(PIN_DRIVE, 1);
+       _delay_us(4);
+       setpin(PIN_DRIVE, 0);
+       _delay_us(4);
+}
+
+/*
+ * Configuration for mm receiver code.
+ */
+
+#define MM_SENSE (!PINVAL(PIN_SENSE))
+#define MM_TSTART_FAST ({TCNT0 = 0; GTCCR |= 1; OCR0A = 110; TCCR0B = 2;})
+#define MM_TSTART_SLOW ({TCNT0 = 0; GTCCR |= 1; OCR0A = 220; TCCR0B = 2;})
+#define MM_TSTOP ({TCCR0B = 0;})
+#define MM_TIMER_INT_VECT TIMER0_COMPA_vect
+
+/* Costs 63 bytes program memory */
+#define MM_FILTER_REPEATED
+
+#define USE_EEPROM_UPDATE
+#endif
diff --git a/trennfix/sw/config/trennfix_attiny25.mk b/trennfix/sw/config/trennfix_attiny25.mk
new file mode 100644 (file)
index 0000000..466277b
--- /dev/null
@@ -0,0 +1,29 @@
+
+SRC = src/main.c
+
+################################################################################
+################################################################################
+
+AVRDUDE_PROGRAMMER = avrisp2
+MCU=attiny25
+F_CPU = 16000000
+
+# Fuse-Bits gibts praktisch bei http://www.engbedded.com/fusecalc !
+# 8 MHz interner RC-Oszillator usw. Brown out 4V
+
+LFUSE=0x61
+#HFUSE=0xdc
+HFUSE=0xd4
+EFUSE=0xff
+
+CFLAGS+=-DONLY_2K
+
+
+
+
+
+
+
+
+
+
diff --git a/trennfix/sw/config/trennfix_attiny85.h b/trennfix/sw/config/trennfix_attiny85.h
new file mode 100644 (file)
index 0000000..39c1592
--- /dev/null
@@ -0,0 +1,85 @@
+#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 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;})
+
+
+/*
+ * Various sinks for valuable program memory
+ *
+ */
+// #define USE_EEPROM_UPDATE /* 14 bytes */
+//#define INTERPRET_DRIVE_COMMANDS
+#define INTERPRET_DRIVE_SIMPLE
+
+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 */
+}
+
+/*
+ * Function to trigger an oscilloscope on the drive pin
+ *
+ * Can be altered to use the LED.
+ *
+ */
+static void __attribute__((unused)) trigger(void)
+{
+       setpin(PIN_DRIVE, 1);
+       _delay_us(4);
+       setpin(PIN_DRIVE, 0);
+       _delay_us(4);
+}
+
+/*
+ * Configuration for mm receiver code.
+ */
+
+#define MM_SENSE (!PINVAL(PIN_SENSE))
+#define MM_TSTART_FAST ({TCNT0 = 0; GTCCR |= 1; OCR0A = 110; TCCR0B = 2;})
+#define MM_TSTART_SLOW ({TCNT0 = 0; GTCCR |= 1; OCR0A = 220; TCCR0B = 2;})
+#define MM_TSTOP ({TCCR0B = 0;})
+#define MM_TIMER_INT_VECT TIMER0_COMPA_vect
+
+/* Costs 63 bytes program memory */
+#define MM_FILTER_REPEATED
+
+#endif
diff --git a/trennfix/sw/config/trennfix_attiny85.mk b/trennfix/sw/config/trennfix_attiny85.mk
new file mode 100644 (file)
index 0000000..896a008
--- /dev/null
@@ -0,0 +1,30 @@
+
+SRC = src/main.c
+
+################################################################################
+################################################################################
+
+AVRDUDE_PROGRAMMER = avrisp2
+MCU=attiny85
+F_CPU = 16000000
+
+# Fuse-Bits gibts praktisch bei http://www.engbedded.com/fusecalc !
+# 8 MHz interner RC-Oszillator usw. Brown out 4V
+
+# Tiny 25
+#LFUSE=0x61
+#HFUSE=0xdc
+#EFUSE=0xff
+
+LFUSE=0x61
+HFUSE=0xd4
+EFUSE=0xff
+
+
+
+
+
+
+
+
+
diff --git a/trennfix/sw/hardware.h b/trennfix/sw/hardware.h
deleted file mode 100644 (file)
index edcd7ff..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#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
diff --git a/trennfix/sw/main.c b/trennfix/sw/main.c
deleted file mode 100644 (file)
index 2437151..0000000
+++ /dev/null
@@ -1,429 +0,0 @@
-/******************************************************************************
- *
- *  Trennfix firmware - main.c
- *
- *  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 "mm_switch.h"
-#include "hardware.h"
-
-// #define DEBUG_TIMEOUT
-#ifdef DEBUG_TIMEOUT
-#define MON_TIMEOUT(val) setpin(DRIVE, val)
-#else
-#define MON_TIMEOUT(xx) ({0;})
-#endif
-
-#define EE_MAGIC 0xab
-
-static void trigger(void)
-{
-       setpin(PIN_DRIVE, 1);
-       _delay_us(10);
-       setpin(PIN_DRIVE, 0);
-}
-
-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_OFF;
-
-static void load_config(void)
-{
-       eeprom_read_block(&config, &ee_config, sizeof(config));
-}
-
-static void save_config(void)
-{
-       eeprom_update_block(&config, &ee_config, sizeof(config));
-}
-
-static volatile uint8_t drive_on = 0;
-
-ISR(PCINT0_vect){
-       static uint8_t btn_last = 0;
-
-       mm_pinchange_handler();
-
-       if (BTN_PRESSED && !btn_last) {
-               learn_mode++;
-               learn_mode %= LM_END;
-       }
-       btn_last = BTN_PRESSED;
-}
-
-static uint8_t get_speed(uint8_t command)
-{
-       uint8_t b1, b2, b3, b4, b5, b6, b7, b8;
-       b1 = ((command & 0x80) != 0);
-       b2 = ((command & 0x40) != 0);
-       b3 = ((command & 0x20) != 0);
-       b4 = ((command & 0x10) != 0);
-       b5 = ((command & 0x8) != 0);
-       b6 = ((command & 0x4) != 0);
-       b7 = ((command & 0x2) != 0);
-       b8 = ((command & 0x1) != 0);
-       
-       //if ((b1 != b2) || (b2 != b3) || (b3 != b4) || (b5 != b6) || (b7 != b8))
-       //      return 0xff;
-       
-       return (b1 + b3*2 + b5*4 +b7*8);
-}
-
-void mm_switch_drive(uint8_t decoder, uint8_t function, uint8_t command)
-{
-       static uint8_t seen_before = 0;
-       uint8_t speed;
-
-       
-       if (!seen_before) {
-               //              if (decoder == 100)
-               //      
-               
-               if ((decoder == 100) && (function == 0) && (command == 0xc0)) {
-                       config.magic = 0;
-                       save_config();
-               }
-       }
-       seen_before = 1;
-       speed = get_speed(command);
-       static uint8_t itsme = 0;
-       if (decoder == 10) {
-               trigger();
-
-               if (speed == 1) {
-                       itsme = 1;
-                       drive_on = 1;
-               }else {
-                       if (itsme) {
-                               drive_on = 0;
-                               itsme = 0;
-                       }
-               }
-       }
-       if (decoder == 33) {
-               //              trigger();
-
-               speed = get_speed(command);
-               if (speed != 0xff) {
-                       if (speed >= 1) speed -= 1;
-                       if (speed <= 14)
-                               config.on_duty_cycle = speed;
-                       else
-                               config.on_duty_cycle = 14;
-               }
-       }
-}
-
-void mm_switch_command(uint8_t decoder, uint8_t command)
-{
-       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;
-                       }
-               }
-
-               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;
-                       }
-               }
-
-               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;
-
-#ifdef LEARN_THE_STUFF
-       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;
-
-       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;
-#endif         
-       }
-}
-
-
-/******************************************************************************
- *
- * main() - The main routine
- *
- */
-
-int main(void) {
-       // uint8_t learn_mode_off;
-       uint8_t drive_last = 0;
-       uint8_t drive_slope = 0;
-       uint8_t i;
-
-       load_config();
-       setup_hw();
-
-       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();
-       
-       while (1) {
-               
-               //      drive_start:
-               
-               cli();
-               if (!drive_last && drive_on)
-                       drive_slope = 1;
-               else
-                       drive_slope = 0;
-               drive_last = drive_on;
-               sei();
-
-               if (drive_on) {
-#ifdef ROOM_FOR_KICK
-                       if (drive_slope) {
-                               for (i = 0; i < config.initial_pulse; i++) {
-                                       setpin(PIN_DRIVE, 1);   
-                                       _delay_ms(10);
-                               }
-                       }
-#endif                 
-
-#define ROOM_FOR_PWM
-#ifdef ROOM_FOR_PWM
-                       for (i = 0; i < config.on_duty_cycle; i++) {
-                               setpin(PIN_DRIVE, drive_on);
-                               _delay_us(1);
-                       }
-                       for (i = 0; i < (14 - config.on_duty_cycle); i++) {
-                               setpin(PIN_DRIVE, 0);
-                               _delay_us(1);
-                       }
-
-#else
-                       setpin(PIN_DRIVE, 1);
-#endif                 
-
-               } else {
-                       setpin(PIN_DRIVE, 0);
-                       if (!learn_mode)
-                               continue;
-
-                       //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/include/mm/mm_switch.h b/trennfix/sw/mm/include/mm/mm_switch.h
new file mode 100644 (file)
index 0000000..fb36036
--- /dev/null
@@ -0,0 +1,38 @@
+#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);
+
+/*
+ *  empty comment :-)
+ */
+void mm_switch_drive_cb(uint8_t address, uint8_t speed, uint8_t functions, uint8_t flags);
+
+void mm_switch_drive(uint8_t decoder, uint8_t function, uint8_t command);
+
+void mm_pinchange_handler(void);
+
+void mm_init(void);
+
+#endif
diff --git a/trennfix/sw/mm/src/mm_switch.c b/trennfix/sw/mm/src/mm_switch.c
new file mode 100644 (file)
index 0000000..2b09e5c
--- /dev/null
@@ -0,0 +1,324 @@
+/******************************************************************************
+ *
+ *  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 <config/hardware.h>
+#include <mm/mm_switch.h>
+
+/*
+ *    Private data types
+ */
+
+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,
+};
+
+/*
+ *
+ * Check for stuff we need
+ *
+ */
+#if !defined(MM_TSTART_FAST) || !defined(MM_TSTART_SLOW) || !defined(MM_TSTOP) \
+       || !defined(MM_SENSE) || !defined(MM_TIMER_INT_VECT)
+
+#error Missing timer start macro MM_TSTART_FAST!
+
+#endif
+
+/*
+ *    Private global variables
+ */
+static volatile uint8_t shift_command;
+static volatile uint8_t shift_function;
+static volatile uint8_t shift_address;
+static enum recstate recstate = IDLE;
+volatile uint8_t bitno = 0;
+
+
+/*
+ * Lookup trinary nibble
+ *
+ * This was implemented using a switch statement before.
+ * Changing the lookup to a table did only add two bytes
+ * of memory and saved ca. 50 bytes program memory.
+ */
+static const uint8_t nibble_table[16]={
+       [0x0] = 0,
+       [0xc] = 1,
+       [0x8] = 2,
+       [0x3] = 3,
+       [0xf] = 4,
+       [0xb] = 5,
+       [0x2] = 6,
+       [0xe] = 7,
+       [0xa] = 8
+};
+#define lookup_nibble(nibble) nibble_table[nibble & 0xf]
+static uint8_t lookup_decoder(uint8_t mm_byte)
+{
+       uint8_t low;
+       uint8_t high;
+       if (mm_byte == 0)
+               return 80;
+       low = lookup_nibble(mm_byte >> 4);
+       high = lookup_nibble(mm_byte & 0xf);
+       if (!low)
+               return 0;
+       return 9 * high + low;
+}
+
+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;
+        }
+}
+
+/* We will shift from right to left.
+ * XXXXXXXX        XX          XXXXXXXX
+ * shift_address   shift_function  shift_command
+ *
+ * The bits 7 downto 2 of shift_function are ignored.
+ */
+
+static inline void shift(uint8_t value)
+{
+       shift_address <<= 1;
+       if (shift_function & 2)
+               shift_address |= 1;
+       shift_function <<= 1;
+       if (shift_command & 0x80)
+               shift_function |= 1;
+       shift_command <<= 1;
+       if (value)
+               shift_command |= 1;
+}
+
+ISR(MM_TIMER_INT_VECT) {
+       static uint8_t tolerated_timeouts = 0;
+
+       static volatile uint8_t shift_command_first;
+       static volatile uint8_t shift_function_first;
+       static volatile uint8_t shift_address_first;
+       uint8_t address;
+       uint8_t command;
+
+#ifdef MM_FILTER_REPEATED
+       static uint8_t address_last = 0xff;
+       static uint8_t function_last = 0xff;
+       static uint8_t command_last = 0xff;
+#endif
+
+       switch(recstate) {
+       case FIRST_FAST_SAMPLE:
+               recstate = FIRST_SLOW_SAMPLE;
+               MM_TSTART_FAST; /* Will not run out in fast! */
+               break;
+
+       case FIRST_SLOW_SAMPLE:
+               bitno = 0;
+
+       case SLOW_SAMPLE:
+               recstate = SLOW_WAIT_FOR_CLOCK;
+               MM_TSTART_SLOW;
+               break;
+       
+       case FAST_SAMPLE:
+               recstate = FAST_WAIT_FOR_CLOCK;
+               MM_TSTART_FAST;
+               break;
+
+       case FAST_WAIT_FOR_CLOCK: /* A timeout! */
+               if (tolerated_timeouts) {
+                       tolerated_timeouts--;
+                       MM_TSTART_FAST;
+                       return;
+               }
+               recstate = IDLE;
+               MM_TSTOP;
+               return;
+
+       case SLOW_WAIT_FOR_CLOCK:
+               if (tolerated_timeouts) {
+                       tolerated_timeouts--;
+                       MM_TSTART_SLOW;
+                       return;
+               }
+       default:
+               MM_TSTOP;
+               recstate = IDLE;
+               return;
+       }
+       
+       shift(MM_SENSE);
+       bitno++;
+
+       if (bitno == 18) { /* Save first received word */
+               shift_address_first  = shift_address;
+               shift_function_first = shift_function;
+               shift_command_first  = shift_command;
+
+               tolerated_timeouts = 18;
+       } 
+
+       if (bitno == 36) {
+               if ((shift_command == shift_command_first) &&
+                   (shift_address == shift_address_first) &&
+                   (shift_function == shift_function_first)) {
+
+#ifdef MM_FILTER_REPEATED
+                       if ((shift_address != address_last) || (shift_command != command_last) ||
+                           shift_function != function_last) {
+#endif
+                               address = lookup_decoder(shift_address);
+                               
+                               if (recstate == SLOW_WAIT_FOR_CLOCK) {
+                                       mm_switch_drive(address, shift_function, shift_command);
+                               } else if (recstate == FAST_WAIT_FOR_CLOCK) {
+                                       command = lookup_command(shift_command);
+                                       mm_switch_command(address, command);
+                               }
+#ifdef MM_FILTER_REPEATED
+                       }
+                       address_last   = shift_address;
+                       function_last  = shift_function;
+                       command_last   = shift_command;
+#endif
+               }
+               
+       }
+}
+
+//void __attribute((weak)) mm_switch_drive(uint8_t address, uint8_t function, uint8_t 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;
+               MM_TSTART_FAST;
+               break;
+       case FIRST_SLOW_SAMPLE:
+               recstate = FAST_SAMPLE;
+               MM_TSTART_FAST;
+               break;
+       case FAST_WAIT_FOR_CLOCK:
+               recstate = FAST_SAMPLE;
+               MM_TSTART_FAST;
+               break;
+       case SLOW_WAIT_FOR_CLOCK:
+               recstate = SLOW_SAMPLE;
+               MM_TSTART_SLOW;
+               break;
+
+               /* Not expected */
+       case FIRST_FAST_SAMPLE:
+       case FAST_SAMPLE:
+       case SLOW_SAMPLE:
+       default:
+               break;
+       }
+}
+
+void __attribute__((weak))mm_switch_drive(uint8_t decoder, uint8_t function,
+                                         uint8_t command)
+{
+       while(1);
+}
+
+void __attribute__((weak))mm_switch_command(uint8_t address, uint8_t command)
+{
+}
+
+
+/******************************************************************************
+ *                        The end :-)
+ */
+
+
+
diff --git a/trennfix/sw/mm_switch.c b/trennfix/sw/mm_switch.c
deleted file mode 100644 (file)
index cb7b4f7..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-/******************************************************************************
- *
- *  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_nibble(uint8_t mm_nibble)
-{
-       switch(mm_nibble) {
-       case 0x0: return 0;
-       case 0xc: return 1;
-       case 0x8: return 2;
-       case 0x3: return 3;
-       case 0xf: return 4;
-       case 0xb: return 5;
-       case 0x2: return 6;
-       case 0xe: return 7;
-       case 0xa: return 8;
-       default: return 0;
-       }
-       return 0;
-}
-
-static uint8_t lookup_decoder(uint8_t mm_byte)
-{
-       uint8_t low;
-       uint8_t high;
-       if (mm_byte == 0)
-               return 100;
-       low = lookup_nibble(mm_byte >> 4);
-       high = lookup_nibble(mm_byte & 0xf);
-       if (!low)
-               return 0;
-       return 9 * high + low;
-}
-
-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 __attribute__((unused)) 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_command;
-static volatile uint8_t shift_function;
-static volatile uint8_t shift_address;
-static volatile uint8_t shift_command_first;
-static volatile uint8_t shift_address_first;
-
-/* We will shift from right to left.
- * XXXXXXXX        XX          XXXXXXXX
- * shift_address   shift_function  shift_command
- *
- * The bits 7 downto 2 of shift_function are ignored.
- */
-
-volatile uint8_t bitno = 0;
-
-static void __attribute__((unused)) trigger(void)
-{
-       setpin(PIN_DRIVE, 1);
-       _delay_us(4);
-       setpin(PIN_DRIVE, 0);
-       _delay_us(4);
-}
-
-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_address <<= 1;
-       if (shift_function & 2)
-               shift_address |= 1;
-       shift_function <<= 1;
-       if (shift_command & 0x80)
-               shift_function |= 1;
-       shift_command <<= 1;
-       if (value)
-               shift_command |= 1;
-}
-
-
-ISR(TIMER0_COMPA_vect) {
-       static uint8_t patience = 0;
-       static uint8_t address_last = 0xff;
-       static uint8_t function_last = 0xff;
-       static uint8_t command_last = 0xff;
-
-       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;
-               }
-       default:
-               TSTOP;
-               recstate = IDLE;
-               return;
-       }
-       
-       shift(MM_SENSE);
-       bitno++;
-
-       if (bitno == 18) { /* Save first received word */
-               shift_command_first = shift_command;
-               shift_address_first = shift_address;
-               patience = 18;
-
-       } 
-
-       if (bitno == 36) {
-               if ((shift_command == shift_command_first) &&
-                   (shift_address == shift_address_first)) {
-                       if ((shift_address != address_last) || (shift_command != command_last) ||
-                           shift_function != function_last) {
-
-                               uint8_t addr =  lookup_decoder(shift_address);
-                               
-                               if (recstate == SLOW_WAIT_FOR_CLOCK) {
-                                       mm_switch_drive(addr, shift_function, shift_command);
-                               }
-                       
-               
-                               if (recstate == FAST_WAIT_FOR_CLOCK && addr) {
-                                       uint8_t command = lookup_command(shift_command);
-                                       /* Congratulations, we have a valid command */
-                                       mm_switch_command(addr, command);
-                               }
-                       }
-                       address_last = shift_address;
-                       function_last = shift_function;
-                       command_last = shift_command;
-               }
-               
-       }
-}
-
-//void __attribute((weak)) mm_switch_drive(uint8_t address, uint8_t function, uint8_t 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
deleted file mode 100644 (file)
index 7791f07..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#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);
-
-/*
- *  empty comment :-)
- */
-void mm_switch_drive_cb(uint8_t address, uint8_t speed, uint8_t functions, uint8_t flags);
-
-void mm_switch_drive(uint8_t decoder, uint8_t function, uint8_t command);
-
-void mm_pinchange_handler(void);
-
-void mm_init(void);
-
-
-
-
-
-#endif
diff --git a/trennfix/sw/src/main.c b/trennfix/sw/src/main.c
new file mode 100644 (file)
index 0000000..7d5c10a
--- /dev/null
@@ -0,0 +1,469 @@
+/******************************************************************************
+ *
+ *  Trennfix firmware - main.c
+ *
+ *  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 <mm/mm_switch.h>
+#include <config/hardware.h>
+
+
+#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                  */
+        volatile enum learn_mode  learn_mode;
+};
+
+static struct EEMEM config ee_config;
+static volatile struct config config;
+static volatile uint8_t drive_on = 0;
+
+static void load_config(void)
+{
+       eeprom_read_block((uint8_t *)&config, &ee_config, sizeof(config));
+}
+
+static void save_config(void)
+{
+#ifdef USE_EEPROM_UPDATE
+       eeprom_update_block((uint8_t *)&config, &ee_config, sizeof(config));
+#else
+       eeprom_write_block((uint8_t *)&config, &ee_config, sizeof(config));
+#endif
+}
+
+
+
+ISR(PCINT0_vect){
+       static uint8_t btn_last = 0;
+
+       mm_pinchange_handler();
+
+       if (BTN_PRESSED && !btn_last) {
+               config.learn_mode++;
+               config.learn_mode %= LM_END;
+       }
+       btn_last = BTN_PRESSED;
+}
+
+static uint8_t get_speed(uint8_t command)
+{
+       uint8_t b1,  b3, b5, b7;
+               
+       b1 = ((command & 0x80) != 0);
+       //      b2 = ((command & 0x40) != 0);
+       b3 = ((command & 0x20) != 0);
+       //      b4 = ((command & 0x10) != 0);
+       b5 = ((command & 0x8) != 0);
+       //      b6 = ((command & 0x4) != 0);
+       b7 = ((command & 0x2) != 0);
+       //      b8 = ((command & 0x1) != 0);
+       
+       //if ((b1 != b2) || (b2 != b3) || (b3 != b4) || (b5 != b6) || (b7 != b8))
+       //      return 0xff;
+       
+       return (b1 + b3*2 + b5*4 +b7*8);
+}
+
+#ifdef INTERPRET_DRIVE_COMMANDS
+
+void mm_switch_drive(uint8_t decoder, uint8_t function, uint8_t command)
+{
+       static uint8_t seen_before = 0;
+       uint8_t speed;
+
+       if (!seen_before) {
+               if ((decoder == 80) && (function == 0) && (command == 0xc0)) {
+                       config.learn_mode = 1;
+                       save_config();
+               }
+       }
+       seen_before = 1;
+       
+       speed = get_speed(command);
+       static uint8_t itsme = 0;
+
+       if (config.learn_mode) {
+               if (decoder == 70) {
+                       if (speed == 1) {
+                               itsme = 1;
+                       drive_on = 1;
+                       }else {
+                               if (itsme) {
+                                       drive_on = 0;
+                                       itsme = 0;
+                               }
+                       }
+               }
+               
+               if (decoder == 33) {
+                       if (speed != 0xff) {
+                               if (speed >= 1) speed -= 1;
+                               if (speed <= 14)
+                                       config.on_duty_cycle = speed;
+                               else
+                                       config.on_duty_cycle = 14;
+                               
+                       }
+               }
+               
+               if (decoder == 32) {
+                       if (speed != 0xff) {
+                               config.initial_pulse = speed;
+                       }
+               }
+               
+               if (decoder == 31 && command == 0xc0)
+                       save_config();
+       }
+}
+
+#else
+#ifdef INTERPRET_DRIVE_SIMPLE
+
+static volatile uint8_t current_loco;
+
+void mm_switch_drive(uint8_t decoder, uint8_t function, uint8_t command)
+{
+       uint8_t speed;
+       speed = get_speed(command);
+       current_loco = decoder;
+       if (speed != 0xff) {
+               if (decoder == 50) {
+                       setpin(PIN_LED, drive_on = function & 3);
+                       config.initial_pulse = speed;
+               } else if (decoder == 51) {
+                       if (speed >= 1) speed -= 1;
+                       if (speed <= 14)
+                               config.on_duty_cycle = speed;
+                       else
+                               config.on_duty_cycle = 14;
+               } else if (decoder == 52) {
+                       static uint8_t last_speed;
+                       if (speed == 1 && last_speed != 1)
+                               save_config();
+                       last_speed = speed;
+                       
+               }
+       }
+}
+
+#endif
+#endif
+static volatile uint8_t switch_on = 0;
+
+void mm_switch_command(uint8_t decoder, uint8_t command)
+{
+       static uint8_t toggle_lock = 0;
+       switch(config.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:
+                               if (!switch_on && current_loco == 52)
+                                       save_config();
+                               switch_on = 1;
+                               break;
+                       case OM_TOGGLE:
+                               if (!toggle_lock) {
+                                       drive_on = !drive_on;
+                                       toggle_lock = 1;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               if ((decoder == config.decoder_on) &&
+                   (command == 0)) { /* Primary key released */
+                       switch(config.op_mode) {
+                       case OM_MOMENTARY:
+                               switch_on = 0;
+                               break;
+                       case OM_TOGGLE:
+                               toggle_lock = 0;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+#ifdef HANDLE_OFF_KEY
+
+               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;
+                       }
+               }
+#endif
+               break;
+               
+       case LM_LEARN_ON_KEY:
+               if (command) {
+                       config.decoder_on = decoder;
+                       config.key_on     = command;
+                       if (config.op_mode == OM_DOUBLE)
+                               config.learn_mode = LM_LEARN_OFF_KEY;
+                       else
+                               config.learn_mode = LM_OFF;
+                       save_config();
+               }
+               break;
+#ifdef LEARN_ADVANCED
+       case LM_LEARN_OFF_KEY:
+               if (command) {
+                       config.decoder_off = decoder;
+                       config.key_off     = command;
+                       config.learn_mode = LM_OFF;
+                       save_config();
+               }
+               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;
+
+       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();
+                       config.learn_mode = LM_OFF;
+                       break;
+               case 3:
+                       config.op_mode = OM_DOUBLE;
+                       save_config();
+                       config.learn_mode = LM_OFF;
+                       break;
+               case 5:
+                       config.op_mode = OM_TOGGLE;
+                       save_config();
+                       config.learn_mode = LM_OFF;
+                       break;
+               default:
+                       break;
+               }
+               break;
+#endif
+       }
+}
+
+
+/******************************************************************************
+ *
+ * main() - The main routine
+ *
+ */
+
+int main(void) {
+       uint8_t learn_mode_off;
+       uint8_t drive_last = 0;
+       uint8_t drive_slope = 0;
+       uint8_t i;
+       uint8_t output_on;
+
+       load_config();
+       setup_hw();
+       
+       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;
+               config.learn_mode = LM_LEARN_ON_KEY;
+       }
+       drive_on = 0;
+       sei();
+       setpin(PIN_DRIVE, 1);   
+       _delay_ms(50);
+       setpin(PIN_DRIVE, 0);   
+
+       //setpin(PIN_LED,1 );
+       //_delay_ms(400);
+       //setpin(PIN_LED,0 );
+       while (1) {
+               
+       drive_start:
+
+               output_on = drive_on || switch_on;
+               cli();
+               if (!drive_last && output_on)
+                       drive_slope = 1;
+               else
+                       drive_slope = 0;
+               drive_last = output_on;
+               sei();
+
+               if (output_on) {
+                       if (drive_slope) {
+                               for (i = 0; i < config.initial_pulse; i++) {
+                                       setpin(PIN_DRIVE, 1);   
+                                       _delay_ms(20);
+                               }
+                       }
+
+                       for (i = 0; i < config.on_duty_cycle; i++) {
+                               setpin(PIN_DRIVE, output_on);
+                               _delay_us(3);
+                       }
+                       for (i = 0; i < (28 - config.on_duty_cycle); i++) {
+                               setpin(PIN_DRIVE, 0);
+                               _delay_us(3);
+                       }
+
+               } else {
+                       setpin(PIN_DRIVE, 0);
+                       if (!config.learn_mode)
+                               continue;
+
+                       learn_mode_off = !config.learn_mode;
+                       
+                       if (output_on || (config.learn_mode && learn_mode_off))
+                               goto drive_start;
+
+                       for (i = 0; i < config.learn_mode; i++) {
+                               setpin(PIN_LED, 1);
+                               _delay_ms(10);
+                               //if (output_on || (config.learn_mode && learn_mode_off))
+                               //      goto drive_start;
+                               setpin(PIN_LED, 0);
+                               _delay_ms(135);
+                               //if (output_on || (config.learn_mode && learn_mode_off))
+                               //      goto drive_start;
+
+                               //if (output_on || (config.learn_mode && learn_mode_off))
+                               //      goto drive_start;
+                       }
+                       for (i = 0; i < 15 - config.learn_mode; i++) {
+                               //if (output_on || (config.learn_mode && learn_mode_off))
+                               //      goto drive_start;
+                               setpin(PIN_LED, 0);
+                               _delay_ms(70);
+                               //if (output_on || (config.learn_mode && learn_mode_off))
+                               //      goto drive_start;
+                               // _delay_ms(40);
+                       }
+               }
+       }
+       return 0;
+}
+
+
+/******************************************************************************
+ *                        The end :-)
+ */