All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mauro Carvalho Chehab <mchehab@redhat.com>
To: linux-media@vger.kernel.org,
	Linux Media Mailing List <linux-media@vger.kernel.org>
Subject: [PATCH 26/26] V4L/DVB: ir-rc5-decoder: fix state machine
Date: Tue, 6 Apr 2010 15:18:00 -0300	[thread overview]
Message-ID: <20100406151800.09f3c466@pedra> (raw)
In-Reply-To: <cover.1270577768.git.mchehab@redhat.com>

Reimplement the RC-5 decoder state machine. Code is now clear, and works
properly. It is also simpler than the previous implementations.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c
index 4fb3ce4..a62277b 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/IR/ir-rc5-decoder.c
@@ -15,19 +15,17 @@
 /*
  * This code only handles 14 bits RC-5 protocols. There are other variants
  * that use a different number of bits. This is currently unsupported
+ * It considers a carrier of 36 kHz, with a total of 14 bits, where
+ * the first two bits are start bits, and a third one is a filing bit
  */
 
 #include <media/ir-core.h>
 
+static unsigned int ir_rc5_remote_gap = 888888;
+
 #define RC5_NBITS		14
-#define RC5_HALFBIT		888888 /* ns */
-#define RC5_BIT			(RC5_HALFBIT * 2)
-#define RC5_DURATION		(RC5_BIT * RC5_NBITS)
-
-#define is_rc5_halfbit(nsec) ((ev->delta.tv_nsec >= RC5_HALFBIT / 2) &&	   \
-		      (ev->delta.tv_nsec < RC5_HALFBIT + RC5_HALFBIT / 2))
-
-#define n_half(nsec) ((ev->delta.tv_nsec + RC5_HALFBIT / 2) / RC5_HALFBIT)
+#define RC5_BIT			(ir_rc5_remote_gap * 2)
+#define RC5_DURATION		(ir_rc5_remote_gap * RC5_NBITS)
 
 /* Used to register rc5_decoder clients */
 static LIST_HEAD(decoder_list);
