Revision 0:f8e2ed766064, committed 2011-02-27
- 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
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