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.
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
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