[media] rc: rc-ir-raw: Add Manchester encoder (phase encoder) helper
authorAntti Seppälä <a.seppala@gmail.com>
Tue, 31 Mar 2015 17:48:07 +0000 (14:48 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Thu, 14 May 2015 17:29:14 +0000 (14:29 -0300)
Adding a simple Manchester encoder to rc-core.
Manchester coding is used by at least RC-5 and RC-6 protocols and their
variants.

Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
Signed-off-by: James Hogan <james@albanarts.com>
Cc: David Härdeman <david@hardeman.nu>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/rc/rc-core-priv.h
drivers/media/rc/rc-ir-raw.c

index 122c25fe91e042b148c48a57242a6e92f23cd6c2..5266ecc73f0594dc53c63bddebdb68712851f9b9 100644 (file)
@@ -152,6 +152,39 @@ static inline bool is_timing_event(struct ir_raw_event ev)
 #define TO_US(duration)                        DIV_ROUND_CLOSEST((duration), 1000)
 #define TO_STR(is_pulse)               ((is_pulse) ? "pulse" : "space")
 
+/* functions for IR encoders */
+
+static inline void init_ir_raw_event_duration(struct ir_raw_event *ev,
+                                             unsigned int pulse,
+                                             u32 duration)
+{
+       init_ir_raw_event(ev);
+       ev->duration = duration;
+       ev->pulse = pulse;
+}
+
+/**
+ * struct ir_raw_timings_manchester - Manchester coding timings
+ * @leader:            duration of leader pulse (if any) 0 if continuing
+ *                     existing signal (see @pulse_space_start)
+ * @pulse_space_start: 1 for starting with pulse (0 for starting with space)
+ * @clock:             duration of each pulse/space in ns
+ * @invert:            if set clock logic is inverted
+ *                     (0 = space + pulse, 1 = pulse + space)
+ * @trailer_space:     duration of trailer space in ns
+ */
+struct ir_raw_timings_manchester {
+       unsigned int leader;
+       unsigned int pulse_space_start:1;
+       unsigned int clock;
+       unsigned int invert:1;
+       unsigned int trailer_space;
+};
+
+int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
+                         const struct ir_raw_timings_manchester *timings,
+                         unsigned int n, unsigned int data);
+
 /*
  * Routines from rc-raw.c to be used internally and by decoders
  */
index dd47fe567f03561bef0a6a87bdc20b574b990972..6c9580e4cac508ba6620476c42959c08d145ee0c 100644 (file)
@@ -246,6 +246,91 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_type)
        return 0;
 }
 
+/**
+ * ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation.
+ * @ev:                Pointer to pointer to next free event. *@ev is incremented for
+ *             each raw event filled.
+ * @max:       Maximum number of raw events to fill.
+ * @timings:   Manchester modulation timings.
+ * @n:         Number of bits of data.
+ * @data:      Data bits to encode.
+ *
+ * Encodes the @n least significant bits of @data using Manchester (bi-phase)
+ * modulation with the timing characteristics described by @timings, writing up
+ * to @max raw IR events using the *@ev pointer.
+ *
+ * Returns:    0 on success.
+ *             -ENOBUFS if there isn't enough space in the array to fit the
+ *             full encoded data. In this case all @max events will have been
+ *             written.
+ */
+int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
+                         const struct ir_raw_timings_manchester *timings,
+                         unsigned int n, unsigned int data)
+{
+       bool need_pulse;
+       unsigned int i;
+       int ret = -ENOBUFS;
+
+       i = 1 << (n - 1);
+
+       if (timings->leader) {
+               if (!max--)
+                       return ret;
+               if (timings->pulse_space_start) {
+                       init_ir_raw_event_duration((*ev)++, 1, timings->leader);
+
+                       if (!max--)
+                               return ret;
+                       init_ir_raw_event_duration((*ev), 0, timings->leader);
+               } else {
+                       init_ir_raw_event_duration((*ev), 1, timings->leader);
+               }
+               i >>= 1;
+       } else {
+               /* continue existing signal */
+               --(*ev);
+       }
+       /* from here on *ev will point to the last event rather than the next */
+
+       while (n && i > 0) {
+               need_pulse = !(data & i);
+               if (timings->invert)
+                       need_pulse = !need_pulse;
+               if (need_pulse == !!(*ev)->pulse) {
+                       (*ev)->duration += timings->clock;
+               } else {
+                       if (!max--)
+                               goto nobufs;
+                       init_ir_raw_event_duration(++(*ev), need_pulse,
+                                                  timings->clock);
+               }
+
+               if (!max--)
+                       goto nobufs;
+               init_ir_raw_event_duration(++(*ev), !need_pulse,
+                                          timings->clock);
+               i >>= 1;
+       }
+
+       if (timings->trailer_space) {
+               if (!(*ev)->pulse)
+                       (*ev)->duration += timings->trailer_space;
+               else if (!max--)
+                       goto nobufs;
+               else
+                       init_ir_raw_event_duration(++(*ev), 0,
+                                                  timings->trailer_space);
+       }
+
+       ret = 0;
+nobufs:
+       /* point to the next event rather than last event before returning */
+       ++(*ev);
+       return ret;
+}
+EXPORT_SYMBOL(ir_raw_gen_manchester);
+
 /**
  * ir_raw_encode_scancode() - Encode a scancode as raw events
  *