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.
Diff: Rc6.cpp
- Revision:
- 0:f8e2ed766064
--- /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; +}