trennfix/sw: Register variables, restructuring, whatever
[eisenbahn.git] / trennfix / sw / mm / src / mm_switch.c
index 2b09e5cbeaf5dda4d387f85b7f488fd0373b8b3e..30f43cbaa3ddd13f0391d3e76a54cbec4c464318 100644 (file)
  *    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,
-};
 
 /*
  *
@@ -65,12 +56,16 @@ enum recstate {
 /*
  *    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;
 
+#ifndef MM_USE_REGISTER_VARS
+
+static volatile uint8_t bitno = 0;
+static uint8_t shift_command;
+static uint8_t shift_function;
+static uint8_t shift_address;
+static  enum mm_recstate recstate = MM_IDLE;
+
+#endif
 
 /*
  * Lookup trinary nibble
@@ -105,30 +100,115 @@ static uint8_t lookup_decoder(uint8_t mm_byte)
        return 9 * high + low;
 }
 
-static uint8_t lookup_command(uint8_t mm_byte)
+static uint8_t lookup_command(uint8_t mm_command)
 {
-       switch(mm_byte) {
-       case 0xc3: return 1;
-       case 0x03: return 2;
-       case 0xf3: return 3;
-       case 0x33: return 4;
-       case 0xcf: return 5;
-       case 0x0f: return 6;
-       case 0xff: return 7;
-       case 0x3f: return 8;
-       default:
+       uint8_t res;
+       /*
+        * Check for aabbccdd condition
+        * 
+        *        a  a  b  b  c  c  d  d   mm_command
+        *   XOR  a  b  b  c  c  d  d  0   mm_command << 1
+        * Mask   1  0  1  0  1  0  1  0   0xaa
+        *
+        * Must be zero!
+        *
+        */
+
+       if ((mm_command ^ (mm_command << 1)) & 0xaa)
                return 0;
-        }
+       /*
+        * Protocol differences:
+        * =====================
+        *
+        * I have an old "central control" 6022 and a "control unit" 6021
+        * for measurements and test. It is assumed that the 6022 outputs
+        * old MM1 format while the 6021 definitively outputs MM2 telegrams.
+        * 
+        * In MM1, switch commands are different from MM2 with respect what
+        * happens if you release a button.
+        *
+        * When you press a button, both protocols send
+        *
+        * <aaaaaaaa><00><aabbcc11>
+        *
+        * where a = 1, b = 2, c = 4 and the keys are numerated from 0 to 7
+        * in the order 1 red, 1 green, 2 red, 2 green and so on.
+        * 
+        * The last two bits correspond to "on" state of the button/coil.
+        *
+        * When a key is released under MM1 protocol, the sequence sent is
+        * analogue to the button down sequence:
+        * 
+        * <aaaaaaaa><00><aabbcc00> where abc again represents the button's
+        * address and the last bits now signal "off".
+        *
+        * MM2 handles this differently:
+        * Whenever any key from the addressed decoder is released, the sequence
+        * <aaaaaaaa>00<00000000> is sent - not only for key 0, but for all
+        * keys!
+        *
+        * While MM1 presents the theoretical possibility to press several keys
+        * independently and simultaneously (which my keyboard does NOT
+        * support), MM2 supports only one key at a time (besides strange
+        * sequences like "one down, another down, all up"...
+        * 
+        * A decoder that strictly adheres to the MM1 standard would not work
+        * properly with MM2 control units. As far as I know all K83/K84
+        * decoders always worked with MM2 control units. That means that
+        * they reduce the commands to the possibilities of MM2 from the
+        * beginning.
+        *
+        * Possible use cases for the old protocol button release commands:
+        *   - Determine if the protocol is MM1 or MM2
+        *   - Implement hidden evil features into the controller which can
+        *     only be summoned by old MM1 gear or selfmade control telegram
+        *     generators.
+        *
+        * What this code now actually does:
+        * =================================
+        *
+        * When key pressed (aabbcc11), it will send out the key number in the
+        * range 1-8 and 0 if it gets any key up command and therefore ignore
+        * the key number if it is transmitted with the key up command.
+        *
+        */
+       if (!(mm_command & 0x01))
+               res = 0;
+       else
+               res = (mm_command & 0x80) * 1 + (mm_command & 0x20) * 0x02
+                       + (mm_command & 0x08) * 0x04 + 1;
+       return res;
 }
 
+
 /* We will shift from right to left.
  * XXXXXXXX        XX          XXXXXXXX
  * shift_address   shift_function  shift_command
  *
  * The bits 7 downto 2 of shift_function are ignored.
  */
+#define SAVE_ANOTHER_40_BYTES
+#ifdef SAVE_ANOTHER_40_BYTES
 
