forked from Arduino-IRremote/Arduino-IRremote
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathir_Denon.hpp
313 lines (274 loc) · 12.5 KB
/
ir_Denon.hpp
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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/*
* ir_Denon.cpp
*
* Contains functions for receiving and sending Denon/Sharp IR Protocol
*
* This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
*
************************************************************************************
* MIT License
*
* Copyright (c) 2020-2023 Armin Joachimsmeyer
*
* 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.
*
************************************************************************************
*/
#ifndef _IR_DENON_HPP
#define _IR_DENON_HPP
#if defined(DEBUG) && !defined(LOCAL_DEBUG)
#define LOCAL_DEBUG
#else
//#define LOCAL_DEBUG // This enables debug output only for this file
#endif
/** \addtogroup Decoder Decoders and encoders for different protocols
* @{
*/
//==============================================================================
// DDDD EEEEE N N OOO N N
// D D E NN N O O NN N
// D D EEE N N N O O N N N
// D D E N NN O O N NN
// DDDD EEEEE N N OOO N N
//==============================================================================
// SSSS H H AAA RRRR PPPP
// S H H A A R R P P
// SSS HHHHH AAAAA RRRR PPPP
// S H H A A R R P
// SSSS H H A A R R P
//==============================================================================
/*
Protocol=Denon Address=0x11 Command=0x76 Raw-Data=0xED1 15 bits LSB first
+ 200,-1800 + 300,- 750 + 300,- 800 + 200,- 800
+ 250,-1800 + 250,- 800 + 250,-1800 + 300,-1750
+ 300,- 750 + 300,-1800 + 250,-1800 + 250,-1850
+ 250,- 750 + 300,- 800 + 250,- 800 + 250
Sum: 23050
Denon/Sharp variant
Protocol=Denon Address=0x11 Command=0x76 Raw-Data=0x4ED1 15 bits LSB first
+ 200,-1800 + 300,- 750 + 250,- 800 + 250,- 750
+ 300,-1800 + 250,- 800 + 250,-1800 + 300,-1750
+ 300,- 750 + 300,-1800 + 250,-1800 + 250,-1800
+ 300,- 750 + 300,- 750 + 300,-1800 + 250
Sum: 23050
*/
/*
* https://www.mikrocontroller.net/articles/IRMP_-_english#DENON
* Denon published all their IR codes:
* http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls
* Example:
* 0000 006D 0000 0020 000A 001E 000A 0046 000A 001E 000A 001E 000A 001E // 5 address bits
* 000A 001E 000A 001E 000A 0046 000A 0046 000A 0046 000A 001E 000A 0046 000A 0046 // 8 command bits
* 000A 001E 000A 001E 000A 0679 // 2 frame bits 0,0 + stop bit + space for AutoRepeat
* 000A 001E 000A 0046 000A 001E 000A 001E 000A 001E // 5 address bits
* 000A 0046 000A 0046 000A 001E 000A 001E 000A 001E 000A 0046 000A 001E 000A 001E // 8 inverted command bits
* 000A 0046 000A 0046 000A 0679 // 2 frame bits 1,1 + stop bit + space for Repeat
* From analyzing the codes for Tuner preset 1 to 8 in tab Main Zone ID#1 it is obvious, that the protocol is LSB first at least for command.
* All Denon codes with 32 as 3. value use the Kaseyikyo Denon variant.
*/
// LSB first, no start bit, 5 address + 8 command + 2 frame (0,0) + 1 stop bit - each frame 2 times
// Every frame is auto repeated with a space period of 45 ms and the command and frame inverted to (1,1) or (0,1) for SHARP.
//
#define DENON_ADDRESS_BITS 5
#define DENON_COMMAND_BITS 8
#define DENON_FRAME_BITS 2 // 00/10 for 1. frame Denon/Sharp, inverted for autorepeat frame
#define DENON_BITS (DENON_ADDRESS_BITS + DENON_COMMAND_BITS + DENON_FRAME_BITS) // 15 - The number of bits in the command
#define DENON_UNIT 260
#define DENON_BIT_MARK DENON_UNIT // The length of a Bit:Mark
#define DENON_ONE_SPACE (7 * DENON_UNIT) // 1820 // The length of a Bit:Space for 1's
#define DENON_ZERO_SPACE (3 * DENON_UNIT) // 780 // The length of a Bit:Space for 0's
#define DENON_AUTO_REPEAT_DISTANCE 45000 // Every frame is auto repeated with a space period of 45 ms and the command and frame inverted.
#define DENON_REPEAT_PERIOD 110000 // Commands are repeated every 110 ms (measured from start to start) for as long as the key on the remote control is held down.
// for old decoder
#define DENON_HEADER_MARK DENON_UNIT // The length of the Header:Mark
#define DENON_HEADER_SPACE (3 * DENON_UNIT) // 780 // The length of the Header:Space
struct PulseDistanceWidthProtocolConstants DenonProtocolConstants = { DENON, DENON_KHZ, DENON_HEADER_MARK, DENON_HEADER_SPACE,
DENON_BIT_MARK, DENON_ONE_SPACE, DENON_BIT_MARK, DENON_ZERO_SPACE, PROTOCOL_IS_LSB_FIRST,
(DENON_REPEAT_PERIOD / MICROS_IN_ONE_MILLI), NULL };
/************************************
* Start of send and decode functions
************************************/
void IRsend::sendSharp(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats) {
sendDenon(aAddress, aCommand, aNumberOfRepeats, true);
}
void IRsend::sendDenon(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, bool aSendSharp) {
// Set IR carrier frequency
enableIROut (DENON_KHZ); // 38 kHz
// Add frame marker for sharp
uint16_t tCommand = aCommand;
if (aSendSharp) {
tCommand |= 0x0200; // the 2 upper bits are 00 for Denon and 10 for Sharp
}
uint16_t tData = aAddress | ((uint16_t) tCommand << DENON_ADDRESS_BITS);
uint16_t tInvertedData = (tData ^ 0x7FE0); // Command and frame (upper 10 bits) are inverted
uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
while (tNumberOfCommands > 0) {
// Data
sendPulseDistanceWidthData(&DenonProtocolConstants, tData, DENON_BITS);
// Inverted autorepeat frame
delay(DENON_AUTO_REPEAT_DISTANCE / MICROS_IN_ONE_MILLI);
sendPulseDistanceWidthData(&DenonProtocolConstants, tInvertedData, DENON_BITS);
tNumberOfCommands--;
// skip last delay!
if (tNumberOfCommands > 0) {
// send repeated command with a fixed space gap
delay( DENON_AUTO_REPEAT_DISTANCE / MICROS_IN_ONE_MILLI);
}
}
}
bool IRrecv::decodeSharp() {
return decodeDenon();
}
bool IRrecv::decodeDenon() {
// we have no start bit, so check for the exact amount of data bits
// Check we have the right amount of data (32). The + 2 is for initial gap + stop bit mark
if (decodedIRData.rawDataPtr->rawlen != (2 * DENON_BITS) + 2) {
IR_DEBUG_PRINT(F("Denon: "));
IR_DEBUG_PRINT(F("Data length="));
IR_DEBUG_PRINT(decodedIRData.rawDataPtr->rawlen);
IR_DEBUG_PRINTLN(F(" is not 32"));
return false;
}
// Try to decode as Denon protocol
if (!decodePulseDistanceWidthData(&DenonProtocolConstants, DENON_BITS, 1)) {
#if defined(LOCAL_DEBUG)
Serial.print(F("Denon: "));
Serial.println(F("Decode failed"));
#endif
return false;
}
// Check for stop mark
if (!matchMark(decodedIRData.rawDataPtr->rawbuf[(2 * DENON_BITS) + 1], DENON_HEADER_MARK)) {
#if defined(LOCAL_DEBUG)
Serial.print(F("Denon: "));
Serial.println(F("Stop bit mark length is wrong"));
#endif
return false;
}
// Success
decodedIRData.address = decodedIRData.decodedRawData & 0x1F;
decodedIRData.command = decodedIRData.decodedRawData >> DENON_ADDRESS_BITS;
uint8_t tFrameBits = (decodedIRData.command >> 8) & 0x03;
decodedIRData.command &= 0xFF;
// Check for (auto) repeat
if (decodedIRData.rawDataPtr->rawbuf[0] < ((DENON_AUTO_REPEAT_DISTANCE + (DENON_AUTO_REPEAT_DISTANCE / 4)) / MICROS_PER_TICK)) {
repeatCount++;
if (repeatCount > 1) { // skip first auto repeat
decodedIRData.flags = IRDATA_FLAGS_IS_REPEAT;
}
if (tFrameBits & 0x01) {
/*
* Here we are in the auto repeated frame with the inverted command
*/
#if defined(LOCAL_DEBUG)
Serial.print(F("Denon: "));
Serial.println(F("Autorepeat received="));
#endif
decodedIRData.flags |= IRDATA_FLAGS_IS_AUTO_REPEAT;
// Check parity of consecutive received commands. There is no parity in one data set.
if ((uint8_t) lastDecodedCommand != (uint8_t)(~decodedIRData.command)) {
decodedIRData.flags |= IRDATA_FLAGS_PARITY_FAILED;
#if defined(LOCAL_DEBUG)
Serial.print(F("Denon: "));
Serial.print(F("Parity check for repeat failed. Last command="));
Serial.print(lastDecodedCommand, HEX);
Serial.print(F(" current="));
Serial.println(~decodedIRData.command, HEX);
#endif
}
// always take non inverted command
decodedIRData.command = lastDecodedCommand;
}
// repeated command here
if (tFrameBits == 1 || tFrameBits == 2) {
decodedIRData.protocol = SHARP;
} else {
decodedIRData.protocol = DENON;
}
} else {
repeatCount = 0;
// first command here
if (tFrameBits == 2) {
decodedIRData.protocol = SHARP;
} else {
decodedIRData.protocol = DENON;
}
}
decodedIRData.numberOfBits = DENON_BITS;
return true;
}
/*********************************************************************************
* Old deprecated functions, kept for backward compatibility to old 2.0 tutorials
*********************************************************************************/
/*
* Only for backwards compatibility
*/
void IRsend::sendDenonRaw(uint16_t aRawData, int_fast8_t aNumberOfRepeats) {
sendDenon(aRawData >> (DENON_COMMAND_BITS + DENON_FRAME_BITS), (aRawData >> DENON_FRAME_BITS) & 0xFF, aNumberOfRepeats);
}
/*
* Old function with parameter data
*/
void IRsend::sendDenon(unsigned long data, int nbits) {
// Set IR carrier frequency
enableIROut (DENON_KHZ);
#if !(defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__))
// Serial.println(
// "The function sendDenon(data, nbits) is deprecated and may not work as expected! Use sendDenonRaw(data, NumberOfRepeats) or better sendDenon(Address, Command, NumberOfRepeats).");
#endif
// Header
mark(DENON_HEADER_MARK);
space(DENON_HEADER_SPACE);
// Data
sendPulseDistanceWidthData(DENON_BIT_MARK, DENON_ONE_SPACE, DENON_BIT_MARK, DENON_ZERO_SPACE, data, nbits,
PROTOCOL_IS_MSB_FIRST);
}
/*
* Old function without parameter aNumberOfRepeats
*/
void IRsend::sendSharp(uint16_t aAddress, uint16_t aCommand) {
sendDenon(aAddress, aCommand, true, 0);
}
bool IRrecv::decodeDenonOld(decode_results *aResults) {
// Check we have the right amount of data
if (decodedIRData.rawDataPtr->rawlen != 1 + 2 + (2 * DENON_BITS) + 1) {
return false;
}
// Check initial Mark+Space match
if (!matchMark(aResults->rawbuf[1], DENON_HEADER_MARK)) {
return false;
}
if (!matchSpace(aResults->rawbuf[2], DENON_HEADER_SPACE)) {
return false;
}
// Try to decode as Denon protocol
if (!decodePulseDistanceWidthData(DENON_BITS, 3, DENON_BIT_MARK, 0, DENON_ONE_SPACE, DENON_ZERO_SPACE, PROTOCOL_IS_MSB_FIRST)) {
return false;
}
// Success
aResults->value = decodedIRData.decodedRawData;
aResults->bits = DENON_BITS;
aResults->decode_type = DENON;
decodedIRData.protocol = DENON;
return true;
}
/** @}*/
#if defined(LOCAL_DEBUG)
#undef LOCAL_DEBUG
#endif
#endif // _IR_DENON_HPP