* 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,
-};
/*
*
/*
* 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
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)
if (value)
shift_command |= 1;
}
+#endif
+
ISR(MM_TIMER_INT_VECT) {
static uint8_t tolerated_timeouts = 0;
#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;
}
default:
MM_TSTOP;
- recstate = IDLE;
+ recstate = MM_IDLE;
return;
}
#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);
}
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;
}