47d051d34dacce3e486d21da22a6256932cea3d7
[eisenbahn.git] / trennfix / sw / src / main.c
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>
33 #include <mm/mm_switch.h>
34 #include <config/hardware.h>
35
36 #define EE_MAGIC 0xab
37
38 enum 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
45 enum 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
55 struct 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;
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;
65 };
66
67 static struct EEMEM config ee_config;
68 static volatile struct config config;
69 static volatile uint8_t drive_on = 0;
70
71 static void load_config(void)
72 {
73 eeprom_read_block((uint8_t *)&config, &ee_config, sizeof(config));
74 }
75
76 static void save_config(void)
77 {
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
83 }
84
85
86
87 ISR(PCINT0_vect){
88 static uint8_t btn_last = 0;
89
90 mm_pinchange_handler();
91
92 if (BTN_PRESSED && !btn_last) {
93 config.learn_mode++;
94 config.learn_mode %= LM_END;
95 }
96 btn_last = BTN_PRESSED;
97 }
98
99 static uint8_t get_speed(uint8_t command)
100 {
101 uint8_t b1, b3, b5, b7;
102
103 b1 = ((command & 0x80) != 0);
104 // b2 = ((command & 0x40) != 0);
105 b3 = ((command & 0x20) != 0);
106 // b4 = ((command & 0x10) != 0);
107 b5 = ((command & 0x8) != 0);
108 // b6 = ((command & 0x4) != 0);
109 b7 = ((command & 0x2) != 0);
110 // b8 = ((command & 0x1) != 0);
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
118 #ifdef INTERPRET_DRIVE_COMMANDS
119
120 void 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
125 if (!seen_before) {
126 if ((decoder == 80) && (function == 0) && (command == 0xc0)) {
127 config.learn_mode = 1;
128 save_config();
129 }
130 }
131 seen_before = 1;
132
133 speed = get_speed(command);
134 static uint8_t itsme = 0;
135
136 if (config.learn_mode) {
137 if (decoder == 70) {
138 if (speed == 1) {
139 itsme = 1;
140 drive_on = 1;
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
157 }
158 }
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();
168 }
169 }
170
171 #else
172 #ifdef INTERPRET_DRIVE_SIMPLE
173
174 static volatile uint8_t current_loco;
175
176 void 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) {
186 if (speed >= 1) speed -= 1;
187 if (speed <= 14)
188 config.on_duty_cycle = speed;
189 else
190 config.on_duty_cycle = 14;
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
197 }
198 }
199 }
200
201 #endif
202 #endif
203 static volatile uint8_t switch_on = 0;
204
205 void mm_switch_command(uint8_t decoder, uint8_t command)
206 {
207 static uint8_t toggle_lock = 0;
208 switch(config.learn_mode) {
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:
217 if (!switch_on && current_loco == 52)
218 save_config();
219 switch_on = 1;
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 }
231
232 if ((decoder == config.decoder_on) &&
233 (command == 0)) { /* Primary key released */
234 switch(config.op_mode) {
235 case OM_MOMENTARY:
236 switch_on = 0;
237 break;
238 case OM_TOGGLE:
239 toggle_lock = 0;
240 break;
241 default:
242 break;
243 }
244 }
245 #ifdef HANDLE_OFF_KEY
246
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;
257 }
258 }
259 #endif
260 break;
261
262 case LM_LEARN_ON_KEY:
263 if (command) {
264 config.decoder_on = decoder;
265 config.key_on = command;
266 if (config.op_mode == OM_DOUBLE)
267 config.learn_mode = LM_LEARN_OFF_KEY;
268 else
269 config.learn_mode = LM_OFF;
270 save_config();
271 }
272 break;
273 #ifdef LEARN_ADVANCED
274 case LM_LEARN_OFF_KEY:
275 if (command) {
276 config.decoder_off = decoder;
277 config.key_off = command;
278 config.learn_mode = LM_OFF;
279 save_config();
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;
311
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();
341 config.learn_mode = LM_OFF;
342 break;
343 case 3:
344 config.op_mode = OM_DOUBLE;
345 save_config();
346 config.learn_mode = LM_OFF;
347 break;
348 case 5:
349 config.op_mode = OM_TOGGLE;
350 save_config();
351 config.learn_mode = LM_OFF;
352 break;
353 default:
354 break;
355 }
356 break;
357 #endif
358 }
359 }
360
361
362 /******************************************************************************
363 *
364 * main() - The main routine
365 *
366 */
367 void shift(uint8_t mu);
368
369 int main(void) {
370 uint8_t learn_mode_off;
371 uint8_t drive_last = 0;
372 uint8_t drive_slope = 0;
373 uint8_t i;
374 uint8_t output_on;
375
376 mm_init();
377 load_config();
378 setup_hw();
379
380 if ((config.op_mode == OM_ERASED) || (config.magic != EE_MAGIC)) {
381 config.magic = EE_MAGIC;
382 config.op_mode = OM_MOMENTARY;
383 config.decoder_on = 1;
384 config.key_on = 1;
385 config.decoder_off = 1;
386 config.key_off = 2;
387 config.initial_pulse = 10;
388 config.on_duty_cycle = 5;
389 config.learn_mode = LM_LEARN_ON_KEY;
390 }
391 drive_on = 0;
392 sei();
393
394
395 //setpin(PIN_LED,1 );
396 //_delay_ms(400);
397 //setpin(PIN_LED,0 );
398 while (1) {
399
400 drive_start:
401
402 output_on = drive_on || switch_on;
403 cli();
404 if (!drive_last && output_on)
405 drive_slope = 1;
406 else
407 drive_slope = 0;
408 drive_last = output_on;
409 sei();
410
411 if (output_on) {
412 if (drive_slope) {
413 for (i = 0; i < config.initial_pulse; i++) {
414 setpin(PIN_DRIVE, 1);
415 _delay_ms(20);
416 }
417 }
418
419 for (i = 0; i < config.on_duty_cycle; i++) {
420 setpin(PIN_DRIVE, output_on);
421 _delay_us(1);
422 }
423 for (i = 0; i < (14 - config.on_duty_cycle); i++) {
424 setpin(PIN_DRIVE, 0);
425 _delay_us(1);
426 }
427
428 } else {
429 setpin(PIN_DRIVE, 0);
430 if (!config.learn_mode)
431 continue;
432
433 learn_mode_off = !config.learn_mode;
434
435 if (output_on || (config.learn_mode && learn_mode_off))
436 goto drive_start;
437
438 for (i = 0; i < config.learn_mode; i++) {
439 setpin(PIN_LED, 1);
440 _delay_ms(10);
441 //if (output_on || (config.learn_mode && learn_mode_off))
442 // goto drive_start;
443 setpin(PIN_LED, 0);
444 _delay_ms(135);
445 //if (output_on || (config.learn_mode && learn_mode_off))
446 // goto drive_start;
447
448 //if (output_on || (config.learn_mode && learn_mode_off))
449 // goto drive_start;
450 }
451 for (i = 0; i < 15 - config.learn_mode; i++) {
452 //if (output_on || (config.learn_mode && learn_mode_off))
453 // goto drive_start;
454 setpin(PIN_LED, 0);
455 _delay_ms(70);
456 //if (output_on || (config.learn_mode && learn_mode_off))
457 // goto drive_start;
458 // _delay_ms(40);
459 }
460 }
461 }
462 return 0;
463 }
464
465
466 /******************************************************************************
467 * The end :-)
468 */