From 93cb14d45dd54a188bef116c5884d6bd1e410677 Mon Sep 17 00:00:00 2001 From: Philipp Hachtmann Date: Thu, 9 Feb 2017 13:51:30 +0100 Subject: [PATCH] trennfix/sw: More versatile file structure A working state commit. Sources have been reordered. Signed-off-by: Philipp Hachtmann --- trennfix/sw/Makefile | 21 +- trennfix/sw/README | 1 + trennfix/sw/config/hardware.h | 10 + trennfix/sw/config/trennfix_attiny25.h | 86 +++++++ .../trennfix_attiny25.mk} | 9 +- .../trennfix_attiny85.h} | 47 ++-- trennfix/sw/config/trennfix_attiny85.mk | 30 +++ trennfix/sw/{ => mm/include/mm}/mm_switch.h | 4 - trennfix/sw/{ => mm/src}/mm_switch.c | 222 ++++++++--------- trennfix/sw/{ => src}/main.c | 234 ++++++++++-------- 10 files changed, 418 insertions(+), 246 deletions(-) create mode 100644 trennfix/sw/README create mode 100644 trennfix/sw/config/hardware.h create mode 100644 trennfix/sw/config/trennfix_attiny25.h rename trennfix/sw/{config.make => config/trennfix_attiny25.mk} (85%) rename trennfix/sw/{hardware.h => config/trennfix_attiny85.h} (63%) create mode 100644 trennfix/sw/config/trennfix_attiny85.mk rename trennfix/sw/{ => mm/include/mm}/mm_switch.h (99%) rename trennfix/sw/{ => mm/src}/mm_switch.c (65%) rename trennfix/sw/{ => src}/main.c (67%) diff --git a/trennfix/sw/Makefile b/trennfix/sw/Makefile index 66135de..5f3774f 100644 --- a/trennfix/sw/Makefile +++ b/trennfix/sw/Makefile @@ -27,13 +27,13 @@ # 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__="" # 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 index 0000000..5bda705 --- /dev/null +++ b/trennfix/sw/README @@ -0,0 +1 @@ +This is trennfix. \ No newline at end of file diff --git a/trennfix/sw/config/hardware.h b/trennfix/sw/config/hardware.h new file mode 100644 index 0000000..4f07b0b --- /dev/null +++ b/trennfix/sw/config/hardware.h @@ -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 index 0000000..a995437 --- /dev/null +++ b/trennfix/sw/config/trennfix_attiny25.h @@ -0,0 +1,86 @@ +#ifndef __HARDWARE_H +#define __HARDWARE_H + +#include + +#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.make b/trennfix/sw/config/trennfix_attiny25.mk similarity index 85% rename from trennfix/sw/config.make rename to trennfix/sw/config/trennfix_attiny25.mk index 17f249d..466277b 100644 --- a/trennfix/sw/config.make +++ b/trennfix/sw/config/trennfix_attiny25.mk @@ -1,5 +1,5 @@ -SRC = main.c mm_switch.c +SRC = src/main.c ################################################################################ ################################################################################ @@ -10,10 +10,15 @@ 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=0xdc +HFUSE=0xd4 EFUSE=0xff +CFLAGS+=-DONLY_2K + + diff --git a/trennfix/sw/hardware.h b/trennfix/sw/config/trennfix_attiny85.h similarity index 63% rename from trennfix/sw/hardware.h rename to trennfix/sw/config/trennfix_attiny85.h index edcd7ff..39c1592 100644 --- a/trennfix/sw/hardware.h +++ b/trennfix/sw/config/trennfix_attiny85.h @@ -1,15 +1,13 @@ #ifndef __HARDWARE_H #define __HARDWARE_H - -#include "pin_magic.h" +#include #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;}) @@ -17,6 +15,14 @@ #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*/ @@ -49,20 +55,31 @@ static inline void setup_hw(void) // 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;}) +/* + * 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); +} -#define TSTOP ({TCCR0B = 0;}) +/* + * 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 index 0000000..896a008 --- /dev/null +++ b/trennfix/sw/config/trennfix_attiny85.mk @@ -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/mm_switch.h b/trennfix/sw/mm/include/mm/mm_switch.h similarity index 99% rename from trennfix/sw/mm_switch.h rename to trennfix/sw/mm/include/mm/mm_switch.h index 7791f07..fb36036 100644 --- a/trennfix/sw/mm_switch.h +++ b/trennfix/sw/mm/include/mm/mm_switch.h @@ -35,8 +35,4 @@ void mm_pinchange_handler(void); void mm_init(void); - - - - #endif diff --git a/trennfix/sw/mm_switch.c b/trennfix/sw/mm/src/mm_switch.c similarity index 65% rename from trennfix/sw/mm_switch.c rename to trennfix/sw/mm/src/mm_switch.c index cb7b4f7..2b09e5c 100644 --- a/trennfix/sw/mm_switch.c +++ b/trennfix/sw/mm/src/mm_switch.c @@ -33,45 +33,71 @@ #include #include -#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 +#include +#include +/* + * 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, +}; /* - * Lookup decoder number. + * + * 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) -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; -} +#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 100; + return 80; low = lookup_nibble(mm_byte >> 4); high = lookup_nibble(mm_byte & 0xf); if (!low) @@ -95,36 +121,6 @@ static uint8_t lookup_command(uint8_t mm_byte) } } - -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 @@ -132,28 +128,6 @@ static volatile uint8_t shift_address_first; * 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; @@ -167,17 +141,25 @@ static inline void shift(uint8_t value) shift_command |= 1; } +ISR(MM_TIMER_INT_VECT) { + static uint8_t tolerated_timeouts = 0; -ISR(TIMER0_COMPA_vect) { - static uint8_t patience = 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; - TSTART_CLK_TO_SAMPLE_FAST; /* Will not run out in fast! */ + MM_TSTART_FAST; /* Will not run out in fast! */ break; case FIRST_SLOW_SAMPLE: @@ -185,32 +167,32 @@ ISR(TIMER0_COMPA_vect) { case SLOW_SAMPLE: recstate = SLOW_WAIT_FOR_CLOCK; - TSTART_CLK_TO_SAMPLE_SLOW; + MM_TSTART_SLOW; break; case FAST_SAMPLE: recstate = FAST_WAIT_FOR_CLOCK; - TSTART_CLK_TO_SAMPLE_FAST; + MM_TSTART_FAST; break; case FAST_WAIT_FOR_CLOCK: /* A timeout! */ - if (patience) { - patience--; - TSTART_CLK_TO_SAMPLE_FAST; + if (tolerated_timeouts) { + tolerated_timeouts--; + MM_TSTART_FAST; return; } recstate = IDLE; - TSTOP; + MM_TSTOP; return; case SLOW_WAIT_FOR_CLOCK: - if (patience) { - patience--; - TSTART_CLK_TO_SAMPLE_SLOW; + if (tolerated_timeouts) { + tolerated_timeouts--; + MM_TSTART_SLOW; return; } default: - TSTOP; + MM_TSTOP; recstate = IDLE; return; } @@ -219,34 +201,36 @@ ISR(TIMER0_COMPA_vect) { bitno++; if (bitno == 18) { /* Save first received word */ - shift_command_first = shift_command; - shift_address_first = shift_address; - patience = 18; + 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_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) { - - uint8_t addr = lookup_decoder(shift_address); +#endif + address = 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); + 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; + address_last = shift_address; + function_last = shift_function; + command_last = shift_command; +#endif } } @@ -282,7 +266,6 @@ ISR(TIM0_OVF_vect) } - /* Pin change interrupt vector */ void mm_pinchange_handler(void) { @@ -298,19 +281,19 @@ void mm_pinchange_handler(void) case IDLE: bitno = 0; recstate = FIRST_FAST_SAMPLE; - TSTART_CLK_TO_SAMPLE_FAST; + MM_TSTART_FAST; break; case FIRST_SLOW_SAMPLE: recstate = FAST_SAMPLE; - TSTART_CLK_TO_SAMPLE_FAST; + MM_TSTART_FAST; break; case FAST_WAIT_FOR_CLOCK: recstate = FAST_SAMPLE; - TSTART_CLK_TO_SAMPLE_FAST; + MM_TSTART_FAST; break; case SLOW_WAIT_FOR_CLOCK: recstate = SLOW_SAMPLE; - TSTART_CLK_TO_SAMPLE_SLOW; + MM_TSTART_SLOW; break; /* Not expected */ @@ -322,6 +305,17 @@ void mm_pinchange_handler(void) } } +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/main.c b/trennfix/sw/src/main.c similarity index 67% rename from trennfix/sw/main.c rename to trennfix/sw/src/main.c index 2437151..7d5c10a 100644 --- a/trennfix/sw/main.c +++ b/trennfix/sw/src/main.c @@ -30,26 +30,12 @@ #include #include +#include +#include -#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 */ @@ -74,25 +60,30 @@ struct config { 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 */ + 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 struct config config; -static volatile enum learn_mode learn_mode = LM_OFF; +static volatile struct config config; +static volatile uint8_t drive_on = 0; static void load_config(void) { - eeprom_read_block(&config, &ee_config, sizeof(config)); + eeprom_read_block((uint8_t *)&config, &ee_config, sizeof(config)); } static void save_config(void) { - eeprom_update_block(&config, &ee_config, sizeof(config)); +#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 } -static volatile uint8_t drive_on = 0; + ISR(PCINT0_vect){ static uint8_t btn_last = 0; @@ -100,23 +91,24 @@ ISR(PCINT0_vect){ mm_pinchange_handler(); if (BTN_PRESSED && !btn_last) { - learn_mode++; - learn_mode %= LM_END; + config.learn_mode++; + config.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; + uint8_t b1, b3, b5, b7; + b1 = ((command & 0x80) != 0); - b2 = ((command & 0x40) != 0); + // b2 = ((command & 0x40) != 0); b3 = ((command & 0x20) != 0); - b4 = ((command & 0x10) != 0); + // b4 = ((command & 0x10) != 0); b5 = ((command & 0x8) != 0); - b6 = ((command & 0x4) != 0); + // b6 = ((command & 0x4) != 0); b7 = ((command & 0x2) != 0); - b8 = ((command & 0x1) != 0); + // b8 = ((command & 0x1) != 0); //if ((b1 != b2) || (b2 != b3) || (b3 != b4) || (b5 != b6) || (b7 != b8)) // return 0xff; @@ -124,55 +116,97 @@ static uint8_t get_speed(uint8_t command) 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 == 100) - // - - if ((decoder == 100) && (function == 0) && (command == 0xc0)) { - config.magic = 0; + 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 (decoder == 10) { - trigger(); - if (speed == 1) { - itsme = 1; + if (config.learn_mode) { + if (decoder == 70) { + if (speed == 1) { + itsme = 1; drive_on = 1; - }else { - if (itsme) { - drive_on = 0; - itsme = 0; + }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(); } - if (decoder == 33) { - // trigger(); +} + +#else +#ifdef INTERPRET_DRIVE_SIMPLE - speed = get_speed(command); - if (speed != 0xff) { +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(learn_mode) { + switch(config.learn_mode) { case LM_OFF: default: @@ -181,7 +215,9 @@ void mm_switch_command(uint8_t decoder, uint8_t command) switch(config.op_mode) { case OM_MOMENTARY: case OM_DOUBLE: - drive_on = 1; + if (!switch_on && current_loco == 52) + save_config(); + switch_on = 1; break; case OM_TOGGLE: if (!toggle_lock) { @@ -198,7 +234,7 @@ void mm_switch_command(uint8_t decoder, uint8_t command) (command == 0)) { /* Primary key released */ switch(config.op_mode) { case OM_MOMENTARY: - drive_on = 0; + switch_on = 0; break; case OM_TOGGLE: toggle_lock = 0; @@ -207,6 +243,7 @@ void mm_switch_command(uint8_t decoder, uint8_t command) break; } } +#ifdef HANDLE_OFF_KEY if ((decoder == config.decoder_off) && (command == config.key_off)) { /* Secondary "off" key pressed */ @@ -220,27 +257,27 @@ void mm_switch_command(uint8_t decoder, uint8_t command) break; } } +#endif 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; + config.learn_mode = LM_LEARN_OFF_KEY; else - learn_mode = LM_OFF; + config.learn_mode = LM_OFF; + save_config(); } break; - -#ifdef LEARN_THE_STUFF +#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(); - learn_mode = LM_OFF; } break; @@ -302,23 +339,23 @@ void mm_switch_command(uint8_t decoder, uint8_t command) case 1: config.op_mode = OM_MOMENTARY; save_config(); - learn_mode = LM_OFF; + config.learn_mode = LM_OFF; break; case 3: config.op_mode = OM_DOUBLE; save_config(); - learn_mode = LM_OFF; + config.learn_mode = LM_OFF; break; case 5: config.op_mode = OM_TOGGLE; save_config(); - learn_mode = LM_OFF; + config.learn_mode = LM_OFF; break; default: break; } break; -#endif +#endif } } @@ -330,14 +367,15 @@ void mm_switch_command(uint8_t decoder, uint8_t command) */ int main(void) { - // uint8_t learn_mode_off; + 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; @@ -347,74 +385,76 @@ int main(void) { config.key_off = 2; config.initial_pulse = 10; config.on_duty_cycle = 5; - learn_mode = LM_LEARN_ON_KEY; + 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: - + drive_start: + + output_on = drive_on || switch_on; cli(); - if (!drive_last && drive_on) + if (!drive_last && output_on) drive_slope = 1; else drive_slope = 0; - drive_last = drive_on; + drive_last = output_on; sei(); - if (drive_on) { -#ifdef ROOM_FOR_KICK + if (output_on) { if (drive_slope) { for (i = 0; i < config.initial_pulse; i++) { setpin(PIN_DRIVE, 1); - _delay_ms(10); + _delay_ms(20); } } -#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); + setpin(PIN_DRIVE, output_on); + _delay_us(3); } - for (i = 0; i < (14 - config.on_duty_cycle); i++) { + for (i = 0; i < (28 - config.on_duty_cycle); i++) { setpin(PIN_DRIVE, 0); - _delay_us(1); + _delay_us(3); } -#else - setpin(PIN_DRIVE, 1); -#endif - } else { setpin(PIN_DRIVE, 0); - if (!learn_mode) + if (!config.learn_mode) continue; - //learn_mode_off = !learn_mode; + learn_mode_off = !config.learn_mode; - //if (drive_on || (learn_mode && learn_mode_off)) - // goto drive_start; + if (output_on || (config.learn_mode && learn_mode_off)) + goto drive_start; - for (i = 0; i < learn_mode; i++) { + for (i = 0; i < config.learn_mode; i++) { setpin(PIN_LED, 1); - _delay_ms(30); + _delay_ms(10); + //if (output_on || (config.learn_mode && learn_mode_off)) + // goto drive_start; setpin(PIN_LED, 0); - _delay_ms(280); - - //if (drive_on || (learn_mode && learn_mode_off)) + _delay_ms(135); + //if (output_on || (config.learn_mode && learn_mode_off)) // goto drive_start; - //if (drive_on || (learn_mode && learn_mode_off)) + + //if (output_on || (config.learn_mode && learn_mode_off)) // goto drive_start; } - for (i = 0; i < 15 - learn_mode; i++) { - //if (drive_on || (learn_mode && learn_mode_off)) + 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(80); - //if (drive_on || (learn_mode && learn_mode_off)) + _delay_ms(70); + //if (output_on || (config.learn_mode && learn_mode_off)) // goto drive_start; // _delay_ms(40); } -- 2.32.0