trennfix/sw: Temporary first working time measurement method
[eisenbahn.git] / trennfix / sw / mm / src / mm_switch.c
index 4bda4730a30e4d57c1a7f9e4e369edb5b7a86917..34819e5d626071098f1d6ca1660163799f15eb0d 100644 (file)
@@ -59,6 +59,10 @@ static uint8_t shift_command;
 static uint8_t shift_function;
 static uint8_t shift_address;
 static  enum mm_recstate recstate = MM_IDLE;
+static uint8_t sense_last = 23;
+uint8_t time_h = 0;
+uint8_t time_l = 0;
+uint8_t bit_val = 23;
 
 #endif
 
@@ -82,7 +86,7 @@ static const uint8_t nibble_table[16]={
 };
 #define lookup_nibble(nibble) nibble_table[nibble & 0xf]
  
-static uint8_t lookup_decoder(uint8_t mm_byte)
+static uint8_t __attribute__((unused)) lookup_decoder(uint8_t mm_byte)
 {
        uint8_t low;
        uint8_t high;
@@ -95,7 +99,7 @@ static uint8_t lookup_decoder(uint8_t mm_byte)
        return 9 * high + low;
 }
 
-static uint8_t lookup_command(uint8_t mm_command)
+static uint8_t __attribute__((unused)) lookup_command(uint8_t mm_command)
 {
        uint8_t res;
        /*
@@ -175,7 +179,6 @@ static uint8_t lookup_command(uint8_t mm_command)
        return res;
 }
 
-
 /* We will shift from right to left.
  * XXXXXXXX        XX          XXXXXXXX
  * shift_address   shift_function  shift_command
@@ -219,9 +222,13 @@ void shift(uint8_t value)
 
 static volatile uint8_t mm_rec_tolerated_timeouts;
 
+#define MM_SLOW 0
+#define MM_FAST 1
 
-ISR(MM_TIMER_INT_VECT) {
+static uint8_t style;
 
+void mm_feed_bit(uint8_t bit, uint8_t seen_style)
+{
        static volatile uint8_t shift_command_first;
        static volatile uint8_t shift_function_first;
        static volatile uint8_t shift_address_first;
@@ -233,63 +240,26 @@ ISR(MM_TIMER_INT_VECT) {
        static uint8_t function_last = 0xff;
        static uint8_t command_last = 0xff;
 #endif
-       MM_TSTART;
-
-       switch(recstate) {
-       case MM_FIRST_FAST_SAMPLE:
-               recstate = MM_FIRST_SLOW_SAMPLE;
-               break;
-
-       case MM_FIRST_SLOW_SAMPLE:
-               bitno = 0;
-
-       case MM_SLOW_SAMPLE:
-               recstate = MM_SLOW_WAIT_FOR_CLOCK_DELAY;
-               break;
-
-       case MM_SLOW_WAIT_FOR_CLOCK_DELAY:
-               recstate = MM_SLOW_WAIT_FOR_CLOCK;
-               return;
-
-       case MM_FAST_SAMPLE:
-               recstate = MM_FAST_WAIT_FOR_CLOCK;
-               break;
-
-       case MM_FAST_WAIT_FOR_CLOCK: /* A timeout! */
-               if (mm_rec_tolerated_timeouts)
-                       mm_rec_tolerated_timeouts--;
-               else
-                       recstate = MM_IDLE;
-               return;
-
-       case MM_SLOW_SAMPLE_DELAY:
-               recstate = MM_SLOW_SAMPLE;
-               return;
-
-       case MM_SLOW_WAIT_FOR_CLOCK:
-               if (mm_rec_tolerated_timeouts) {
-                       mm_rec_tolerated_timeouts--;
-                       recstate = MM_SLOW_WAIT_FOR_CLOCK_DELAY;
+
+       if (bitno == 0)
+               style = seen_style;
+       else
+               if (seen_style != style) {
+                       bitno = 0;
                        return;
                }
-       default:
-               recstate = MM_IDLE;
-       case MM_IDLE:
-               return;
-       }
-
-       shift(MM_SENSE);
+                       
+       shift(bit);
        bitno++;
-
        if (bitno == 18) { /* Save first received word */
                shift_address_first  = shift_address;
                shift_function_first = shift_function;
                shift_command_first  = shift_command;
                mm_rec_tolerated_timeouts = 18;
-
        } 
 
        if (bitno == 36) {
+
                if ((shift_command == shift_command_first) &&
                    (shift_address == shift_address_first) &&
                    (shift_function == shift_function_first)) {
@@ -299,14 +269,16 @@ ISR(MM_TIMER_INT_VECT) {
                        if ((shift_address != address_last) || (shift_command != command_last) ||
                            shift_function != function_last) {
 #endif
-                               address = lookup_decoder(shift_address);
-                               if (recstate == MM_SLOW_WAIT_FOR_CLOCK_DELAY) {
+                               if (style == MM_SLOW) {
+                                       address = lookup_decoder(shift_address);
                                        mm_switch_drive(address, shift_function, shift_command);
-                               } else if (recstate == MM_FAST_WAIT_FOR_CLOCK) {
+                               } else {
+                                       trigger();
+
                                        command = lookup_command(shift_command);
                                        mm_switch_command(address, command);
-                               }
-                               recstate = MM_IDLE;
+                               }                               
+                               bitno = 0;
 #ifdef MM_FILTER_REPEATED
                        }
                        address_last   = shift_address;
@@ -318,82 +290,132 @@ ISR(MM_TIMER_INT_VECT) {
        }
 }
 
-//void __attribute((weak)) mm_switch_drive(uint8_t address, uint8_t function, uint8_t command);
+ISR(__vector_timer_extra) {
+       //trigger();
+}
 
-ISR(BADISR_vect)
+/*
+ *  The timeout interrupt vector does nothing else
+ *  than incrementing the time_h round counter.
+ *
+ *  It is written in naked assembly because we want to avoid pushing
+ *  and popping of all upper registers.
+ */
+void __attribute__((naked)) MM_TIMER_INT_VECT(void)
 {
-       while(1) {
-               /*
-               setpin(PIN_LED, 1);
-               _delay_ms(30);
-               setpin(PIN_LED, 0);
-               _delay_ms(30);
-               setpin(PIN_LED, 1);
-               _delay_ms(30);
-               setpin(PIN_LED, 0);
-               _delay_ms(2000);
-               */
-       }
+       asm("push r0       ; save r0 \n\t"
+           "in r0, __SREG__    \n\t"
+#ifdef MM_USE_REGISTER_VARS
+           "inc %[th]          \n\t"
+#else
+           "push r1            \n\t"
+           "lds r1, time_h     \n\t"
+           "inc r1             \n\t"
+           "sts  time_h, r1    \n\t"
+           "pop r1             \n\t"
+#endif
+           "out __SREG__, r0    \n\t"
+           "pop r0              \n\t"
+           //      "rjmp __vector_timer_extra \n\t"
+           "reti                \n\t"
+#ifdef MM_USE_REGISTER_VARS
+           :: [th] "r" (time_h)
+#endif
+           );
 }
 
-ISR(TIM0_OVF_vect)
+/*
+ * Another naked interrupt trampoline
+ *
+ * Here we first save the timer value as fast as possible, then we jump (!)
+ * into the "official" interrupt handler with all its decorations.
+ */
+void __attribute__((naked)) PCINT0_vect(void)
 {
-       return;
-       while(1) {
-               setpin(PIN_LED, 1);
-               _delay_ms(30);
-               setpin(PIN_LED, 0);
-               _delay_ms(300);
+#ifdef MM_USE_REGISTER_VARS
+       asm("in %[tl], %[tmr]   \n\t"
+           "rjmp __vector_pinchange  \n\t"
+           :: [tl] "r" (time_l), [tmr] "I" (_SFR_IO_ADDR(TCNT0))
+           );
+#else
+       asm("push r0         \n\t"
+           "in r0, %[tmr]   \n\t"
+           "sts time_l, r0  \n\t"
+           "pop r0          \n\t"
+           "rjmp __vector_pinchange  \n\t"
+           :: [tmr] "I" (_SFR_IO_ADDR(TCNT0))
+           );
+#endif
+}
+
+/* Pin change interrupt vector, here we have a bit more time */
+ISR(__vector_pinchange){
+       /* First kill off that timer */
+
+       MM_TSTART;  /* Restart timer */
+       
+       /* Account for not yet handled timer overflow */
+       if (TIFR & _BV(TOV0)) {
+               time_h++;
+               TIFR |= _BV(TOV0);
        }
        
-}
+       bit_val = !MM_SENSE;
+
+       uint16_t duration = time_h << 8;
+       duration += time_l;
+       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.
+        *
+        */
+
+#define D_MATCH(d, v) ((duration > (d * 2 - 2 * v)) && (duration < (d * 2 + 2 * v)))
+
+       static uint8_t mm_positive = 1;
+       static uint8_t last_was_short = 0;
 
-uint8_t register sense_last asm("r9");
+       if (D_MATCH(26, 4)) {
+               if (last_was_short)
+                       mm_positive = bit_val;
+               last_was_short = 1;
 
+               if (bit_val == mm_positive)
+                       mm_feed_bit(0, MM_SLOW);
+       } else {
+               last_was_short = 0;
+       }
 
-/* Pin change interrupt vector */
-ISR(PCINT0_vect){
-       static uint8_t sense_last;
-       if (MM_SENSE && !sense_last) {
-               MM_TSTART;
-               switch(recstate) {
-               case MM_IDLE:
+       if (style == MM_SLOW) {
+               if (duration > 4000) { /* Maerklin inter package timeout 2ms */
                        bitno = 0;
-                       recstate = MM_FIRST_FAST_SAMPLE;
-                       break;
-
-               case MM_FIRST_SLOW_SAMPLE:
-                       recstate = MM_FAST_SAMPLE;
-                       break;
-
-               case MM_FAST_WAIT_FOR_CLOCK:
-                       recstate = MM_FAST_SAMPLE;
-                       mm_rec_tolerated_timeouts = 0;
-                       break;
-
-               case MM_SLOW_WAIT_FOR_CLOCK_DELAY: /* If clock comes early */
-                       recstate = MM_SLOW_SAMPLE_DELAY;
-                       break;
-
-               case MM_SLOW_WAIT_FOR_CLOCK:
-                       recstate = MM_SLOW_SAMPLE_DELAY;
-                       mm_rec_tolerated_timeouts = 0;
-                       break;
-                       
-               case MM_SLOW_SAMPLE_DELAY:
-                       recstate = MM_SLOW_SAMPLE;
-                       break;
-                       
-                       /* Not expected */
-               case MM_FIRST_FAST_SAMPLE:
-               case MM_FAST_SAMPLE:
-               case MM_SLOW_SAMPLE:
-                       recstate = MM_IDLE;
-               default:
-                       break;
+                       goto done;
+               }
+       } else {
+               if (duration > 2000) { /* Maerklin inter package timeout 1ms */
+                       bitno = 0;
+                       goto done;
                }
        }
-       sense_last = MM_SENSE;
+       
+       if (bit_val != mm_positive)
+               goto done;
+
+       if (D_MATCH(182, 25)) mm_feed_bit(1, MM_SLOW);
+       
+       if (D_MATCH(91, 17)) {mm_feed_bit(1, MM_FAST);}
+       if (D_MATCH(13, 4)) {mm_feed_bit(0, MM_FAST);}
+
+ done:
        mm_switch_pinchange_callback();
  }
 
@@ -411,9 +433,7 @@ void __attribute__((weak))mm_switch_command(uint8_t address, uint8_t command)
 }
 
 
+
 /******************************************************************************
  *                        The end :-)
  */
-
-
-