1 /******************************************************************************
3 * Trennfix firmware - main.c
5 * Copyright (C) 2017 Philipp Hachtmann
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *****************************************************************************/
27 #include <avr/eeprom.h>
28 #include <avr/interrupt.h>
29 #include <avr/pgmspace.h>
31 #include <util/delay.h>
33 #include <mm/mm_switch.h>
34 #include <config/hardware.h>
40 OM_MOMENTARY
, /* on as long as "key on" pressed */
41 OM_DOUBLE
, /* On off with "on" and "off" keys */
42 OM_TOGGLE
, /* toggle on "key on" pressed */
43 OM_ERASED
= 0xff /* EEPROM erased, need setup */
48 LM_LEARN_ON_KEY
, /* Learn primary key */
49 LM_LEARN_OFF_KEY
, /* Learn secondary key, relevant for OM_DOUBLE */
50 LM_LEARN_INITIAL
, /* Learn initial pulse length, 10ms steps */
51 LM_LEARN_DUTY
, /* Learn duty cycle 0-10 */
52 LM_LEARN_OP_MODE
, /* Learn operation mode */
53 LM_END
, /* Only a label */
57 uint8_t magic
; /* Magic value */
63 uint8_t initial_pulse
; /* Lenghth of initial pulse in 10ms steps */
64 uint8_t on_duty_cycle
; /* Duty cycle for on. 0-10 */
65 volatile enum learn_mode learn_mode
;
68 static struct EEMEM config ee_config
;
69 static volatile struct config config
;
70 static volatile uint8_t drive_on
= 0;
72 static void load_config(void)
74 eeprom_read_block((uint8_t *)&config
, &ee_config
, sizeof(config
));
77 static void save_config(void)
79 #ifdef USE_EEPROM_UPDATE
80 eeprom_update_block((uint8_t *)&config
, &ee_config
, sizeof(config
));
82 eeprom_write_block((uint8_t *)&config
, &ee_config
, sizeof(config
));
89 static uint8_t btn_last
= 0;
91 mm_pinchange_handler();
93 if (BTN_PRESSED
&& !btn_last
) {
95 config
.learn_mode
%= LM_END
;
97 btn_last
= BTN_PRESSED
;
100 static uint8_t get_speed(uint8_t command
)
102 uint8_t b1
, b3
, b5
, b7
;
104 b1
= ((command
& 0x80) != 0);
105 // b2 = ((command & 0x40) != 0);
106 b3
= ((command
& 0x20) != 0);
107 // b4 = ((command & 0x10) != 0);
108 b5
= ((command
& 0x8) != 0);
109 // b6 = ((command & 0x4) != 0);
110 b7
= ((command
& 0x2) != 0);
111 // b8 = ((command & 0x1) != 0);
113 //if ((b1 != b2) || (b2 != b3) || (b3 != b4) || (b5 != b6) || (b7 != b8))
116 return (b1
+ b3
*2 + b5
*4 +b7
*8);
119 #ifdef INTERPRET_DRIVE_COMMANDS
121 void mm_switch_drive(uint8_t decoder
, uint8_t function
, uint8_t command
)
123 static uint8_t seen_before
= 0;
127 if ((decoder
== 80) && (function
== 0) && (command
== 0xc0)) {
128 config
.learn_mode
= 1;
134 speed
= get_speed(command
);
135 static uint8_t itsme
= 0;
137 if (config
.learn_mode
) {
152 if (speed
>= 1) speed
-= 1;
154 config
.on_duty_cycle
= speed
;
156 config
.on_duty_cycle
= 14;
163 config
.initial_pulse
= speed
;
167 if (decoder
== 31 && command
== 0xc0)
173 #ifdef INTERPRET_DRIVE_SIMPLE
175 static volatile uint8_t current_loco
;
177 void mm_switch_drive(uint8_t decoder
, uint8_t function
, uint8_t command
)
180 speed
= get_speed(command
);
181 current_loco
= decoder
;
184 setpin(PIN_LED
, drive_on
= function
& 3);
185 config
.initial_pulse
= speed
;
186 } else if (decoder
== 51) {
187 if (speed
>= 1) speed
-= 1;
189 config
.on_duty_cycle
= speed
;
191 config
.on_duty_cycle
= 14;
192 } else if (decoder
== 52) {
193 static uint8_t last_speed
;
194 if (speed
== 1 && last_speed
!= 1)
204 static volatile uint8_t switch_on
= 0;
206 void mm_switch_command(uint8_t decoder
, uint8_t command
)
208 static uint8_t toggle_lock
= 0;
209 switch(config
.learn_mode
) {
213 if ((decoder
== config
.decoder_on
) &&
214 (command
== config
.key_on
)) { /* Primary key pressed */
215 switch(config
.op_mode
) {
218 if (!switch_on
&& current_loco
== 52)
224 drive_on
= !drive_on
;
233 if ((decoder
== config
.decoder_on
) &&
234 (command
== 0)) { /* Primary key released */
235 switch(config
.op_mode
) {
246 #ifdef HANDLE_OFF_KEY
248 if ((decoder
== config
.decoder_off
) &&
249 (command
== config
.key_off
)) { /* Secondary "off" key pressed */
250 switch(config
.op_mode
) {
263 case LM_LEARN_ON_KEY
:
265 config
.decoder_on
= decoder
;
266 config
.key_on
= command
;
267 if (config
.op_mode
== OM_DOUBLE
)
268 config
.learn_mode
= LM_LEARN_OFF_KEY
;
270 config
.learn_mode
= LM_OFF
;
274 #ifdef LEARN_ADVANCED
275 case LM_LEARN_OFF_KEY
:
277 config
.decoder_off
= decoder
;
278 config
.key_off
= command
;
279 config
.learn_mode
= LM_OFF
;
284 case LM_LEARN_INITIAL
:
292 if (config
.initial_pulse
>= 10)
293 config
.initial_pulse
-= 10;
295 config
.initial_pulse
= 0;
300 if (config
.initial_pulse
<= 245)
301 config
.initial_pulse
+= 10;
303 config
.initial_pulse
= 255;
320 if (config
.on_duty_cycle
> 0)
321 config
.on_duty_cycle
-= 1;
326 if (config
.on_duty_cycle
< 10)
327 config
.on_duty_cycle
+= 1;
337 case LM_LEARN_OP_MODE
:
340 config
.op_mode
= OM_MOMENTARY
;
342 config
.learn_mode
= LM_OFF
;
345 config
.op_mode
= OM_DOUBLE
;
347 config
.learn_mode
= LM_OFF
;
350 config
.op_mode
= OM_TOGGLE
;
352 config
.learn_mode
= LM_OFF
;
363 /******************************************************************************
365 * main() - The main routine
370 uint8_t learn_mode_off
;
371 uint8_t drive_last
= 0;
372 uint8_t drive_slope
= 0;
379 if ((config
.op_mode
== OM_ERASED
) || (config
.magic
!= EE_MAGIC
)) {
380 config
.magic
= EE_MAGIC
;
381 config
.op_mode
= OM_MOMENTARY
;
382 config
.decoder_on
= 1;
384 config
.decoder_off
= 1;
386 config
.initial_pulse
= 10;
387 config
.on_duty_cycle
= 5;
388 config
.learn_mode
= LM_LEARN_ON_KEY
;
392 setpin(PIN_DRIVE
, 1);
394 setpin(PIN_DRIVE
, 0);
396 //setpin(PIN_LED,1 );
398 //setpin(PIN_LED,0 );
403 output_on
= drive_on
|| switch_on
;
405 if (!drive_last
&& output_on
)
409 drive_last
= output_on
;
414 for (i
= 0; i
< config
.initial_pulse
; i
++) {
415 setpin(PIN_DRIVE
, 1);
420 for (i
= 0; i
< config
.on_duty_cycle
; i
++) {
421 setpin(PIN_DRIVE
, output_on
);
424 for (i
= 0; i
< (28 - config
.on_duty_cycle
); i
++) {
425 setpin(PIN_DRIVE
, 0);
430 setpin(PIN_DRIVE
, 0);
431 if (!config
.learn_mode
)
434 learn_mode_off
= !config
.learn_mode
;
436 if (output_on
|| (config
.learn_mode
&& learn_mode_off
))
439 for (i
= 0; i
< config
.learn_mode
; i
++) {
442 //if (output_on || (config.learn_mode && learn_mode_off))
446 //if (output_on || (config.learn_mode && learn_mode_off))
449 //if (output_on || (config.learn_mode && learn_mode_off))
452 for (i
= 0; i
< 15 - config
.learn_mode
; i
++) {
453 //if (output_on || (config.learn_mode && learn_mode_off))
457 //if (output_on || (config.learn_mode && learn_mode_off))
467 /******************************************************************************