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 */
+ 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_EASY_WAIT_PRESS, /* Wait for key press to enter easy mode */
+ LM_EASY_WAIT_UP, /* Wait for end of key press */
+ LM_EASY_WAIT_TURN, /* Wait for loco 80 turn end */
+ LM_EASY_MODE, /* Easy config mode for PWM and initial kick */
+ LM_END, /* Only a label */
};
struct config {
static struct EEMEM config ee_config;
static volatile struct config config;
+
+static volatile uint8_t easy_mode = 0;
+static volatile uint8_t easy_mode_possible = 0;
+
+#ifndef USE_REGISTER_VARS
static volatile uint8_t drive_on = 0;
+#endif
+
+/******************************************************************************
+ *
+ * Some nice sounds to play on your coil
+ *
+ */
+
+#define G 180
+#define sekunde(g)(quinte((quinte(g)))*2)
+#define terz(g) ((g) * 4 / 5)
+#define kleine_terz(g) ((g) * 5 / 6)
+#define quarte(g) ((g) * 3 / 4)
+#define quinte(g) ((g) * 2 / 3)
+#define tt(g) ((g) * 32 / 45)
+#define septime(g) ((g) * 15 / 8)
+
+#if defined(WITH_SOUND) && defined(WITH_PWM)
+void play_tone(uint8_t divisor, uint8_t duration, uint8_t pause)
+{
+ uint16_t c;
+ TCCR1 = 0x8;
+ OCR1C = divisor;
+ OCR1B = divisor / 2;
+ for (c = 0; c < duration - pause; c++)
+ _delay_ms(2);
+ OCR1B = 255;
+ OCR1C = 14;
+ for (c = 0; c < pause; c++)
+ _delay_ms(2);
+ TCCR1 = 0x6;
+ OCR1C = 14;
+ OCR1B = 14;
+}
+
+static void tone_enter(void)
+{
+ play_tone((G), 70, 20);
+ play_tone(terz(G), 70, 20);
+ play_tone(quinte(G), 70, 20);
+ play_tone(G/2, 100, 0);
+}
+
+static void tone_good(void)
+{
+ play_tone(G, 150, 120);
+ play_tone(terz(G), 100, 70);
+ play_tone(tt(G), 100, 50);
+ play_tone(quarte(terz((G))), 50, 0);
+ play_tone(quinte(G), 150, 0);
+ play_tone(terz(G), 100, 50);
+}
+
+static void snd_on(void)
+{
+ TCCR1 = 0x8;
+ OCR1C = 120;
+ OCR1B = 60;
+}
+
+static void snd_off(void)
+{
+ TCCR1 = 0x6;
+ OCR1C = 14;
+ OCR1B = 14;
+}
+
+#else
+#define play_tone(...)
+#define tone_enter(...)
+#define tone_good(...)
+#define snd_on(...)
+#define snd_off(...)
+#endif
static void load_config(void)
{
static void save_config(void)
{
-#ifdef USE_EEPROM_UPDATE
+#ifdef WITH_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;
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)
+void mm_switch_drive(uint8_t loco, 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;
+ static uint8_t alert_last = 0;
+
+ switch(loco) {
+ case 80:
+ switch (config.learn_mode) {
+ case LM_OFF:
+ if (speed == 1)
+ config.learn_mode = LM_EASY_WAIT_PRESS;
+ break;
+ case LM_EASY_MODE:
+ if ((speed == 1) && (alert_last == 0)) {
+ config.learn_mode = LM_OFF;
+ save_config();
+ tone_good();
}
- }
-
- if (decoder == 31 && command == 0xc0)
- save_config();
- }
-}
-
-#else
-#ifdef INTERPRET_DRIVE_SIMPLE
+ break;
-static volatile uint8_t current_loco;
+ case LM_EASY_WAIT_PRESS:
+ if (speed != 1)
+ config.learn_mode = LM_OFF;
+ break;
-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);
+ default:
+ break;
+ }
+ alert_last = (speed == 1);
+ break;
+ case 50:
+ if (speed)
+ speed -= 1;
+
+ if (config.learn_mode == LM_EASY_MODE) {
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;
-
}
+ break;
+ case 51:
+ if (config.learn_mode == LM_EASY_MODE)
+ config.on_duty_cycle = speed;
+ break;
}
+
}
-#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:
switch(config.op_mode) {
case OM_MOMENTARY:
case OM_DOUBLE:
- if (!switch_on && current_loco == 52)
- save_config();
- switch_on = 1;
+ drive_on = 1;
break;
case OM_TOGGLE:
if (!toggle_lock) {
- drive_on = !drive_on;
+ drive_on = ~drive_on;
toggle_lock = 1;
}
break;
break;
}
}
-
if ((decoder == config.decoder_on) &&
(command == 0)) { /* Primary key released */
switch(config.op_mode) {
case OM_MOMENTARY:
- switch_on = 0;
+ drive_on = 0;
break;
case OM_TOGGLE:
toggle_lock = 0;
break;
}
}
+ break;
+
+ case LM_EASY_WAIT_PRESS:
+ if ((decoder == config.decoder_on) &&
+ (command == config.key_on))
+ config.learn_mode = LM_EASY_WAIT_UP;
+ return;
+
+ case LM_EASY_WAIT_UP:
+ if ((decoder == config.decoder_on) &&
+ (command == 0)) {
+ config.learn_mode = LM_EASY_MODE;
+ tone_enter();
+ }
+ return;
+
#ifdef HANDLE_OFF_KEY
if ((decoder == config.decoder_off) &&
*/
void shift(uint8_t mu);
+#ifdef WITH_PWM
+#define DRIVE_OFF {OCR1B = 14;}
+#define DRIVE_ON {OCR1B = 14 - config.on_duty_cycle;}
+#define DRIVE_FULL {OCR1B = 0;}
+#else
+#define DRIVE_OFF {setpin(PIN_DRIVE, 0);}
+#define DRIVE_ON {setpin(PIN_DRIVE, 1); setpin(PIN_LED, 1);}
+#define DRIVE_FULL {setpin(PIN_DRIVE, 1); setpin(PIN_LED, 0);}
+#endif
+
int main(void) {
- uint8_t learn_mode_off;
+ uint16_t i;
+
+#ifdef WITH_INITIAL_PULSE
uint8_t drive_last = 0;
uint8_t drive_slope = 0;
- uint8_t i;
- uint8_t output_on;
+#endif
+
+#ifdef USE_REGISTER_VARS
+ drive_on = 0;
+#endif
mm_init();
load_config();
setup_hw();
-
- if ((config.op_mode == OM_ERASED) || (config.magic != EE_MAGIC)) {
+
+ if (config.magic != EE_MAGIC) {
config.magic = EE_MAGIC;
config.op_mode = OM_MOMENTARY;
config.decoder_on = 1;
config.on_duty_cycle = 5;
config.learn_mode = LM_LEARN_ON_KEY;
}
- drive_on = 0;
sei();
-
- //setpin(PIN_LED,1 );
- //_delay_ms(400);
- //setpin(PIN_LED,0 );
while (1) {
-
drive_start:
- output_on = drive_on || switch_on;
+#ifdef WITH_INITIAL_PULSE
cli();
- if (!drive_last && output_on)
+ if (drive_on && !drive_last)
drive_slope = 1;
else
drive_slope = 0;
- drive_last = output_on;
+ drive_last = drive_on;
sei();
+#endif
+ if (drive_on) {
- if (output_on) {
+#ifdef WITH_INITIAL_PULSE
if (drive_slope) {
+ DRIVE_FULL;
for (i = 0; i < config.initial_pulse; i++) {
- setpin(PIN_DRIVE, 1);
- _delay_ms(20);
+ _delay_ms(5);
}
}
-
- for (i = 0; i < config.on_duty_cycle; i++) {
- setpin(PIN_DRIVE, output_on);
- _delay_us(1);
- }
- for (i = 0; i < (14 - config.on_duty_cycle); i++) {
- setpin(PIN_DRIVE, 0);
- _delay_us(1);
- }
-
+#endif
+ DRIVE_ON;
+
} else {
- setpin(PIN_DRIVE, 0);
- if (!config.learn_mode)
+ DRIVE_OFF;
+
+ if (!config.learn_mode ||
+ config.learn_mode > LM_LEARN_OP_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);
+ snd_on();
_delay_ms(10);
- //if (output_on || (config.learn_mode && learn_mode_off))
- // goto drive_start;
setpin(PIN_LED, 0);
+ snd_off();
+ if (drive_on) goto drive_start;
_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;
+ if (drive_on) 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);
+ if (drive_on) goto drive_start;
_delay_ms(70);
- //if (output_on || (config.learn_mode && learn_mode_off))
- // goto drive_start;
- // _delay_ms(40);
}
}
}
return 0;
}
-
/******************************************************************************
* The end :-)
*/