trennfix/sw: Register variables, restructuring, whatever
[eisenbahn.git] / trennfix / sw / src / main.c
CommitLineData
54de37bf
PH
1/******************************************************************************
2 *
3 * Trennfix firmware - main.c
4 *
5 * Copyright (C) 2017 Philipp Hachtmann
6 *
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.
11 *
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.
16 *
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/>.
19 *
20 *****************************************************************************/
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <avr/io.h>
27#include <avr/eeprom.h>
28#include <avr/interrupt.h>
29#include <avr/pgmspace.h>
30
31#include <util/delay.h>
32#include <stdint.h>
93cb14d4
PH
33#include <mm/mm_switch.h>
34#include <config/hardware.h>
54de37bf 35
70095677
PH
36#define EE_MAGIC 0xab
37
38enum op_mode {
39 OM_MOMENTARY, /* on as long as "key on" pressed */
40 OM_DOUBLE, /* On off with "on" and "off" keys */
41 OM_TOGGLE, /* toggle on "key on" pressed */
42 OM_ERASED = 0xff /* EEPROM erased, need setup */
43};
44
45enum learn_mode {
46 LM_OFF = 0,
47 LM_LEARN_ON_KEY, /* Learn primary key */
48 LM_LEARN_OFF_KEY, /* Learn secondary key, relevant for OM_DOUBLE */
49 LM_LEARN_INITIAL, /* Learn initial pulse length, 10ms steps */
50 LM_LEARN_DUTY, /* Learn duty cycle 0-10 */
51 LM_LEARN_OP_MODE, /* Learn operation mode */
52 LM_END, /* Only a label */
53};
54
55struct config {
56 uint8_t magic; /* Magic value */
57 enum op_mode op_mode;
58 uint8_t decoder_on;
59 uint8_t key_on;
60 uint8_t decoder_off;
61 uint8_t key_off;
93cb14d4
PH
62 uint8_t initial_pulse; /* Lenghth of initial pulse in 10ms steps */
63 uint8_t on_duty_cycle; /* Duty cycle for on. 0-10 */
64 volatile enum learn_mode learn_mode;
70095677
PH
65};
66
67static struct EEMEM config ee_config;
93cb14d4
PH
68static volatile struct config config;
69static volatile uint8_t drive_on = 0;
70095677
PH
70
71static void load_config(void)
54de37bf 72{
93cb14d4 73 eeprom_read_block((uint8_t *)&config, &ee_config, sizeof(config));
54de37bf
PH
74}
75
70095677 76static void save_config(void)
54de37bf 77{
93cb14d4
PH
78#ifdef USE_EEPROM_UPDATE
79 eeprom_update_block((uint8_t *)&config, &ee_config, sizeof(config));
80#else
81 eeprom_write_block((uint8_t *)&config, &ee_config, sizeof(config));
82#endif
54de37bf
PH
83}
84
93cb14d4 85
54de37bf 86
70095677
PH
87ISR(PCINT0_vect){
88 static uint8_t btn_last = 0;
56b25f8b 89
70095677 90 mm_pinchange_handler();
54de37bf 91
70095677 92 if (BTN_PRESSED && !btn_last) {
93cb14d4
PH
93 config.learn_mode++;
94 config.learn_mode %= LM_END;
70095677
PH
95 }
96 btn_last = BTN_PRESSED;
54de37bf
PH
97}
98
56b25f8b
PH
99static uint8_t get_speed(uint8_t command)
100{
93cb14d4
PH
101 uint8_t b1, b3, b5, b7;
102
56b25f8b 103 b1 = ((command & 0x80) != 0);
93cb14d4 104 // b2 = ((command & 0x40) != 0);
56b25f8b 105 b3 = ((command & 0x20) != 0);
93cb14d4 106 // b4 = ((command & 0x10) != 0);
56b25f8b 107 b5 = ((command & 0x8) != 0);
93cb14d4 108 // b6 = ((command & 0x4) != 0);
56b25f8b 109 b7 = ((command & 0x2) != 0);
93cb14d4 110 // b8 = ((command & 0x1) != 0);
56b25f8b
PH
111
112 //if ((b1 != b2) || (b2 != b3) || (b3 != b4) || (b5 != b6) || (b7 != b8))
113 // return 0xff;
114
115 return (b1 + b3*2 + b5*4 +b7*8);
116}
117
93cb14d4
PH
118#ifdef INTERPRET_DRIVE_COMMANDS
119
56b25f8b
PH
120void mm_switch_drive(uint8_t decoder, uint8_t function, uint8_t command)
121{
122 static uint8_t seen_before = 0;
123 uint8_t speed;
124
56b25f8b 125 if (!seen_before) {
93cb14d4
PH
126 if ((decoder == 80) && (function == 0) && (command == 0xc0)) {
127 config.learn_mode = 1;
56b25f8b
PH
128 save_config();
129 }
130 }
131 seen_before = 1;
93cb14d4 132
56b25f8b
PH
133 speed = get_speed(command);
134 static uint8_t itsme = 0;
56b25f8b 135
93cb14d4
PH
136 if (config.learn_mode) {
137 if (decoder == 70) {
138 if (speed == 1) {
139 itsme = 1;
56b25f8b 140 drive_on = 1;
93cb14d4
PH
141 }else {
142 if (itsme) {
143 drive_on = 0;
144 itsme = 0;
145 }
146 }
147 }
148
149 if (decoder == 33) {
150 if (speed != 0xff) {
151 if (speed >= 1) speed -= 1;
152 if (speed <= 14)
153 config.on_duty_cycle = speed;
154 else
155 config.on_duty_cycle = 14;
156
56b25f8b
PH
157 }
158 }
93cb14d4
PH
159
160 if (decoder == 32) {
161 if (speed != 0xff) {
162 config.initial_pulse = speed;
163 }
164 }
165
166 if (decoder == 31 && command == 0xc0)
167 save_config();
56b25f8b 168 }
93cb14d4
PH
169}
170
171#else
172#ifdef INTERPRET_DRIVE_SIMPLE
56b25f8b 173
93cb14d4
PH
174static volatile uint8_t current_loco;
175
176void mm_switch_drive(uint8_t decoder, uint8_t function, uint8_t command)
177{
178 uint8_t speed;
179 speed = get_speed(command);
180 current_loco = decoder;
181 if (speed != 0xff) {
182 if (decoder == 50) {
183 setpin(PIN_LED, drive_on = function & 3);
184 config.initial_pulse = speed;
185 } else if (decoder == 51) {
56b25f8b
PH
186 if (speed >= 1) speed -= 1;
187 if (speed <= 14)
188 config.on_duty_cycle = speed;
189 else
190 config.on_duty_cycle = 14;
93cb14d4
PH
191 } else if (decoder == 52) {
192 static uint8_t last_speed;
193 if (speed == 1 && last_speed != 1)
194 save_config();
195 last_speed = speed;
196
56b25f8b
PH
197 }
198 }
199}
200
93cb14d4
PH
201#endif
202#endif
203static volatile uint8_t switch_on = 0;
204
70095677 205void mm_switch_command(uint8_t decoder, uint8_t command)
54de37bf 206{
70095677 207 static uint8_t toggle_lock = 0;
93cb14d4 208 switch(config.learn_mode) {
70095677
PH
209
210 case LM_OFF:
211 default:
212 if ((decoder == config.decoder_on) &&
213 (command == config.key_on)) { /* Primary key pressed */
214 switch(config.op_mode) {
215 case OM_MOMENTARY:
216 case OM_DOUBLE:
93cb14d4
PH
217 if (!switch_on && current_loco == 52)
218 save_config();
219 switch_on = 1;
70095677
PH
220 break;
221 case OM_TOGGLE:
222 if (!toggle_lock) {
223 drive_on = !drive_on;
224 toggle_lock = 1;
225 }
226 break;
227 default:
228 break;
229 }
230 }
54de37bf 231
70095677 232 if ((decoder == config.decoder_on) &&
7c08d02a 233 (command == 0)) { /* Primary key released */
70095677
PH
234 switch(config.op_mode) {
235 case OM_MOMENTARY:
93cb14d4 236 switch_on = 0;
70095677
PH
237 break;
238 case OM_TOGGLE:
239 toggle_lock = 0;
240 break;
241 default:
242 break;
243 }
244 }
93cb14d4 245#ifdef HANDLE_OFF_KEY
54de37bf 246
70095677
PH
247 if ((decoder == config.decoder_off) &&
248 (command == config.key_off)) { /* Secondary "off" key pressed */
249 switch(config.op_mode) {
250 case OM_DOUBLE:
251 drive_on = 0;
252 break;
253 case OM_TOGGLE:
254 case OM_MOMENTARY:
255 default:
256 break;
70095677
PH
257 }
258 }
93cb14d4 259#endif
70095677
PH
260 break;
261
262 case LM_LEARN_ON_KEY:
263 if (command) {
264 config.decoder_on = decoder;
265 config.key_on = command;
70095677 266 if (config.op_mode == OM_DOUBLE)
93cb14d4 267 config.learn_mode = LM_LEARN_OFF_KEY;
70095677 268 else
93cb14d4
PH
269 config.learn_mode = LM_OFF;
270 save_config();
70095677
PH
271 }
272 break;
93cb14d4 273#ifdef LEARN_ADVANCED
70095677
PH
274 case LM_LEARN_OFF_KEY:
275 if (command) {
276 config.decoder_off = decoder;
277 config.key_off = command;
93cb14d4 278 config.learn_mode = LM_OFF;
70095677 279 save_config();
70095677
PH
280 }
281 break;
282
283 case LM_LEARN_INITIAL:
284 if (drive_on) {
285 if (command == 0)
286 drive_on = 0;
287
288 } else {
289 switch(command) {
290 case 1:
291 if (config.initial_pulse >= 10)
292 config.initial_pulse -= 10;
293 else
294 config.initial_pulse = 0;
295 save_config();
296 drive_on = 1;
297 break;
298 case 2:
299 if (config.initial_pulse <= 245)
300 config.initial_pulse += 10;
301 else
302 config.initial_pulse = 255;
303 save_config();
304 drive_on = 1;
305 break;
306 default:
307 break;
308 }
309 }
310 break;
54de37bf 311
70095677
PH
312 case LM_LEARN_DUTY:
313 if (drive_on) {
314 if (command == 0)
315 drive_on = 0;
316 } else {
317 switch(command) {
318 case 1:
319 if (config.on_duty_cycle > 0)
320 config.on_duty_cycle -= 1;
321 save_config();
322 drive_on = 1;
323 break;
324 case 2:
325 if (config.on_duty_cycle < 10)
326 config.on_duty_cycle += 1;
327 save_config();
328 drive_on = 1;
329 break;
330 default:
331 break;
332 }
333 }
334 break;
335
336 case LM_LEARN_OP_MODE:
337 switch(command) {
338 case 1:
339 config.op_mode = OM_MOMENTARY;
340 save_config();
93cb14d4 341 config.learn_mode = LM_OFF;
70095677
PH
342 break;
343 case 3:
344 config.op_mode = OM_DOUBLE;
345 save_config();
93cb14d4 346 config.learn_mode = LM_OFF;
70095677
PH
347 break;
348 case 5:
349 config.op_mode = OM_TOGGLE;
350 save_config();
93cb14d4 351 config.learn_mode = LM_OFF;
70095677
PH
352 break;
353 default:
354 break;
355 }
356 break;
93cb14d4 357#endif
54de37bf
PH
358 }
359}
360
361
54de37bf
PH
362/******************************************************************************
363 *
364 * main() - The main routine
365 *
366 */
7c08d02a 367void shift(uint8_t mu);
54de37bf
PH
368
369int main(void) {
93cb14d4 370 uint8_t learn_mode_off;
70095677
PH
371 uint8_t drive_last = 0;
372 uint8_t drive_slope = 0;
373 uint8_t i;
93cb14d4 374 uint8_t output_on;
70095677 375
7c08d02a 376 mm_init();
70095677 377 load_config();
56b25f8b 378 setup_hw();
93cb14d4 379
56b25f8b 380 if ((config.op_mode == OM_ERASED) || (config.magic != EE_MAGIC)) {
70095677
PH
381 config.magic = EE_MAGIC;
382 config.op_mode = OM_MOMENTARY;
56b25f8b
PH
383 config.decoder_on = 1;
384 config.key_on = 1;
70095677
PH
385 config.decoder_off = 1;
386 config.key_off = 2;
387 config.initial_pulse = 10;
388 config.on_duty_cycle = 5;
93cb14d4 389 config.learn_mode = LM_LEARN_ON_KEY;
70095677 390 }
93cb14d4 391 drive_on = 0;
54de37bf 392 sei();
7c08d02a 393
93cb14d4
PH
394
395 //setpin(PIN_LED,1 );
396 //_delay_ms(400);
397 //setpin(PIN_LED,0 );
54de37bf 398 while (1) {
70095677 399
93cb14d4
PH
400 drive_start:
401
402 output_on = drive_on || switch_on;
70095677 403 cli();
93cb14d4 404 if (!drive_last && output_on)
70095677
PH
405 drive_slope = 1;
406 else
407 drive_slope = 0;
93cb14d4 408 drive_last = output_on;
70095677 409 sei();
56b25f8b 410
93cb14d4 411 if (output_on) {
70095677
PH
412 if (drive_slope) {
413 for (i = 0; i < config.initial_pulse; i++) {
414 setpin(PIN_DRIVE, 1);
93cb14d4 415 _delay_ms(20);
70095677 416 }
af5fd980 417 }
56b25f8b 418
70095677 419 for (i = 0; i < config.on_duty_cycle; i++) {
93cb14d4 420 setpin(PIN_DRIVE, output_on);
7c08d02a 421 _delay_us(1);
af5fd980 422 }
7c08d02a 423 for (i = 0; i < (14 - config.on_duty_cycle); i++) {
70095677 424 setpin(PIN_DRIVE, 0);
7c08d02a 425 _delay_us(1);
70095677
PH
426 }
427
54de37bf 428 } else {
56b25f8b 429 setpin(PIN_DRIVE, 0);
93cb14d4 430 if (!config.learn_mode)
70095677 431 continue;
54de37bf 432
93cb14d4 433 learn_mode_off = !config.learn_mode;
70095677 434
93cb14d4
PH
435 if (output_on || (config.learn_mode && learn_mode_off))
436 goto drive_start;
70095677 437
93cb14d4 438 for (i = 0; i < config.learn_mode; i++) {
70095677 439 setpin(PIN_LED, 1);
93cb14d4
PH
440 _delay_ms(10);
441 //if (output_on || (config.learn_mode && learn_mode_off))
442 // goto drive_start;
70095677 443 setpin(PIN_LED, 0);
93cb14d4
PH
444 _delay_ms(135);
445 //if (output_on || (config.learn_mode && learn_mode_off))
70095677 446 // goto drive_start;
93cb14d4
PH
447
448 //if (output_on || (config.learn_mode && learn_mode_off))
70095677
PH
449 // goto drive_start;
450 }
93cb14d4
PH
451 for (i = 0; i < 15 - config.learn_mode; i++) {
452 //if (output_on || (config.learn_mode && learn_mode_off))
70095677
PH
453 // goto drive_start;
454 setpin(PIN_LED, 0);
93cb14d4
PH
455 _delay_ms(70);
456 //if (output_on || (config.learn_mode && learn_mode_off))
70095677
PH
457 // goto drive_start;
458 // _delay_ms(40);
459 }
460 }
54de37bf
PH
461 }
462 return 0;
463}
464
70095677 465
54de37bf
PH
466/******************************************************************************
467 * The end :-)
468 */