Jeroen Hilgers / Rc6
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Rc6.cpp Source File

Rc6.cpp

00001 /* mbed RC6 (Philips remote control protocol) library
00002  * Copyright (c) 2011 Jeroen Hilgers
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to deal
00006  * in the Software without restriction, including without limitation the rights
00007  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  * copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020  * THE SOFTWARE.
00021  */
00022 
00023 #include "Rc6.h"
00024 
00025 Rc6Transmitter::Rc6Transmitter(PinName irPin) :
00026     mOut(irPin)
00027 {
00028 
00029     mBusy = false;
00030 }
00031 
00032 void Rc6Transmitter::Send(uint32_t code)
00033 {
00034     if(mBusy)
00035     {
00036         printf("Busy");
00037         return;
00038     }
00039     mBusy = true;        
00040         
00041     uint8_t index = 0;
00042     uint8_t level;
00043     uint16_t time;
00044     uint8_t bit;
00045     // Leader
00046     mPattern[index++] = 6*16; // Mark
00047     mPattern[index++] = 2*16; // Pause
00048     // Start bit 3.
00049     mPattern[index++] = 16;
00050     mPattern[index++] = 2*16;
00051     // Start bit 2.
00052     mPattern[index++] = 16;
00053     // Start bit 1.
00054     mPattern[index++] = 16;
00055     mPattern[index++] = 16;
00056     // Start bit 0.
00057     mPattern[index++] = 16;
00058     // Toggle bit.
00059     if(code & 0x10000) 
00060     {
00061         mPattern[index++] = 3*16;
00062         level = 0;
00063         time = 2*16;
00064     }
00065     else
00066     {
00067         mPattern[index++] = 16;
00068         mPattern[index++] = 2*16;
00069         level = 1;
00070         time = 2*16;
00071     }
00072     for(bit = 0; bit < 16; bit ++)
00073     {
00074         if(code & 0x8000)
00075         {   // Send '1'
00076             if(level) 
00077             {
00078                mPattern[index++] = 16+time;
00079             }   
00080             else
00081             {
00082                 mPattern[index++] = time;
00083                 mPattern[index++] = 16;
00084             }
00085             level = 0;
00086             time = 16;
00087         }
00088         else
00089         {   // Send '0'
00090             if(level) 
00091             {
00092                mPattern[index++] = time;
00093                mPattern[index++] = 16;
00094             }   
00095             else
00096             {
00097                mPattern[index++] = 16+time;
00098             }
00099             level = 1;
00100             time = 16;
00101         }
00102         code <<= 1;
00103     }
00104     if(level == 1)
00105     {
00106         mPattern[index++] = time;
00107     }
00108     mPattern[index++] = 16; // Teminate with half symbol (not long enough?)
00109     
00110     mPattern[index++] = 0; // Mark duration of 0 means end-of-pattern.
00111     mPattern[index++] = 0;
00112  
00113     // Setup transmitter variables...
00114     mMark = 0;  
00115     mPause = 0;
00116     mPatPtr = mPattern;  
00117     
00118     // ... and attach ticker.
00119     // mTicker.attach(this, &Rc6Sender::Tick, 1.0/(2.0*36000.0)); // This rounds down to:
00120     // mTicker.attach_us(this, &Rc6Sender::Tick, 13); // Both are noticeable too slow compared to the real remote!
00121     mTicker.attach_us(this, &Rc6Transmitter::Tick, 14); // This does work.
00122 }
00123 
00124 bool Rc6Transmitter::IsBusy()
00125 {
00126     return mBusy;
00127 }
00128 
00129 void Rc6Transmitter::Tick()
00130 {
00131     if(mMark)
00132     { // Busy sending a mark. Do next part.
00133       mMark--;
00134       if(mMark&1)
00135       {
00136         mOut = 1;
00137       }
00138       else
00139       {
00140         mOut = 0;
00141       }
00142     }
00143     else
00144     { 
00145         if(mPause)
00146         {  // Need to do some more pause.
00147            mPause--;
00148         }
00149         else
00150         { // Last half cycle of pause. Check next activity.
00151           mMark = (*mPatPtr++)<<1; // Half-cycles of marker.
00152           mPause = (*mPatPtr++)<<1; // half-cycles of pause.
00153           mPause--; // The last half-cycle of puase is spend here setting up next cycle.
00154           if(mMark == 0)
00155           {
00156             // We are done. Stop ticker.
00157             mTicker.detach();
00158             mBusy = false;
00159           }
00160         }
00161     }
00162 }
00163 
00164 Rc6Receiver::Rc6Receiver(PinName irIn) :
00165     irq(irIn)
00166 {
00167     // NOTE: Ir sensor inversion is handled here!
00168     irq.rise(this, &Rc6Receiver::OnFall);
00169     irq.fall(this, &Rc6Receiver::OnRise);
00170     mBusy = false;
00171     mLastCode = 0xFFFFFFFF;
00172 }
00173 
00174 uint32_t Rc6Receiver::Receive()
00175 {
00176     // TODO: Disable interrupts to prevent one in a million chance that
00177     // mLastCode gets updated...
00178     uint32_t code = mLastCode;
00179     // ... at exactly this moment, so it will be discarded here:
00180     mLastCode = 0xFFFFFFFF;
00181     return code;
00182 }
00183 
00184 void Rc6Receiver::OnRise()
00185 {
00186     if(mBusy) 
00187     {
00188         // Rising edges are not interesting; they correspond to '0'.
00189     }
00190     else
00191     {
00192         mBusy = true;
00193         mCode = 0;
00194         mTimer.start();
00195         mTimeout.attach_us(this, &Rc6Receiver::OnTimeout, 30000);  // 52T of 16/36000 sec = 23ms
00196     }
00197 }
00198 
00199 void Rc6Receiver::OnFall()
00200 {
00201     if(mBusy)
00202     {
00203         // Express edge location in 'T' (444.444 us)
00204         int32_t edgeId = (mTimer.read_us()*1000 + 222222)/444444;
00205         // printf("%d %d\r\n", mTimer.read_us(), edgeId); // Debug print. Doesn't mess up timing as hard as expected :-)
00206         
00207         // Toggle bit is at edge 18. Store it!
00208         if(edgeId == 18)
00209             mCode |= 0x10000;
00210         // Address and data bits.
00211         if((edgeId & 0x01) && (edgeId > 21) && (edgeId < 52))
00212         {
00213             uint8_t bit = 15 - (edgeId-21)/2;
00214             mCode |= 1<<bit;
00215         }
00216     }
00217 }
00218 
00219 void Rc6Receiver::OnTimeout()
00220 {
00221     mTimer.stop();
00222     mTimer.reset();
00223     mBusy = false;
00224     mLastCode = mCode;
00225 }