trennfix/sw: Added smokefix, further modularized the mm decoder
[eisenbahn.git] / trennfix / sw / mm / src / mm_switch.c
index 35016fcd4769d6826847d12ef697b992bdfcd7e0..a960355298ba8aac8f1354f862eebf1e34d70144 100644 (file)
@@ -35,7 +35,7 @@
 
 #include <config/hardware.h>
 #include <mm/mm_switch.h>
-
+#include <mm/mm_decode.h>
 
 /*
  *
 #error Missing needed MM_... macro!
 #endif
 
-/*
- *    Private global variables
- */
+#ifndef MM_QUEUE_DEPTH
+#define MM_QUEUE_DEPTH 8
+#endif
 
-enum recmode {
-       INIT,
-       ARMED,
-       MM_SLOW,
-       MM_FAST,
-       DCC,
-};
-enum recmode recmode = INIT;
+
+       /*
+        * The nominal length of a bit cycle is 208 us.
+        * This consists of 8 parts, each 26 us:
+        * 1 d d d d d d 0
+        *
+        * That means that the 1 pulse is 7 * 26 = 182us
+        * and the short pulse is 1 * 26 = 26us.
+        *
+        * Reality seems to look not as that exact. I measure
+        * 26us for the clock pulse, but 196 for the long pulse.
+        *
+        * Keep in mind: Time is counted in 500ns steps.
+        *
+        */
+#define IN_RANGE(duration, lower, upper)               \
+       ((duration >= (2 * lower)                       \
+         && (duration <= (2 * upper))))
+
+#define MM_FAST_SHORT(duration) IN_RANGE(duration,   7,  18)
+#define MM_FAST_LONG(duration)  IN_RANGE(duration,  70, 130)
+#define MM_FAST_GAP(duration)   IN_RANGE(duration, 500, 1100)
+
+#define MM_SLOW_SHORT(duration) IN_RANGE(duration,   18,   35)
+#define MM_SLOW_LONG(duration)  IN_RANGE(duration,  150,  210)
+#define MM_SLOW_GAP(duration)   IN_RANGE(duration, 1000, 2000)
+
+#define MM_SUFFICIENT_IDLE(duration) (duration > 800)
+
+
+
+static enum mm_recmode recmode = __MM_INIT;
+
+#ifdef MM_USE_QUEUE
+static uint8_t queue_wpos = 0;
+static uint8_t queue_rpos = 0;
+static struct mm_command queue[MM_QUEUE_DEPTH];
+#endif
 
 #ifndef MM_USE_REGISTER_VARS
 
@@ -73,126 +103,6 @@ static uint8_t mm_polarity = 1;
 
 #endif
 
