IRremote
ir_Denon.hpp
Go to the documentation of this file.
1 /*
2  * ir_Denon.cpp
3  *
4  * Contains functions for receiving and sending Denon/Sharp IR Protocol
5  *
6  * This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
7  *
8  ************************************************************************************
9  * MIT License
10  *
11  * Copyright (c) 2020-2026 Armin Joachimsmeyer
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a copy
14  * of this software and associated documentation files (the "Software"), to deal
15  * in the Software without restriction, including without limitation the rights
16  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17  * copies of the Software, and to permit persons to whom the Software is furnished
18  * to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included in all
21  * copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
24  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
25  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
28  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29  *
30  ************************************************************************************
31  */
32 #ifndef _IR_DENON_HPP
33 #define _IR_DENON_HPP
34 
35 // This block must be located after the includes of other *.hpp files
36 //#define LOCAL_DEBUG // This enables debug output only for this file - only for development
37 #include "LocalDebugLevelStart.h"
38 
42 //==============================================================================
43 // DDDD EEEEE N N OOO N N
44 // D D E NN N O O NN N
45 // D D EEE N N N O O N N N
46 // D D E N NN O O N NN
47 // DDDD EEEEE N N OOO N N
48 //==============================================================================
49 // SSSS H H AAA RRRR PPPP
50 // S H H A A R R P P
51 // SSS HHHHH AAAAA RRRR PPPP
52 // S H H A A R R P
53 // SSSS H H A A R R P
54 //==============================================================================
55 /*
56  Protocol=Denon Address=0x11 Command=0x76 Raw-Data=0xED1 15 bits LSB first
57  + 200,-1800 + 300,- 750 + 300,- 800 + 200,- 800
58  + 250,-1800 + 250,- 800 + 250,-1800 + 300,-1750
59  + 300,- 750 + 300,-1800 + 250,-1800 + 250,-1850
60  + 250,- 750 + 300,- 800 + 250,- 800 + 250
61  Sum: 23050
62 
63  Denon/Sharp variant
64  Protocol=Denon Address=0x11 Command=0x76 Raw-Data=0x4ED1 15 bits LSB first
65  + 200,-1800 + 300,- 750 + 250,- 800 + 250,- 750
66  + 300,-1800 + 250,- 800 + 250,-1800 + 300,-1750
67  + 300,- 750 + 300,-1800 + 250,-1800 + 250,-1800
68  + 300,- 750 + 300,- 750 + 300,-1800 + 250
69  Sum: 23050
70  */
71 /*
72  * https://www.mikrocontroller.net/articles/IRMP_-_english#DENON
73  * Denon published all their IR codes:
74  * http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls
75  * Example:
76  * 0000 006D 0000 0020 000A 001E 000A 0046 000A 001E 000A 001E 000A 001E // 5 address bits
77  * 000A 001E 000A 001E 000A 0046 000A 0046 000A 0046 000A 001E 000A 0046 000A 0046 // 8 command bits
78  * 000A 001E 000A 001E 000A 0679 // 2 frame bits 0,0 + stop bit + space for AutoRepeat
79  * 000A 001E 000A 0046 000A 001E 000A 001E 000A 001E // 5 address bits
80  * 000A 0046 000A 0046 000A 001E 000A 001E 000A 001E 000A 0046 000A 001E 000A 001E // 8 inverted command bits
81  * 000A 0046 000A 0046 000A 0679 // 2 frame bits 1,1 + stop bit + space for Repeat
82  * 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.
83  * All Denon codes with 32 as 3. value use the Kaseikyo Denon variant.
84  */
85 // LSB first, no start bit, 5 address + 8 command + 2 frame (0,0) + 1 stop bit - each frame 2 times
86 // 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.
87 //
88 #define DENON_ADDRESS_BITS 5
89 #define DENON_COMMAND_BITS 8
90 #define DENON_FRAME_BITS 2 // 00/10 for 1. frame Denon/Sharp, inverted for autorepeat frame
91 
92 #define DENON_BITS (DENON_ADDRESS_BITS + DENON_COMMAND_BITS + DENON_FRAME_BITS) // 15 - The number of bits in the command
93 #define DENON_UNIT 260
94 
95 #define DENON_BIT_MARK DENON_UNIT // The length of a Bit:Mark
96 #define DENON_ONE_SPACE (7 * DENON_UNIT) // 1820 // The length of a Bit:Space for 1's
97 #define DENON_ZERO_SPACE (3 * DENON_UNIT) // 780 // The length of a Bit:Space for 0's
98 
99 #define DENON_AUTO_REPEAT_DISTANCE 45000 // Every frame is auto repeated with a space period of 45 ms and the command and frame inverted.
100 #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.
101 
102 // for old decoder
103 #define DENON_HEADER_MARK DENON_UNIT // The length of the Header:Mark
104 #define DENON_HEADER_SPACE (3 * DENON_UNIT) // 780 // The length of the Header:Space
105 
109 
110 /************************************
111  * Start of send and decode functions
112  ************************************/
113 
114 void IRsend::sendSharp(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats) {
115  sendDenon(aAddress, aCommand, aNumberOfRepeats, 1);
116  // see https://github.com/Arduino-IRremote/Arduino-IRremote/issues/1272
117 }
118 
119 void IRsend::sendSharp2(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats) {
120  sendDenon(aAddress, aCommand, aNumberOfRepeats, 2);
121 }
122 
123 /*
124  * Denon frames are always sent 3 times. A non inverted (normal), an inverted frame, ending with a normal frame.
125  * Repeats are done by just adding an inverted and a normal frame with no extra delay, so it is quite responsible :-)
126  * If you specify a repeat of e.g. 3, then 3 + 6 frames are sent.
127  * Measured at Denon RC 1081.
128  */
129 void IRsend::sendDenon(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, uint8_t aSendSharpFrameMarker) {
130  // Set IR carrier frequency
131  enableIROut (DENON_KHZ); // 38 kHz
132 
133  // Add frame marker for sharp
134  uint16_t tCommand = aCommand;
135  // see https://github.com/Arduino-IRremote/Arduino-IRremote/issues/1272
136  tCommand |= aSendSharpFrameMarker << 8; // the 2 upper bits are 00 for Denon and 01 or 10 for Sharp
137 
138  uint16_t tData = aAddress | ((uint16_t) tCommand << DENON_ADDRESS_BITS);
139  uint16_t tInvertedData = (tData ^ 0x7FE0); // Command and frame (upper 10 bits, bit 5 to 14) are inverted
140 
141  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
142  while (tNumberOfCommands > 0) {
143 
144  // Data
145  sendPulseDistanceWidthData_P(&DenonProtocolConstants, tData, DENON_BITS);
146 
147  // Inverted autorepeat frame
149  sendPulseDistanceWidthData_P(&DenonProtocolConstants, tInvertedData, DENON_BITS);
150 
151  tNumberOfCommands--;
152  // send repeated command with a fixed space gap
154  }
155  /*
156  * always end with a normal frame
157  * skip last delay!
158  */
159  sendPulseDistanceWidthData_P(&DenonProtocolConstants, tData, DENON_BITS);
160 
161 }
162 
164  return decodeDenon();
165 }
166 
168 
169  // we have no start bit, so check for the exact amount of data bits
170  // Check we have the right amount of data (32). The + 2 is for initial gap + stop bit mark
171  if (decodedIRData.rawlen != (2 * DENON_BITS) + 2) {
172  DEBUG_PRINT(F("Denon: Data length="));
174  DEBUG_PRINTLN(F(" is not 32"));
175  return false;
176  }
177 
178  // Check for first mark, which is no AGC or start bit. This prevents Sony15 from being decoded as Denon.
179  // matchMark is too sensitive!
180  if (irparams.rawbuf[1] >= ((2 * DENON_HEADER_MARK) / MICROS_PER_TICK)) {
181  DEBUG_PRINTLN(F("Denon: First mark length is wrong"));
182  return false;
183  }
184 
185  // Try to decode as Denon protocol
186  decodePulseDistanceWidthData_P(&DenonProtocolConstants, DENON_BITS, 1);
187 
188  // Success
191  uint8_t tFrameBits = (decodedIRData.command >> 8) & 0x03;
192  decodedIRData.command &= 0xFF;
193 
194  // Check for (auto) repeat
197 
198  repeatCount++;
199  /*
200  * 1. repeat is inverted autorepeat -> IRDATA_FLAGS_IS_AUTO_REPEAT
201  * 2. repeat is normal autorepeat (end) or 1. normal repeat -> IRDATA_FLAGS_IS_AUTO_REPEAT
202  * 3. repeat is inverted autorepeat of the 1. repeat -> IRDATA_FLAGS_IS_REPEAT (not the correct frame, but this enables easy counting of repeats)
203  * 4. repeat is normal autorepeat (end) or 2. normal repeat -> IRDATA_FLAGS_IS_AUTO_REPEAT
204  * 5. repeat is inverted autorepeat of the 2. repeat -> IRDATA_FLAGS_IS_REPEAT (not the correct frame, but this enables easy counting of repeats)
205  * 6. repeat is normal autorepeat (end) or 3. normal repeat -> IRDATA_FLAGS_IS_AUTO_REPEAT
206  */
207 
208  if (repeatCount & 0x01) {
209  /*
210  * Here we are in an inverted auto repeated frame where the command and frame bits are inverted
211  */
212  DEBUG_PRINTLN(F("Denon: Inverted frame"));
213 
214  if (repeatCount > 1) { // skip first auto repeat
216  }
217  // Check parity of consecutive received commands. There is no parity in one data set.
218  if ((uint8_t) lastDecodedCommand != (uint8_t)(~decodedIRData.command)) {
220 
221  DEBUG_PRINT(F("Denon: Parity check of inverted with non inverted frame failed. Last command="));
222  DEBUG_PRINT((uint8_t )lastDecodedCommand, HEX);
223  DEBUG_PRINT(F(" current="));
224  DEBUG_PRINTLN((uint8_t )~decodedIRData.command, HEX);
225  }
226  // always take non inverted command
228 
229  // inverted command here, re-invert the frame bits for later protocol decoding
230  tFrameBits = tFrameBits ^ 0x03;
231  }
232  } else {
233  // first command here
234  repeatCount = 0;
235  }
236 
237  if (tFrameBits) {
239  } else {
241  }
242 
244 
245  return true;
246 }
247 
248 /*********************************************************************************
249  * Old deprecated functions, kept for backward compatibility to old 2.0 tutorials
250  *********************************************************************************/
251 /*
252  * Only for backwards compatibility
253  */
254 void IRsend::sendDenonRaw(uint16_t aRawData, int_fast8_t aNumberOfRepeats) {
255  sendDenon(aRawData >> (DENON_COMMAND_BITS + DENON_FRAME_BITS), (aRawData >> DENON_FRAME_BITS) & 0xFF, aNumberOfRepeats);
256 }
257 
258 /*
259  * Old function with parameter data
260  */
261 void IRsend::sendDenon(unsigned long data, int nbits) {
262  // Set IR carrier frequency
264 #if !(defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__))
266  "The function sendDenon(data, nbits) is deprecated and may not work as expected! Use sendDenonRaw(data, NumberOfRepeats) or better sendDenon(Address, Command, NumberOfRepeats).");
267 #endif
268 
269  // Header
272 
273  // Data
276 }
277 
278 /*
279  * Old function without parameter aNumberOfRepeats
280  */
281 void IRsend::sendSharp(uint16_t aAddress, uint16_t aCommand) {
282  sendDenon(aAddress, aCommand, 0, true);
283 }
284 
286 
287  // Check we have the right amount of data
288  if (decodedIRData.rawlen != 1 + 2 + (2 * DENON_BITS) + 1) {
289  return false;
290  }
291 
292  // Check initial Mark+Space match
293  if (!matchMark(aResults->rawbuf[1], DENON_HEADER_MARK)) {
294  return false;
295  }
296 
297  if (!matchSpace(aResults->rawbuf[2], DENON_HEADER_SPACE)) {
298  return false;
299  }
300 
301  // Try to decode as Denon protocol.
303 
304  // Success
305  aResults->value = decodedIRData.decodedRawData;
306  aResults->bits = DENON_BITS;
307  aResults->decode_type = DENON;
309  return true;
310 }
311 
313 #include "LocalDebugLevelEnd.h"
314 
315 #endif // _IR_DENON_HPP
IRData::address
uint16_t address
Decoded address, Distance protocol (tMarkTicksLong (if tMarkTicksLong == 0, then tMarkTicksShort) << ...
Definition: IRremoteInt.h:164
MICROS_PER_TICK
#define MICROS_PER_TICK
microseconds per clock interrupt tick
Definition: IRremote.hpp:133
DENON_COMMAND_BITS
#define DENON_COMMAND_BITS
Definition: ir_Denon.hpp:89
decode_results
Results returned from old decoders !!!deprecated!!!
Definition: IRremoteInt.h:193
decode_results::rawbuf
uint16_t * rawbuf
Definition: IRremoteInt.h:204
IRrecv::decodePulseDistanceWidthData
void decodePulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset=3)
Decode pulse distance protocols for PulseDistanceWidthProtocolConstants.
Definition: IRReceive.hpp:1076
PROTOCOL_IS_MSB_FIRST
#define PROTOCOL_IS_MSB_FIRST
Definition: IRProtocol.h:156
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRremoteInt.h:173
DEBUG_PRINT
#define DEBUG_PRINT(...)
Definition: LocalDebugLevelStart.h:79
IRsend::aNumberOfRepeats
void int_fast8_t aNumberOfRepeats
Definition: IRremoteInt.h:528
IRrecv::decodePulseDistanceWidthData_P
void decodePulseDistanceWidthData_P(PulseDistanceWidthProtocolConstants const *aProtocolConstantsPGM, uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset=3)
Definition: IRReceive.hpp:1112
MICROS_IN_ONE_MILLI
#define MICROS_IN_ONE_MILLI
Definition: IRremote.hpp:217
DENON_FRAME_BITS
#define DENON_FRAME_BITS
Definition: ir_Denon.hpp:90
PROTOCOL_IS_PULSE_DISTANCE
#define PROTOCOL_IS_PULSE_DISTANCE
Definition: IRProtocol.h:151
IRsend::sendSharp2
void sendSharp2(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats)
Definition: ir_Denon.hpp:119
IRsend::mark
void mark(uint16_t aMarkMicros)
Sends an IR mark for the specified number of microseconds.
Definition: IRSend.hpp:1247
IRDATA_FLAGS_IS_REPEAT
#define IRDATA_FLAGS_IS_REPEAT
The gap between the preceding frame is as smaller than the maximum gap expected for a repeat....
Definition: IRProtocol.h:125
IRrecv::decodeSharp
bool decodeSharp()
Definition: ir_Denon.hpp:163
IRDATA_FLAGS_IS_AUTO_REPEAT
#define IRDATA_FLAGS_IS_AUTO_REPEAT
The current repeat frame is a repeat, that is always sent after a regular frame and cannot be avoided...
Definition: IRProtocol.h:126
decode_results::bits
uint8_t bits
Definition: IRremoteInt.h:199
decode_results::decode_type
decode_type_t decode_type
Definition: IRremoteInt.h:196
DENON_HEADER_MARK
#define DENON_HEADER_MARK
Definition: ir_Denon.hpp:103
matchSpace
bool matchSpace(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros)
Compensate for spaces shortened by demodulator hardware.
Definition: IRReceive.hpp:1375
DENON_REPEAT_PERIOD
#define DENON_REPEAT_PERIOD
Definition: ir_Denon.hpp:100
DENON_ZERO_SPACE
#define DENON_ZERO_SPACE
Definition: ir_Denon.hpp:97
DENON_HEADER_SPACE
#define DENON_HEADER_SPACE
Definition: ir_Denon.hpp:104
IRsend::sendDenon
void sendDenon(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, uint8_t aSendSharpFrameMarker=0)
Definition: ir_Denon.hpp:129
LocalDebugLevelStart.h
IRDATA_FLAGS_PARITY_FAILED
#define IRDATA_FLAGS_PARITY_FAILED
The current (autorepeat) frame violated parity check.
Definition: IRProtocol.h:127
decode_results::value
uint32_t value
Definition: IRremoteInt.h:198
PulseDistanceWidthProtocolConstants
Definition: IRProtocol.h:139
DENON_ONE_SPACE
#define DENON_ONE_SPACE
Definition: ir_Denon.hpp:96
IRrecv::decodedIRData
IRData decodedIRData
Definition: IRremoteInt.h:401
IRData::flags
uint8_t flags
IRDATA_FLAGS_IS_REPEAT, IRDATA_FLAGS_WAS_OVERFLOW etc. See IRDATA_FLAGS_* definitions above.
Definition: IRremoteInt.h:174
PROTOCOL_IS_LSB_FIRST
#define PROTOCOL_IS_LSB_FIRST
Definition: IRProtocol.h:157
IRsend::sendSharp
void sendSharp(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats)
Definition: ir_Denon.hpp:114
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRremoteInt.h:165
IRData::decodedRawData
IRDecodedRawDataType decodedRawData
Up to 32/64 bit decoded raw data, to be used for send<protocol>Raw functions.
Definition: IRremoteInt.h:167
IRsend::sendPulseDistanceWidthData_P
void sendPulseDistanceWidthData_P(PulseDistanceWidthProtocolConstants const *aProtocolConstantsPGM, IRDecodedRawDataType aData, uint_fast8_t aNumberOfBits)
Definition: IRSend.hpp:670
matchMark
bool matchMark(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros)
Compensate for marks exceeded by demodulator hardware.
Definition: IRReceive.hpp:1327
irparams_struct::rawbuf
IRRawbufType rawbuf[RAW_BUFFER_LENGTH]
raw data / tick counts per mark/space. With 8 bit we can only store up to 12.7 ms....
Definition: IRremoteInt.h:147
IRrecv::decodeDenonOld
bool decodeDenonOld(decode_results *aResults)
Definition: ir_Denon.hpp:285
IRrecv::irparams
irparams_struct irparams
Definition: IRremoteInt.h:400
IRrecv::lastDecodedCommand
uint16_t lastDecodedCommand
Definition: IRremoteInt.h:406
DENON
@ DENON
Definition: IRProtocol.h:98
DEBUG_PRINTLN
#define DEBUG_PRINTLN(...)
Definition: LocalDebugLevelStart.h:80
PROGMEM
struct PulseDistanceWidthProtocolConstants const DenonProtocolConstants PROGMEM
Definition: ir_Denon.hpp:106
DENON_AUTO_REPEAT_DISTANCE
#define DENON_AUTO_REPEAT_DISTANCE
Definition: ir_Denon.hpp:99
IRsend::space
static void space(uint16_t aSpaceMicros)
Sends an IR space for the specified number of microseconds.
Definition: IRSend.hpp:1458
DENON_BITS
#define DENON_BITS
Definition: ir_Denon.hpp:92
IRData::rawlen
IRRawlenType rawlen
Counter of entries in rawbuf of last received frame.
Definition: IRremoteInt.h:182
IRsend::sendPulseDistanceWidthData
void sendPulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, IRDecodedRawDataType aData, uint_fast8_t aNumberOfBits)
Sends PulseDistance from data contained in parameter using ProtocolConstants structure for timing etc...
Definition: IRSend.hpp:662
DENON_ADDRESS_BITS
#define DENON_ADDRESS_BITS
Definition: ir_Denon.hpp:88
IRrecv::decodeDenon
bool decodeDenon()
Definition: ir_Denon.hpp:167
DENON_BIT_MARK
#define DENON_BIT_MARK
Definition: ir_Denon.hpp:95
DENON_KHZ
#define DENON_KHZ
Definition: IRProtocol.h:168
IRsend::sendDenonRaw
void sendDenonRaw(uint16_t aRawData, int_fast8_t aNumberOfRepeats=NO_REPEATS) __attribute__((deprecated("Please use sendDenon(aAddress
Definition: ir_Denon.hpp:254
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRremoteInt.h:163
IRsend::aCommand
void aCommand
Definition: IRremoteInt.h:617
IRData::initialGapTicks
uint16_t initialGapTicks
Contains the initial gap (pre 4.4: the value in rawbuf[0]) of the last received frame.
Definition: IRremoteInt.h:183
IRsend::enableIROut
void enableIROut(uint_fast8_t aFrequencyKHz)
Enables IR output.
Definition: IRSend.hpp:1498
LocalDebugLevelEnd.h
SHARP
@ SHARP
Definition: IRProtocol.h:101
IRrecv::repeatCount
uint8_t repeatCount
Definition: IRremoteInt.h:411