-static inline void shift(uint8_t value)
+void shift(uint8_t value)
+{
+       asm("ror %[val]                 ; Shift value right into carry\n\t"
+           "rol %[cmd]                 ; and shift to command reg\n\t"
+           "mov __tmp_reg__, %[func]   ; save function value \n\t"
+           "rol %[func]                ; Shift up function value\n\t"
+           "ror __tmp_reg__            ; shift bit 1\n\t"
+           "ror  __tmp_reg__           ;          down to carry\n\t"
+           "rol %[addr]                ; And we're at the address\n\t"
+           : [cmd] "=r" (shift_command), [func] "=r" (shift_function),
+             [addr] "=r" (shift_address)
+           : "0" (shift_command), "1" (shift_function),
+           "2" (shift_address), [val] "r" (value)
+           );
+}
+
+#else /* This is what we do to shift */
+
+void shift(uint8_t value)
 {
        shift_address <<= 1;
        if (shift_function & 2)
@@ -140,6 +220,8 @@ static inline void shift(uint8_t value)
        if (value)
                shift_command |= 1;
 }
+#endif
+
 
 ISR(MM_TIMER_INT_VECT) {
        static uint8_t tolerated_timeouts = 0;
@@ -157,35 +239,35 @@ ISR(MM_TIMER_INT_VECT) {
 #endif
 
        switch(recstate) {
-       case FIRST_FAST_SAMPLE:
-               recstate = FIRST_SLOW_SAMPLE;
+       case MM_FIRST_FAST_SAMPLE:
+               recstate = MM_FIRST_SLOW_SAMPLE;
                MM_TSTART_FAST; /* Will not run out in fast! */
                break;
 
-       case FIRST_SLOW_SAMPLE:
+       case MM_FIRST_SLOW_SAMPLE:
                bitno = 0;
 
-       case SLOW_SAMPLE:
-               recstate = SLOW_WAIT_FOR_CLOCK;
+       case MM_SLOW_SAMPLE:
+               recstate = MM_SLOW_WAIT_FOR_CLOCK;
                MM_TSTART_SLOW;
                break;
        
-       case FAST_SAMPLE:
-               recstate = FAST_WAIT_FOR_CLOCK;
+       case MM_FAST_SAMPLE:
+               recstate = MM_FAST_WAIT_FOR_CLOCK;
                MM_TSTART_FAST;
                break;
 
-       case FAST_WAIT_FOR_CLOCK: /* A timeout! */
+       case MM_FAST_WAIT_FOR_CLOCK: /* A timeout! */
                if (tolerated_timeouts) {
                        tolerated_timeouts--;
                        MM_TSTART_FAST;
                        return;
                }
-               recstate = IDLE;
+               recstate = MM_IDLE;
                MM_TSTOP;
                return;
 
-       case SLOW_WAIT_FOR_CLOCK:
+       case MM_SLOW_WAIT_FOR_CLOCK:
                if (tolerated_timeouts) {
                        tolerated_timeouts--;
                        MM_TSTART_SLOW;
@@ -193,7 +275,7 @@ ISR(MM_TIMER_INT_VECT) {
                }
        default:
                MM_TSTOP;
-               recstate = IDLE;
+               recstate = MM_IDLE;
                return;
        }
        
@@ -219,9 +301,9 @@ ISR(MM_TIMER_INT_VECT) {
 #endif
                                address = lookup_decoder(shift_address);
                                
-                               if (recstate == SLOW_WAIT_FOR_CLOCK) {
+                               if (recstate == MM_SLOW_WAIT_FOR_CLOCK) {
                                        mm_switch_drive(address, shift_function, shift_command);
-                               } else if (recstate == FAST_WAIT_FOR_CLOCK) {
+                               } else if (recstate == MM_FAST_WAIT_FOR_CLOCK) {
                                        command = lookup_command(shift_command);
                                        mm_switch_command(address, command);
                                }
@@ -278,28 +360,28 @@ void mm_pinchange_handler(void)
                return;
 
        switch(recstate) {
-       case IDLE:
+       case MM_IDLE:
                bitno = 0;
-               recstate = FIRST_FAST_SAMPLE;
+               recstate = MM_FIRST_FAST_SAMPLE;
                MM_TSTART_FAST;
                break;
-       case FIRST_SLOW_SAMPLE:
-               recstate = FAST_SAMPLE;
+       case MM_FIRST_SLOW_SAMPLE:
+               recstate = MM_FAST_SAMPLE;
                MM_TSTART_FAST;
                break;
-       case FAST_WAIT_FOR_CLOCK:
-               recstate = FAST_SAMPLE;
+       case MM_FAST_WAIT_FOR_CLOCK:
+               recstate = MM_FAST_SAMPLE;
                MM_TSTART_FAST;
                break;
-       case SLOW_WAIT_FOR_CLOCK:
-               recstate = SLOW_SAMPLE;
+       case MM_SLOW_WAIT_FOR_CLOCK:
+               recstate = MM_SLOW_SAMPLE;
                MM_TSTART_SLOW;
                break;
 
                /* Not expected */
-       case FIRST_FAST_SAMPLE:
-       case FAST_SAMPLE:
-       case SLOW_SAMPLE:
+       case MM_FIRST_FAST_SAMPLE:
+       case MM_FAST_SAMPLE:
+       case MM_SLOW_SAMPLE:
        default:
                break;
        }