-/*
- * Lookup trinary nibble
- *
- * This was implemented using a switch statement before.
- * Changing the lookup to a table did only add two bytes
- * of memory and saved ca. 50 bytes program memory.
- */
-static const uint8_t nibble_table[16]={
-       [0x0] = 0,
-       [0xc] = 1,
-       [0x8] = 2,
-       [0x3] = 3,
-       [0xf] = 4,
-       [0xb] = 5,
-       [0x2] = 6,
-       [0xe] = 7,
-       [0xa] = 8
-};
-#define lookup_nibble(nibble) nibble_table[nibble & 0xf]
-static uint8_t __attribute__((unused)) lookup_decoder(uint8_t mm_byte)
-{
-       uint8_t low;
-       uint8_t high;
-       uint8_t retval;
-
-       if (mm_byte == 0)
-               return 80;
-       low = lookup_nibble(mm_byte >> 4);
-       high = lookup_nibble(mm_byte & 0xf);
-       if (!low)
-               return 0;
-
-       /*      retval = 9 * high + low; */
-       retval = high << 3;
-       retval += high;
-       retval += low;
-       return retval;
-}
-
-static uint8_t __attribute__((unused)) lookup_command(uint8_t mm_command)
-{
-       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
@@ -205,7 +115,7 @@ static uint8_t __attribute__((unused)) lookup_command(uint8_t mm_command)
  * The real shift function is written in assembly and saves many instructions.
  */
 #if 0
-void shift(uint8_t value)
+static void shift(uint8_t value)
 {
        shift_address <<= 1;
        if (shift_function & 2)
@@ -219,7 +129,7 @@ void shift(uint8_t value)
 }
 #else
 
-void shift(uint8_t value)
+static void shift(uint8_t value)
 {
        asm("ror %[val]                 ; Shift value right into carry\n\t"
            "rol %[cmd]                 ; and shift to command reg\n\t"
@@ -242,7 +152,6 @@ static void mm_feed_bit(uint8_t bit)
        static volatile uint8_t shift_function_first;
        static volatile uint8_t shift_address_first;
        uint8_t address;
-       uint8_t command;
 
        shift(bit);
        mm_bitno++;
@@ -251,27 +160,48 @@ static void mm_feed_bit(uint8_t bit)
                shift_address_first  = shift_address;
                shift_function_first = shift_function;
                shift_command_first  = shift_command;
-       } 
+       }
 
        if (mm_bitno == 36) {
-
                if ((shift_command == shift_command_first) &&
                    (shift_address == shift_address_first) &&
                    (shift_function == shift_function_first)) {
-                       address = lookup_decoder(shift_address);
-                       if (recmode == MM_SLOW) {
-                               trigger();
 
-                               mm_switch_drive(address, shift_function,
-                                               shift_command);
+#ifdef MM_USE_CALLBACK
+                       address = mm_lookup_decoder(shift_address);
+                       if (recmode == MM_SLOW) {
+                               mm_drive_cb(address, shift_function,
+                                           shift_command);
                        } else {
-                               command = lookup_command(shift_command);
-                               mm_switch_command(address, command);
-                       }                               
+                               mm_key_cb(address, shift_function, shift_command);
+                       }
+#endif
+
+#ifdef MM_USE_QUEUE
+                       queue[queue_wpos].recmode  = recmode;
+                       queue[queue_wpos].address  = shift_address;
+                       queue[queue_wpos].function = shift_function;
+                       queue[queue_wpos].command  = shift_command;
+                       queue_wpos = (queue_wpos + 1) % MM_QUEUE_DEPTH;
+#endif
                }
-               
        }
 }
