-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontrol-protocol.cpp
213 lines (176 loc) · 6.12 KB
/
control-protocol.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#include <Arduino.h>
int ControlLinePin = 5; // GPIO-5 Remote control line
bool ToggleBitValue = 0; // Toggle bit (T). This bit is inverted each time a key is released and pressed again.
constexpr int RC5Unit = 889; // In micro seconds - Unit is 32 cycles of 36 kHz carrier signal
constexpr int RC5XPauseDuration = RC5Unit * 2 * 2;
// RC5 packet 14 bit:
// | S1 bit | S2 bit | T bit | Address 5 bits | Command 6 bits |
// | 1 | 2 | 3 | 4 .. 8 | 9 .. 14 |
// RC5X (Extended) packet 20 bit:
// | S1 bit | S2 bit - inverted Command bit 6 | T bit | Address 5 bits | pause | Command 6 bits | Extension 6 bits |
// | 1 | 2 | 3 | 4 .. 8 | 2 bit | 9 .. 14 | 14 .. 20 |
constexpr uint8_t RC5Len = 14;
constexpr uint8_t RC5XLen = 20;
constexpr uint8_t S1Value = 1; // Start bit 1. Always = 1.
constexpr uint8_t S2Value = 1; // Start bit 2.
// RC5 - Always = 1.
// RC5X - The value of S2 must be inverted to get the 7th command bit though!
// That way the first 64 commands remain compatible with the original RC-5 protocol.
constexpr uint8_t TValue = 0; // Toggle bit (T). This bit is inverted each time a key is released and pressed again.
constexpr uint8_t AddressMax = 0x1F; // Address is 5 bits. Sent with MSB first
constexpr uint8_t CommandMax = 0x3F; // Command is 6 bits. Sent with MSB first
constexpr uint8_t CommandExtMax = 0x7F; // Command is 7 bits. Sent with MSB first
constexpr uint8_t ExtensionMax = 0x3F; // Extension is 6 bits. Sent with MSB first
constexpr uint8_t S1BitPosition = 1;
constexpr uint8_t S2BitPosition = 2;
constexpr uint8_t TBitPosition = 3;
constexpr uint8_t AddressPosition = 8;
constexpr uint8_t CommandPosition = 14;
constexpr uint8_t RC5XPausePosition = RC5XLen - AddressPosition;
template<uint8_t CommandExtended> constexpr bool GetExtendedCommandBit()
{
static_assert(CommandExtended < CommandExtMax, "RC5 extended Command is out of range");
return !(CommandExtended > CommandMax);
}
template<uint8_t Address, uint8_t Command> constexpr uint16_t GetRC5Code()
{
static_assert(Address <= AddressMax, "RC5 Address is out of range");
static_assert(Command <= CommandMax, "RC5 Command is out of range");
return (S1Value << RC5Len - S1BitPosition) |
(S2Value << RC5Len - S2BitPosition) |
(TValue << RC5Len - TBitPosition) |
(Address << RC5Len - AddressPosition) |
(Command);
}
template<uint8_t Address, uint8_t Command, uint8_t Extension> constexpr uint32_t GetRC5ExtendedCode()
{
static_assert(Address <= AddressMax, "RC5 Address is out of range");
static_assert(Command <= CommandExtMax, "RC5 Extended Command is out of range");
static_assert(Extension <= ExtensionMax, "RC5 Extension is out of range");
return (S1Value << RC5XLen - S1BitPosition) |
((S2Value & GetExtendedCommandBit<Command>())
<< RC5XLen - S2BitPosition) |
(TValue << RC5XLen - TBitPosition) |
(Address << RC5XLen - AddressPosition) |
(Command << RC5XLen - CommandPosition) |
(Extension);
}
inline void Send_0()
{
digitalWrite(ControlLinePin, HIGH);
delayMicroseconds(RC5Unit);
digitalWrite(ControlLinePin, LOW);
delayMicroseconds(RC5Unit);
}
inline void Send_1()
{
digitalWrite(ControlLinePin, LOW);
delayMicroseconds(RC5Unit);
digitalWrite(ControlLinePin, HIGH);
delayMicroseconds(RC5Unit);
}
inline void SetToggleBit(uint32_t &packet, bool isExtended)
{
uint8_t TBitShift = (isExtended ? RC5XLen : RC5Len) - TBitPosition;
if (!ToggleBitValue)
{
ToggleBitValue = true;
packet |= (1 << TBitShift);
}
else
{
// packet &= ~(1 << TBitShift); // already set to 0 in GetRC5Code()
ToggleBitValue = false;
}
}
// Space marker for Marantz RC5 extension after Address
inline void RC5ExtensionPause()
{
delayMicroseconds(RC5XPauseDuration);
}
// Drop signal to zero in case last bit was sent is 1.
inline void DropLineDown(uint32_t &packet)
{
if (packet & 1)
{
digitalWrite(ControlLinePin, LOW);
}
}
// Wait repeat pause 89ms = Repeat T 114ms - Parcel duration 25ms
inline void RepeatPause()
{
delay(89);
}
void SendRC5(uint32_t packet, bool isExtended = false, uint8_t repeatCount = 1)
{
SetToggleBit(packet, isExtended);
while (repeatCount-- > 0)
{
uint8_t StartShift = (isExtended ? RC5XLen : RC5Len) - 1;
for (int i = StartShift; i >= 0; i--)
{
(packet & (1 << i)) ? Send_1() : Send_0();
if (isExtended && (i == RC5XPausePosition))
{
RC5ExtensionPause();
}
}
DropLineDown(packet);
RepeatPause();
}
}
extern "C" void SendMarantzPowerOn()
{
auto packet = GetRC5ExtendedCode<16, 12, 1>();
SendRC5(packet, true);
}
extern "C" void SendMarantzPowerOff()
{
auto packet = GetRC5ExtendedCode<16, 12, 2>();
SendRC5(packet, true);
}
extern "C" void SendMarantzInputCD()
{
auto packet = GetRC5Code<20, 63>();
SendRC5(packet);
}
extern "C" void SendMarantzInputPhono()
{
auto packet = GetRC5Code<21, 63>();
SendRC5(packet);
}
extern "C" void SendMarantzInputTuner()
{
auto packet = GetRC5Code<17, 63>();
SendRC5(packet);
}
extern "C" void SendMarantzInputTape()
{
auto packet = GetRC5Code<18, 63>();
SendRC5(packet);
}
extern "C" void SendMarantzInputAux()
{
auto packet = GetRC5ExtendedCode<16, 0, 6>();
SendRC5(packet, true);
}
extern "C" void SendMarantzInputCdrMd()
{
auto packet = GetRC5Code<23, 63>();
SendRC5(packet);
}
extern "C" void SendMarantzVolumeUp()
{
auto packet = GetRC5Code<16, 16>();
SendRC5(packet, false, 2);
}
extern "C" void SendMarantzVolumeDown()
{
auto packet = GetRC5Code<16, 17>();
SendRC5(packet, false, 2);
}
extern "C" void SendMarantzMute()
{
auto packet = GetRC5Code<16,13>();
SendRC5(packet, false, 2);
}