#include <stdint.h>
#include <config/hardware.h>
-enum mm_recstate {
- MM_IDLE = 0,
- MM_FIRST_FAST_SAMPLE,
- MM_FIRST_SLOW_SAMPLE, /* If clock arrives, we stay on the fast path! */
- MM_FAST_SAMPLE,
- MM_FAST_WAIT_FOR_CLOCK,
- MM_SLOW_SAMPLE_DELAY,
- MM_SLOW_SAMPLE,
- MM_SLOW_WAIT_FOR_CLOCK_DELAY,
- MM_SLOW_WAIT_FOR_CLOCK,
-};
+#define MM_FLAVOR_DRIVE 0
+#define MM_FLAVOR_SWITCH 1
#ifdef MM_USE_REGISTER_VARS
uint8_t register shift_command asm("r2");
uint8_t register shift_function asm("r3");
uint8_t register shift_address asm("r4");
-uint8_t register recstate asm("r5");
-uint8_t register bitno asm("r6");
-uint8_t register sense_last asm("r8");
-uint8_t register time_h asm("r9");
-uint8_t register time_l asm("r10");
-uint8_t register bit_val asm("r11");
+uint8_t register mm_polarity asm("r5");
+uint8_t register mm_bitno asm("r6");
+uint8_t register mm_last_was_short asm("r8");
+uint8_t register mm_time_h asm("r9");
+uint8_t register mm_time_l asm("r10");
+uint8_t register mm_bit_val asm("r11");
+uint8_t register mm_flavor asm("r14");
static void inline __attribute((unused)) mm_init(void)
{
- bitno = 0;
- recstate = MM_IDLE;
- time_h = 0;
- bit_val = 23;
+ mm_bitno = 0;
+ mm_time_h = 0;
+ mm_bit_val = 23;
+ mm_polarity = 1;
+ mm_last_was_short = 0;
}
#else
#ifndef MM_USE_REGISTER_VARS
-static volatile uint8_t bitno = 0;
+static volatile uint8_t mm_bitno = 0;
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;
+uint8_t mm_time_h = 0;
+uint8_t mm_time_l = 0;
+uint8_t mm_bit_val = 23;
+static uint8_t mm_flavor;
+static uint8_t mm_polarity = 1;
+static uint8_t mm_last_was_short = 0;
#endif
{
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;
- return 9 * high + low;
+
+ /* retval = 9 * high + low; */
+ retval = high << 3;
+ retval += high;
+ retval += low;
+ return retval;
}
static uint8_t __attribute__((unused)) lookup_command(uint8_t mm_command)
* shift_address shift_function shift_command
*
* The bits 7 downto 2 of shift_function are ignored.
+ *
+ * First comes the C implementation of the shift routine.
+ * It is usually not used anymore, but I left it for
+ * illustration purposes.
+ * The real shift function is written in assembly and saves many instructions.
*/
-#define SAVE_ANOTHER_40_BYTES
-#ifdef SAVE_ANOTHER_40_BYTES
+#if 0
+void shift(uint8_t value)
+{
+ shift_address <<= 1;
+ if (shift_function & 2)
+ shift_address |= 1;
+ shift_function <<= 1;
+ if (shift_command & 0x80)
+ shift_function |= 1;
+ shift_command <<= 1;
+ if (value)
+ shift_command |= 1;
+}
+#else
void shift(uint8_t value)
{
"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)
- shift_address |= 1;
- shift_function <<= 1;
- if (shift_command & 0x80)
- shift_function |= 1;
- shift_command <<= 1;
- if (value)
- shift_command |= 1;
-}
#endif
-static volatile uint8_t mm_rec_tolerated_timeouts;
-
-#define MM_SLOW 0
-#define MM_FAST 1
-
-static uint8_t style;
-
-void mm_feed_bit(uint8_t bit, uint8_t seen_style)
+static 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;
uint8_t address;
uint8_t command;
-#ifdef MM_FILTER_REPEATED
- static uint8_t address_last = 0xff;
- static uint8_t function_last = 0xff;
- static uint8_t command_last = 0xff;
-#endif
-
- if (bitno == 0)
- style = seen_style;
+ if (mm_bitno == 0)
+ mm_flavor = seen_style;
else
- if (seen_style != style) {
- bitno = 0;
+ if (seen_style != mm_flavor) {
+ mm_bitno = 0;
return;
}
shift(bit);
- bitno++;
- if (bitno == 18) { /* Save first received word */
+ mm_bitno++;
+ if (mm_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 (mm_bitno == 36) {
if ((shift_command == shift_command_first) &&
(shift_address == shift_address_first) &&
(shift_function == shift_function_first)) {
-
-
-#ifdef MM_FILTER_REPEATED
- if ((shift_address != address_last) || (shift_command != command_last) ||
- shift_function != function_last) {
-#endif
- if (style == MM_SLOW) {
- address = lookup_decoder(shift_address);
- mm_switch_drive(address, shift_function, shift_command);
- } else {
- trigger();
-
- command = lookup_command(shift_command);
- mm_switch_command(address, command);
- }
- bitno = 0;
-#ifdef MM_FILTER_REPEATED
- }
- address_last = shift_address;
- function_last = shift_function;
- command_last = shift_command;
-#endif
+ address = lookup_decoder(shift_address);
+ if (mm_flavor == MM_FLAVOR_DRIVE) {
+ mm_switch_drive(address, shift_function,
+ shift_command);
+ } else {
+ trigger();
+ command = lookup_command(shift_command);
+ mm_switch_command(address, command);
+ }
}
}
}
-ISR(__vector_timer_extra) {
- //trigger();
-}
-
/*
* The timeout interrupt vector does nothing else
- * than incrementing the time_h round counter.
+ * than incrementing the mm_time_h round counter.
*
* It is written in naked assembly because we want to avoid pushing
* and popping of all upper registers.
"inc %[th] \n\t"
#else
"push r1 \n\t"
- "lds r1, time_h \n\t"
+ "lds r1, mm_time_h \n\t"
"inc r1 \n\t"
- "sts time_h, r1 \n\t"
+ "sts mm_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)
+ :: [th] "r" (mm_time_h)
#endif
);
}
#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))
+ :: [tl] "r" (mm_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"
+ "sts mm_time_l, r0 \n\t"
"pop r0 \n\t"
"rjmp __vector_pinchange \n\t"
:: [tmr] "I" (_SFR_IO_ADDR(TCNT0))
/* 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++;
+ mm_time_h++;
TIFR |= _BV(TOV0);
}
- bit_val = !MM_SENSE;
+ mm_bit_val = !MM_SENSE;
- uint16_t duration = time_h << 8;
- duration += time_l;
- time_h = 0;
+ uint16_t duration = mm_time_h << 8;
+ duration += mm_time_l;
+ mm_time_h = 0;
/*
* The nominal length of a bit cycle is 208 us.
#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;
-
if (D_MATCH(26, 4)) {
- if (last_was_short)
- mm_positive = bit_val;
- last_was_short = 1;
+ if (mm_last_was_short)
+ mm_polarity = mm_bit_val;
+ mm_last_was_short = 1;
- if (bit_val == mm_positive)
- mm_feed_bit(0, MM_SLOW);
+ if (mm_bit_val == mm_polarity)
+ mm_feed_bit(0, MM_FLAVOR_DRIVE);
} else {
- last_was_short = 0;
+ mm_last_was_short = 0;
}
- if (style == MM_SLOW) {
- if (duration > 4000) { /* Maerklin inter package timeout 2ms */
- bitno = 0;
+ if (mm_flavor == MM_FLAVOR_DRIVE) {
+ if (duration > 4096) { /* Maerklin inter package timeout 2ms */
+ mm_bitno = 0;
goto done;
}
} else {
if (duration > 2000) { /* Maerklin inter package timeout 1ms */
- bitno = 0;
+ mm_bitno = 0;
goto done;
}
}
- if (bit_val != mm_positive)
+ if (mm_bit_val != mm_polarity)
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);}
-
+ if (D_MATCH(182, 25)) mm_feed_bit(1, MM_FLAVOR_DRIVE);
+ if (D_MATCH(91, 17)) mm_feed_bit(1, MM_FLAVOR_SWITCH);
+ if (D_MATCH(13, 4)) mm_feed_bit(0, MM_FLAVOR_SWITCH);
done:
mm_switch_pinchange_callback();
}
+
void __attribute__((weak))mm_switch_pinchange_callback(void)
{
}
}
-
/******************************************************************************
* The end :-)
*/