+#ifdef MM_USE_QUEUE
+
+struct mm_command *mm_get(void)
+{
+       struct mm_command *result = NULL;
+       uint8_t sreg_bak = SREG;
+       cli();
+       if (queue_rpos != queue_wpos) {
+               result = &queue[queue_rpos];
+               queue_rpos = (queue_rpos + 1) % MM_QUEUE_DEPTH;
+       }
+       SREG = sreg_bak;
+       return result;
+}
+#endif
 
 /*
  *  The timeout interrupt vector does nothing else
@@ -331,14 +261,14 @@ void __attribute__((naked)) PCINT0_vect(void)
            );
 #endif
 }
-       
+
 /* Pin change interrupt vector, here we have a bit more time */
 ISR(__vector_pinchange){
        uint16_t duration;
 
        /* First kill off that timer */
        MM_TSTART;  /* Restart timer */
-       
+
        /* Account for not yet handled timer overflow */
        TIFR |= _BV(TOV0);
 
@@ -347,131 +277,81 @@ ISR(__vector_pinchange){
        mm_bit_val = MM_SENSE;
        mm_time_h = 0;
 
-       /*
-        * The nominal length of a bit cycle is 208 us.
-        * This consists of 8 parts, each 26 us:
-        * 1 d d d d d d 0
-        *
-        * That means that the 1 pulse is 7 * 26 = 182us
-        * and the short pulse is 1 * 26 = 26us.
-        *
-        * Reality seems to look not as that exact. I measure
-        * 26us for the clock pulse, but 196 for the long pulse.
-        *
-        * Keep in mind: Time is counted in 500ns steps.
-        *
-        */
-#define D_MATCH(d, v) ((duration > (d * 2 - 2 * v)) && (duration < (d * 2 + 2 * v)))
-
-       switch(recmode) {
-       case INIT:
-       default:
-               break;
-       case ARMED:
-               /* Maerklin only interested when signal is 1 */
-               if (mm_bit_val == mm_polarity) {
-                       /* Fast short MM pulse (logical 0) */
-                       if (D_MATCH(13, 4)){
-                               recmode = MM_FAST;
+       if (recmode != MM_SLOW) {
+               /* Fast short MM pulse */
+               if (MM_FAST_SHORT(duration)){
+                       recmode = MM_FAST;
+                       if (mm_bit_val == mm_polarity)
                                mm_feed_bit(0);
-                               goto done;
-                       }
-                       
-                       /* Slow short MM pulse (logical 0) */
-                       if (D_MATCH(26, 4)) {
-                               recmode = MM_SLOW;
-                               mm_feed_bit(0);
-                               goto done;
-                       }
-
-                       /* Fast long MM pulse (logical 1) */
-                       if (D_MATCH(91, 17)) {
-                               recmode = MM_FAST;
-                               mm_feed_bit(1);
-                               goto done;
-                       }
-
-                       /* Slow long MM pulse (logical 1) */
-                       if (D_MATCH(182, 25)) {
-                               recmode = MM_SLOW;
+                       goto done;
+               }
+               /* Fast long MM pulse */
+               if (MM_FAST_LONG(duration)) {
+                       recmode = MM_FAST;
+                       if (mm_bit_val == mm_polarity)
                                mm_feed_bit(1);
+                       goto done;
+               }
+       } else {
+               /* Accepted slow inter package gap */
+               if (MM_SLOW_GAP(duration))
+                       if (mm_bit_val != mm_polarity)
                                goto done;
-                       }
-               } 
-               break;
+       }
 
-       case MM_FAST:
-               if (mm_bit_val == mm_polarity) {
+       if (recmode != MM_FAST) {
 
-                       /* Fast short MM pulse (logical 0) */
-                       if (D_MATCH(13, 4)){
+               /* Slow short MM pulse */
+               if (MM_SLOW_SHORT(duration)) {
+                       recmode = MM_SLOW;
+                       if (mm_bit_val == mm_polarity)
                                mm_feed_bit(0);
-                               goto done;
-                       }
-                       /* Fast long MM pulse (logical 1) */
-                       if (D_MATCH(91, 17)) {
-                               mm_feed_bit(1);
-                               goto done;
-                       }
-               } else {
-                       if (D_MATCH(13, 4))
-                               goto done;
-                       if (D_MATCH(91, 17))
-                               goto done;
-                       
-                       if (D_MATCH(700, 200))
-                               goto done;
+                       goto done;
                }
-               break;
-                       
-       case MM_SLOW:
-               if (mm_bit_val == mm_polarity) {
-                       /* Slow short MM pulse (logical 0) */
-                       if (D_MATCH(26, 4)) {
-                               mm_feed_bit(0);
-                               goto done;
-                       }
-                       /* Slow long MM pulse (logical 1) */
-                       if (D_MATCH(182, 40)) {
+               /* Slow long MM pulse */
+               if (MM_SLOW_LONG(duration)) {
+                       recmode = MM_SLOW;
+                       if (mm_bit_val == mm_polarity)
                                mm_feed_bit(1);
-                               goto done;
-                       }
-               } else {
-                       if (D_MATCH(26, 4))
-                               goto done;
-                       if (D_MATCH(182, 40))
-                               goto done;
-                       
-                       /* Accepted inter package gap */
-                       if (D_MATCH(1400, 400))
+                       goto done;
+               }
+       } else {
+               /* Accepted fast interpackage gap */
+               if (MM_FAST_GAP(duration)) {
+                       if (mm_bit_val != mm_polarity)
                                goto done;
                }
-               break;
        }
 
-       /* 
+       /*
         * If we have reached here, our pulse comes in somehow unexpected.
         * We kill of everything by re-arming the state machine.
         */
        /* Start over receiver */
        mm_bitno = 0;
-       mm_polarity = !mm_bit_val;
-       recmode = ARMED;
+
+       if (MM_SUFFICIENT_IDLE(duration)) {
+               recmode = __MM_ARMED;
+               mm_polarity = !mm_bit_val;
+       } else {
+               recmode = __MM_INIT;
+       }
  done:
-       mm_switch_pinchange_callback();
+       mm_pinchange_callback();
  }
 
 
-void __attribute__((weak))mm_switch_pinchange_callback(void)
+void __attribute__((weak))mm_pinchange_callback(void)
 {
 }
 
-void __attribute__((weak))mm_switch_drive(uint8_t decoder, uint8_t function,
+void __attribute__((weak))mm_drive_cb(uint8_t decoder, uint8_t function,
                                          uint8_t command)
 {
 }
 
-void __attribute__((weak))mm_switch_command(uint8_t address, uint8_t command)
+void __attribute__((weak))mm_key_cb(uint8_t address,  uint8_t function,
+                                   uint8_t command)
 {
 }