This library implements RC6 (protocol used by some philips remotes). It has a receiver class and a transmitter class. Currently, only mode 0 is supported. It is tested with my DVD/HDD recorder.

Files at this revision

API Documentation at this revision

Comitter:
hilgo
Date:
Sun Feb 27 20:28:35 2011 +0000
Commit message:
Initial revision: Receiver does not check framing yet (thus other remotes cause junk!)

Changed in this revision

Rc6.cpp Show annotated file Show diff for this revision Revisions of this file
Rc6.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r f8e2ed766064 Rc6.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Rc6.cpp	Sun Feb 27 20:28:35 2011 +0000
@@ -0,0 +1,225 @@
+/* mbed RC6 (Philips remote control protocol) library
+ * Copyright (c) 2011 Jeroen Hilgers
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "Rc6.h"
+
+Rc6Transmitter::Rc6Transmitter(PinName irPin) :
+    mOut(irPin)
+{
+
+    mBusy = false;
+}
+
+void Rc6Transmitter::Send(uint32_t code)
+{
+    if(mBusy)
+    {
+        printf("Busy");
+        return;
+    }
+    mBusy = true;        
+        
+    uint8_t index = 0;
+    uint8_t level;
+    uint16_t time;
+    uint8_t bit;
+    // Leader
+    mPattern[index++] = 6*16; // Mark
+    mPattern[index++] = 2*16; // Pause
+    // Start bit 3.
+    mPattern[index++] = 16;
+    mPattern[index++] = 2*16;
+    // Start bit 2.
+    mPattern[index++] = 16;
+    // Start bit 1.
+    mPattern[index++] = 16;
+    mPattern[index++] = 16;
+    // Start bit 0.
+    mPattern[index++] = 16;
+    // Toggle bit.
+    if(code & 0x10000) 
+    {
+        mPattern[index++] = 3*16;
+        level = 0;
+        time = 2*16;
+    }
+    else
+    {
+        mPattern[index++] = 16;
+        mPattern[index++] = 2*16;
+        level = 1;
+        time = 2*16;
+    }
+    for(bit = 0; bit < 16; bit ++)
+    {
+        if(code & 0x8000)
+        {   // Send '1'
+            if(level) 
+            {
+               mPattern[index++] = 16+time;
+            }   
+            else
+            {
+                mPattern[index++] = time;
+                mPattern[index++] = 16;
+            }
+            level = 0;
+            time = 16;
+        }
+        else
+        {   // Send '0'
+            if(level) 
+            {
+               mPattern[index++] = time;
+               mPattern[index++] = 16;
+            }   
+            else
+            {
+               mPattern[index++] = 16+time;
+            }
+            level = 1;
+            time = 16;
+        }
+        code <<= 1;
+    }
+    if(level == 1)
+    {
+        mPattern[index++] = time;
+    }
+    mPattern[index++] = 16; // Teminate with half symbol (not long enough?)
+    
+    mPattern[index++] = 0; // Mark duration of 0 means end-of-pattern.
+    mPattern[index++] = 0;
+ 
+    // Setup transmitter variables...
+    mMark = 0;  
+    mPause = 0;
+    mPatPtr = mPattern;  
+    
+    // ... and attach ticker.
+    // mTicker.attach(this, &Rc6Sender::Tick, 1.0/(2.0*36000.0)); // This rounds down to:
+    // mTicker.attach_us(this, &Rc6Sender::Tick, 13); // Both are noticeable too slow compared to the real remote!
+    mTicker.attach_us(this, &Rc6Transmitter::Tick, 14); // This does work.
+}
+
+bool Rc6Transmitter::IsBusy()
+{
+    return mBusy;
+}
+
+void Rc6Transmitter::Tick()
+{
+    if(mMark)
+    { // Busy sending a mark. Do next part.
+      mMark--;
+      if(mMark&1)
+      {
+        mOut = 1;
+      }
+      else
+      {
+        mOut = 0;
+      }
+    }
+    else
+    { 
+        if(mPause)
+        {  // Need to do some more pause.
+           mPause--;
+        }
+        else
+        { // Last half cycle of pause. Check next activity.
+          mMark = (*mPatPtr++)<<1; // Half-cycles of marker.
+          mPause = (*mPatPtr++)<<1; // half-cycles of pause.
+          mPause--; // The last half-cycle of puase is spend here setting up next cycle.
+          if(mMark == 0)
+          {
+            // We are done. Stop ticker.
+            mTicker.detach();
+            mBusy = false;
+          }
+        }
+    }
+}
+
+Rc6Receiver::Rc6Receiver(PinName irIn) :
+    irq(irIn)
+{
+    // NOTE: Ir sensor inversion is handled here!
+    irq.rise(this, &Rc6Receiver::OnFall);
+    irq.fall(this, &Rc6Receiver::OnRise);
+    mBusy = false;
+    mLastCode = 0xFFFFFFFF;
+}
+
+uint32_t Rc6Receiver::Receive()
+{
+    // TODO: Disable interrupts to prevent one in a million chance that
+    // mLastCode gets updated...
+    uint32_t code = mLastCode;
+    // ... at exactly this moment, so it will be discarded here:
+    mLastCode = 0xFFFFFFFF;
+    return code;
+}
+
+void Rc6Receiver::OnRise()
+{
+    if(mBusy) 
+    {
+        // Rising edges are not interesting; they correspond to '0'.
+    }
+    else
+    {
+        mBusy = true;
+        mCode = 0;
+        mTimer.start();
+        mTimeout.attach_us(this, &Rc6Receiver::OnTimeout, 30000);  // 52T of 16/36000 sec = 23ms
+    }
+}
+
+void Rc6Receiver::OnFall()
+{
+    if(mBusy)
+    {
+        // Express edge location in 'T' (444.444 us)
+        int32_t edgeId = (mTimer.read_us()*1000 + 222222)/444444;
+        // printf("%d %d\r\n", mTimer.read_us(), edgeId); // Debug print. Doesn't mess up timing as hard as expected :-)
+        
+        // Toggle bit is at edge 18. Store it!
+        if(edgeId == 18)
+            mCode |= 0x10000;
+        // Address and data bits.
+        if((edgeId & 0x01) && (edgeId > 21) && (edgeId < 52))
+        {
+            uint8_t bit = 15 - (edgeId-21)/2;
+            mCode |= 1<<bit;
+        }
+    }
+}
+
+void Rc6Receiver::OnTimeout()
+{
+    mTimer.stop();
+    mTimer.reset();
+    mBusy = false;
+    mLastCode = mCode;
+}
diff -r 000000000000 -r f8e2ed766064 Rc6.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Rc6.h	Sun Feb 27 20:28:35 2011 +0000
@@ -0,0 +1,106 @@
+/* mbed RC6 (Philips remote control protocol) library
+ * Copyright (c) 2011 Jeroen Hilgers
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+ 
+ #ifndef __RC6_H__
+ #define __RC6_H__
+ 
+ #include "mbed.h"
+
+/** RC6 (Philips remote control) receiver / transmitter library.
+  *
+  * Example: Code receiver for 'play/pause' on remote for Philips HDD&DVD recorder.
+  * 
+  * Leader  |S3|S2|S1|S0|Togl|A7|A6|A5|A4|A3|A2|A1|A0|D7|D6|D5|D4|D3|D2|D1|D0|
+  *         |1 |0 |0 |0 |1   |0 |0 |1 |1 |0 |0 |1 |0 |0 |0 |1 |0 |1 |1 |0 |0 |
+  *         |  |  |  |  |    |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
+  * ------  |- | -| -| -|--  | -| -|- |- | -| -|- | -| -| -|- | -|- |- | -| -|
+  *       --| -|- |- |- |  --|- |- | -| -|- |- | -|- |- |- | -|- | -| -|- |- |
+  *         |  |  |  |  |    |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
+  *
+  * The toggle bit is in bit 16, A7-A0 in bits 15-8, D7-D0 in bits 7-0.
+  * Thus for the example, 0x1322C is returned. S3..S0 are not implemented
+  * and received / transmitted as shown in the example.
+  */
+  
+ class Rc6Transmitter
+ {
+    public:
+        /** Create a Rc6Transmitter and initizalize it.
+         *
+         * @param pin irPin pin connected IR Led (led on on high level).
+         */
+        Rc6Transmitter(PinName irPin);
+
+        /** Send a code once. 
+         * The function will return synchronously and send the code once. 
+         *
+         * @param code Code to send.
+         */
+        void Send(uint32_t code);
+        
+        /** Check if the transmitter is idle.
+         * 
+         * @return True if transmitter still busy.
+         */
+        bool IsBusy();
+    
+    private:
+        void Tick();
+    
+        bool mBusy;
+        uint16_t mPattern[50];  // 1 leader, 4 startbits, 1 toggle bit, 16 data bits ==>
+                                // at most 24 mark / pause durations + 0,0 terminator = 50 entries. 
+        Ticker mTicker;
+        uint16_t mMark;          // Tick: Remaining half-cycles of mark.
+        uint16_t mPause;         // Tick: Remaining half-cycles of pause.        
+        uint16_t *mPatPtr;       // Transitter pointer.
+        DigitalOut mOut;     // Pin connected to IR.
+};
+ 
+ class Rc6Receiver
+ {
+    public:
+        /** Create a Rc6Receiver and initizalize it.
+         *
+         * @param pin irPin pin connected to IR sensor (low level when IR is received, e.g. TSOP1736).
+         */
+        Rc6Receiver(PinName irPin);
+
+        /** Check if anything was received since last poll. Returns 0xFFFFFFFF if not.
+         *
+         * @return Last code received or 0xFFFFFFFF if nothing was received since last poll.
+         */
+        uint32_t Receive();
+        
+    private:
+        InterruptIn irq;
+        void OnRise();
+        void OnFall();
+        void OnTimeout();
+        Timeout mTimeout;
+        Timer mTimer;
+        bool mBusy;
+        uint32_t mCode;  
+        uint32_t mLastCode;
+ };
+  
+ #endif // __RC6_H__
\ No newline at end of file