@@ -35,19 +33,8 @@ static spinlock_t decoder_lock;
 
 enum rc5_state {
 	STATE_INACTIVE,
-	STATE_START2_SPACE,
-	STATE_START2_MARK,
 	STATE_MARKSPACE,
-	STATE_TRAILER_MARK,
-};
-
-static char *st_name[] = {
-	"Inactive",
-	"start2 sapce",
-	"start2 mark",
-	"mark",
-	"space",
-	"trailer"
+	STATE_TRAILER,
 };
 
 struct rc5_code {
@@ -63,8 +50,7 @@ struct decoder_data {
 	/* State machine control */
 	enum rc5_state		state;
 	struct rc5_code		rc5_code;
-	unsigned		n_half;
-	unsigned		count;
+	unsigned		code, elapsed, last_bit, last_code;
 };
 
 
@@ -147,7 +133,7 @@ static int ir_rc5_decode(struct input_dev *input_dev,
 {
 	struct decoder_data *data;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	int bit, last_bit, n_half;
+	int is_pulse, scancode, delta, toggle;
 
 	data = get_decoder_data(ir_dev);
 	if (!data)
@@ -156,122 +142,79 @@ static int ir_rc5_decode(struct input_dev *input_dev,
 	if (!data->enabled)
 		return 0;
 
-	/* Except for the initial event, what matters is the previous bit */
-	bit = (ev->type & IR_PULSE) ? 1 : 0;
+	delta = DIV_ROUND_CLOSEST(ev->delta.tv_nsec, ir_rc5_remote_gap);
 
-	last_bit = !bit;
-
-	/* Discards spurious space last_bits when inactive */
+	/* The duration time refers to the last bit time */
+	is_pulse = (ev->type & IR_PULSE) ? 1 : 0;
 
 	/* Very long delays are considered as start events */
-	if (ev->delta.tv_nsec > RC5_DURATION + RC5_HALFBIT / 2)
-		data->state = STATE_INACTIVE;
-
-	if (ev->type & IR_START_EVENT)
+	if (delta > RC5_DURATION || (ev->type & IR_START_EVENT))
 		data->state = STATE_INACTIVE;
 
 	switch (data->state) {
 	case STATE_INACTIVE:
-IR_dprintk(1, "currently inative. Received bit (%s) @%luus\n",
-	last_bit ? "pulse" : "space",
-	(ev->delta.tv_nsec + 500) / 1000);
+	IR_dprintk(2, "currently inative. Start bit (%s) @%uus\n",
+		   is_pulse ? "pulse" : "space",
+		   (unsigned)(ev->delta.tv_nsec + 500) / 1000);
 
 		/* Discards the initial start space */
-		if (bit)
-			return 0;
-		data->count = 0;
-		data->n_half = 0;
-		memset (&data->rc5_code, 0, sizeof(data->rc5_code));
-
-		data->state = STATE_START2_SPACE;
-		return 0;
-	case STATE_START2_SPACE:
-		if (last_bit)
+		if (!is_pulse)
 			goto err;
-		if (!is_rc5_halfbit(ev->delta.tv_nsec))
-			goto err;
-		data->state = STATE_START2_MARK;
-		return 0;
-	case STATE_START2_MARK:
-		if (!last_bit)
-			goto err;
-
-		if (!is_rc5_halfbit(ev->delta.tv_nsec))
-			goto err;
-
+		data->code = 1;
+		data->last_bit = 1;
+		data->elapsed = 0;
+		memset(&data->rc5_code, 0, sizeof(data->rc5_code));
 		data->state = STATE_MARKSPACE;
 		return 0;
 	case STATE_MARKSPACE:
-		n_half = n_half(ev->delta.tv_nsec);
-		if (n_half < 1 || n_half > 3) {
-			IR_dprintk(1, "Decode failed at %d-th bit (%s) @%luus\n",
-				data->count,
-				last_bit ? "pulse" : "space",
-				(ev->delta.tv_nsec + 500) / 1000);
-printk("%d halves\n", n_half);
-			goto err2;
-		}
-		data->n_half += n_half;
+		if (delta != 1)
+			data->last_bit = data->last_bit ? 0 : 1;
 
-		if (!last_bit)
+		data->elapsed += delta;
+
+		if ((data->elapsed % 2) == 1)
 			return 0;
 
-		/* Got one complete mark/space cycle */
+		data->code <<= 1;
+		data->code |= data->last_bit;
 
-		bit = ((data->count + 1) * 2)/ data->n_half;
+		/* Fill the 2 unused bits at the command with 0 */
+		if (data->elapsed / 2 == 6)
+			data->code <<= 2;
 
-printk("%d halves, %d bits\n", n_half, bit);
+		if (data->elapsed >= (RC5_NBITS - 1) * 2) {
+			scancode = data->code;
 
-#if 1 /* SANITY check - while testing the decoder */
-		if (bit > 1) {
-			IR_dprintk(1, "Decoder HAS failed at %d-th bit (%s) @%luus\n",
-				data->count,
-				last_bit ? "pulse" : "space",
-				(ev->delta.tv_nsec + 500) / 1000);
+			/* Check for the start bits */
+			if ((scancode & 0xc000) != 0xc000) {
+				IR_dprintk(1, "Code 0x%04x doesn't have two start bits. It is not RC-5\n", scancode);
+				goto err;
+			}
 
-			goto err2;
-		}
-#endif
-		/* Ok, we've got a valid bit. proccess it */
-		if (bit) {
-			int shift = data->count;
+			toggle = (scancode & 0x2000) ? 1 : 0;
 
-			/*
-			 * RC-5 transmit bytes on this temporal order:
-			 * address | not address | command | not command
-			 */
-			if (shift < 8) {
-				data->rc5_code.address |= 1 << shift;
+			if (scancode == data->last_code) {
+				IR_dprintk(1, "RC-5 repeat\n");
+				ir_repeat(input_dev);
 			} else {
-				data->rc5_code.command |= 1 << (shift - 8);
+				data->last_code = scancode;
+				scancode &= 0x1fff;
+				IR_dprintk(1, "RC-5 scancode 0x%04x\n", scancode);
+
+				ir_keydown(input_dev, scancode, 0);
 			}
-		}
-		IR_dprintk(1, "RC-5: bit #%d: %d (%d)\n",
-				data->count, bit, data->n_half);
-		if (++data->count >= RC5_NBITS) {
-			u32 scancode;
-			scancode = data->rc5_code.address << 8 |
-					data->rc5_code.command;
-			IR_dprintk(1, "RC-5 scancode 0x%04x\n", scancode);
-
-			ir_keydown(input_dev, scancode, 0);
-
-			data->state = STATE_TRAILER_MARK;
+			data->state = STATE_TRAILER;
 		}
 		return 0;
-	case STATE_TRAILER_MARK:
-		if (!last_bit)
-			goto err;
+	case STATE_TRAILER:
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
 err:
-	IR_dprintk(1, "RC-5 decoded failed at state %s (%s) @ %luus\n",
-		   st_name[data->state],
-		   bit ? "pulse" : "space",
+	IR_dprintk(1, "RC-5 decoded failed at %s @ %luus\n",
+		   is_pulse ? "pulse" : "space",
 		   (ev->delta.tv_nsec + 500) / 1000);
-err2:
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
-- 
1.6.6.1


  parent reply	other threads:[~2010-04-06 18:18 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <cover.1270577768.git.mchehab@redhat.com>
2010-04-06 18:18 ` [PATCH 23/26] V4L/DVB: ir-core: move rc map code to rc-map.h Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 25/26] V4L/DVB: re-add enable/disable check to the IR decoders Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 22/26] V4L-DVB: ir-core: remove the ancillary buffer Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 24/26] V4L/DVB: ir-core: Add support for badly-implemented hardware decoders Mauro Carvalho Chehab
2010-04-06 18:18 ` Mauro Carvalho Chehab [this message]
2010-04-06 18:18 ` [PATCH 13/26] V4L/DVB: saa7134: Add support for both positive and negative edge IRQ Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 20/26] V4L-DVB: ir-rc5-decoder: Add a decoder for RC-5 IR protocol Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 18/26] V4L/DVB: ir-nec-decoder: Reimplement the entire decoder Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 21/26] V4L/DVB: cx88: don't handle IR on Pixelview too fast Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 19/26] ir-nec-decoder: Cleanups Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 15/26] V4L/DVB: ir-core: re-add some debug functions for keytable changes Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 17/26] V4L/DVB: Convert drivers/media/dvb/ttpci/budget-ci.c to use ir-core Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 12/26] V4L/DVB: saa7134: Fix IRQ2 bit names for the register map Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 11/26] V4L/DVB: ir-common: remove keymap tables from the module Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 10/26] V4L/DVB: ir-core: Make use of the new IR keymap modules Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 14/26] V4L/DVB: drivers/media/IR - improve keytable code Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 05/26] V4L/DVB: ir-common: Use macros to define the keytables Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 08/26] V4L/DVB: Break Remote Controller keymaps into modules Mauro Carvalho Chehab
2010-04-10 12:27   ` Andy Walls
2010-04-10 16:06     ` Mauro Carvalho Chehab
2010-04-10 17:26       ` Andy Walls
2010-04-06 18:18 ` [PATCH 04/26] V4L/DVB: rename all *_rc_keys to ir_codes_*_nec_table Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 07/26] V4L/DVB: ir-core: Add support for RC map code register Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 09/26] V4L/DVB: ir: prepare IR code for a parameter change at register function Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 06/26] V4L/DVB: ir-common: move IR tables from ir-keymaps.c to a separate file Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 02/26] V4L/DVB: ir-common: re-order keytables by name and remove duplicates Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 03/26] V4L/DVB: IR: use IR_KEYTABLE where an IR table is needed Mauro Carvalho Chehab
2010-04-06 18:18 ` [PATCH 01/26] V4L/DVB: ir-common: Use a function to declare an IR table Mauro Carvalho Chehab
2010-04-06 19:13 ` [PATCH 16/26] V4L/DVB: ir-core: improve keyup/keydown logic Mauro Carvalho Chehab

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100406151800.09f3c466@pedra \
    --to=mchehab@redhat.com \
    --cc=linux-media@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.