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.
Rc6.cpp
- Committer:
- hilgo
- Date:
- 2011-02-27
- Revision:
- 0:f8e2ed766064
File content as of revision 0:f8e2ed766064:
/* 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; }