Advanced Settings Panel
[pierogi] / protocols / dishprotocol.cpp
1 #include "dishprotocol.h"
2
3 #include "pirrx51hardware.h"
4
5 #include "pirexception.h"
6
7 // Some global communications stuff:
8 #include <QMutex>
9 extern bool commandInFlight;
10 extern QMutex commandIFMutex;
11
12 // Dish Network, or now just "Dish", has a unique protocol.  It uses "space"
13 // encoding, but otherwise is unlike just about anything else out there.
14 // Here's what I've got on it:
15 // A "zero" is encoded with a 400 usec pulse, 2800 usec space.
16 // A "one" is encoded with a 400 usec pulse, 1600 usec space.
17 // The header is a 400 usec pulse, 6000 usec space.
18 // Commands end with a trailing 400 usec pulse.
19 // Commands are repeated without the header (or, if you like, you can consider
20 // the trailing pulse to be the header for the next repetition).
21 // There is a 6000 usec gap between repetitions.
22 // The carrier frequency is apparently 57600 kHz, or thereabouts.
23 // The duty cycle is 1/3.
24
25 DishProtocol::DishProtocol(
26   QObject *guiObject,
27   unsigned int index)
28   : SpaceProtocol(
29       guiObject, index,
30       400, 2800,
31       400, 1600,
32       400, 6000,
33       400,
34       6000, false)
35 {
36   setCarrierFrequency(57600);
37 //  setDutyCycle(33);
38 }
39
40
41 void DishProtocol::startSendingCommand(
42   unsigned int threadableID,
43   PIRKeyName command)
44 {
45   // Exceptions here are problematic; I'll try to weed them out by putting the
46   // whole thing in a try/catch block:
47   try
48   {
49     // First, check if we are meant to be the recipient of this command:
50     if (threadableID != id) return;
51
52     clearRepeatFlag();
53
54     KeycodeCollection::const_iterator i = keycodes.find(command);
55
56     // Do we even have this key defined?
57     if (i == keycodes.end())
58     {
59       QMutexLocker cifLocker(&commandIFMutex);
60       commandInFlight = false;
61       return;
62 //      std::string s = "Tried to send a non-existent command.\n";
63 //      throw PIRException(s);
64     }
65
66     // construct the device:
67     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
68
69     int repeatCount = 0;
70     int commandDuration = 0;
71     while (repeatCount < MAX_REPEAT_COUNT)
72     {
73       // If this is not a repetition, we need to add the initial header:
74       if (repeatCount == 0)
75       {
76         rx51device.addPair(headerPulse, headerSpace);
77         commandDuration += (headerPulse + headerSpace);
78       }
79
80       // generate the rest of the command:
81       commandDuration += generateStandardCommand(i->second, rx51device);
82
83       // Now, tell the device to send the whole command:
84       rx51device.sendCommandToDevice();
85
86       // sleep until the next repetition of command:
87       sleepUntilRepeat(commandDuration);
88
89       // Check whether we've reached the minimum required number of repetitons:
90       if (repeatCount >= minimumRepetitions)
91       {
92         // Check whether we've been asked to stop:
93         if (checkRepeatFlag())
94         {
95           break;
96 /*
97           QMutexLocker cifLocker(&commandIFMutex);
98           commandInFlight = false;
99           return;
100 */
101         }
102       }
103
104       ++repeatCount;
105     }
106
107     QMutexLocker cifLocker(&commandIFMutex);
108     commandInFlight = false;
109   }
110   catch (PIRException e)
111   {
112     // inform the gui:
113     emit commandFailed(e.getError().c_str());
114   }
115 }
116
117
118 int DishProtocol::generateStandardCommand(
119   const PIRKeyBits &pkb,
120   PIRRX51Hardware &rx51device)
121 {
122   int duration = 0;
123
124   // In the Dish protocol, the pulse train consists of 6 bits of command
125   // data followed by 10 bits of, uhm, other stuff.  I know that at least the
126   // first four bits of these ten can be used for pairing purposes.  It looks
127   // like the last five bits can be used as additional command data.  For
128   // now, I'm going to split this into 5 "address" and 5 "more command" bits.
129   //
130   // The command data is sent MSB-first (I know that at least the first
131   // 6 bits are, I'll represent the last 5 that way as well).
132   // The pairing data is sent LSB-first, god knows why.
133   // - "firstCode" should contain 6-bit value
134   // - "preData" should contain 5 bits of pairing data
135   // - "secondCode" should contain the last 5 bits.
136   duration += pushBits(pkb.firstCode, rx51device);
137   duration += pushReverseBits(postData, rx51device);
138   duration += pushBits(pkb.secondCode, rx51device);
139
140   // Finally add the "trail":
141   rx51device.addSingle(trailerPulse);
142   duration += trailerPulse;
143
144   return duration;
145 }
146