#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
#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
* 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)
}
#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"
static volatile uint8_t shift_function_first;
static volatile uint8_t shift_address_first;
uint8_t address;
- uint8_t command;
shift(bit);
mm_bitno++;
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
);
#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);
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)
{
}