2021-11-08 03:44:07 +08:00
/*
* 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
*
2023-02-24 09:40:21 +08:00
* Copyright ( c ) 2020 - 2023 Armin Joachimsmeyer
2021-11-08 03:44:07 +08:00
*
* 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 .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2022-03-30 17:55:04 +08:00
# ifndef _IR_DENON_HPP
# define _IR_DENON_HPP
2021-11-08 03:44:07 +08:00
2022-11-13 04:42:07 +08:00
# if defined(DEBUG) && !defined(LOCAL_DEBUG)
# define LOCAL_DEBUG
# else
//#define LOCAL_DEBUG // This enables debug output only for this file
# endif
2021-11-08 03:44:07 +08:00
/** \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
//==============================================================================
2022-11-13 04:42:07 +08:00
/*
2022-12-14 02:30:34 +08:00
Protocol = Denon Address = 0x11 Command = 0x76 Raw - Data = 0xED1 15 bits LSB first
2022-11-17 08:06:10 +08:00
+ 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
2022-12-14 02:30:34 +08:00
Sum : 23050
2022-11-17 08:06:10 +08:00
2022-12-14 02:30:34 +08:00
Denon / Sharp variant
Protocol = Denon Address = 0x11 Command = 0x76 Raw - Data = 0x4ED1 15 bits LSB first
2022-11-17 08:06:10 +08:00
+ 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
2022-12-14 02:30:34 +08:00
Sum : 23050
2022-11-17 08:06:10 +08:00
*/
/*
* 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 006 D 0000 0020 000 A 001 E 000 A 0046 000 A 001 E 000 A 001 E 000 A 001 E // 5 address bits
* 000 A 001 E 000 A 001 E 000 A 0046 000 A 0046 000 A 0046 000 A 001 E 000 A 0046 000 A 0046 // 8 command bits
* 000 A 001 E 000 A 001 E 000 A 067 9 // 2 frame bits 0,0 + stop bit + space for AutoRepeat
* 000 A 001 E 000 A 0046 000 A 001 E 000 A 001 E 000 A 001 E // 5 address bits
* 000 A 0046 000 A 0046 000 A 001 E 000 A 001 E 000 A 001 E 000 A 0046 000 A 001 E 000 A 001 E // 8 inverted command bits
* 000 A 0046 000 A 0046 000 A 067 9 // 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 .
2022-11-13 04:42:07 +08:00
*/
2022-12-14 02:30:34 +08:00
// 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.
2021-11-08 03:44:07 +08:00
//
# 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
2022-11-12 02:53:54 +08:00
# 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.
2021-11-08 03:44:07 +08:00
// 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
2022-11-10 05:49:55 +08:00
struct PulseDistanceWidthProtocolConstants DenonProtocolConstants = { DENON , DENON_KHZ , DENON_HEADER_MARK , DENON_HEADER_SPACE ,
2023-02-24 09:40:21 +08:00
DENON_BIT_MARK , DENON_ONE_SPACE , DENON_BIT_MARK , DENON_ZERO_SPACE , PROTOCOL_IS_LSB_FIRST ,
( DENON_REPEAT_PERIOD / MICROS_IN_ONE_MILLI ) , NULL } ;
2021-11-08 03:44:07 +08:00
2022-08-31 19:25:29 +08:00
/************************************
* Start of send and decode functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void IRsend : : sendSharp ( uint8_t aAddress , uint8_t aCommand , int_fast8_t aNumberOfRepeats ) {
sendDenon ( aAddress , aCommand , aNumberOfRepeats , true ) ;
2021-11-08 03:44:07 +08:00
}
2022-08-31 19:25:29 +08:00
void IRsend : : sendDenon ( uint8_t aAddress , uint8_t aCommand , int_fast8_t aNumberOfRepeats , bool aSendSharp ) {
2021-11-08 03:44:07 +08:00
// Set IR carrier frequency
2022-11-17 08:06:10 +08:00
enableIROut ( DENON_KHZ ) ; // 38 kHz
2021-11-08 03:44:07 +08:00
2022-11-17 08:06:10 +08:00
// Add frame marker for sharp
uint16_t tCommand = aCommand ;
2021-11-08 03:44:07 +08:00
if ( aSendSharp ) {
2022-11-17 08:06:10 +08:00
tCommand | = 0x0200 ; // the 2 upper bits are 00 for Denon and 10 for Sharp
2021-11-08 03:44:07 +08:00
}
2022-11-17 08:06:10 +08:00
uint16_t tData = aAddress | ( ( uint16_t ) tCommand < < DENON_ADDRESS_BITS ) ;
2022-12-14 02:30:34 +08:00
uint16_t tInvertedData = ( tData ^ 0x7FE0 ) ; // Command and frame (upper 10 bits) are inverted
2021-11-08 03:44:07 +08:00
uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1 ;
while ( tNumberOfCommands > 0 ) {
// Data
2022-08-31 19:25:29 +08:00
sendPulseDistanceWidthData ( & DenonProtocolConstants , tData , DENON_BITS ) ;
2021-11-08 03:44:07 +08:00
// Inverted autorepeat frame
2022-11-12 02:53:54 +08:00
delay ( DENON_AUTO_REPEAT_DISTANCE / MICROS_IN_ONE_MILLI ) ;
2022-08-31 19:25:29 +08:00
sendPulseDistanceWidthData ( & DenonProtocolConstants , tInvertedData , DENON_BITS ) ;
2021-11-08 03:44:07 +08:00
tNumberOfCommands - - ;
// skip last delay!
if ( tNumberOfCommands > 0 ) {
// send repeated command with a fixed space gap
2022-11-12 02:53:54 +08:00
delay ( DENON_AUTO_REPEAT_DISTANCE / MICROS_IN_ONE_MILLI ) ;
2021-11-08 03:44:07 +08:00
}
}
}
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
2024-02-24 02:28:33 +08:00
if ( decodedIRData . rawlen ! = ( 2 * DENON_BITS ) + 2 ) {
2021-11-29 20:41:03 +08:00
IR_DEBUG_PRINT ( F ( " Denon: " ) ) ;
2022-05-19 15:51:34 +08:00
IR_DEBUG_PRINT ( F ( " Data length= " ) ) ;
2024-02-24 02:28:33 +08:00
IR_DEBUG_PRINT ( decodedIRData . rawlen ) ;
2022-05-19 15:51:34 +08:00
IR_DEBUG_PRINTLN ( F ( " is not 32 " ) ) ;
2021-11-08 03:44:07 +08:00
return false ;
}
2022-11-17 08:06:10 +08:00
// Try to decode as Denon protocol
2022-11-10 05:49:55 +08:00
if ( ! decodePulseDistanceWidthData ( & DenonProtocolConstants , DENON_BITS , 1 ) ) {
2022-11-13 04:42:07 +08:00
# if defined(LOCAL_DEBUG)
Serial . print ( F ( " Denon: " ) ) ;
Serial . println ( F ( " Decode failed " ) ) ;
# endif
2021-11-08 03:44:07 +08:00
return false ;
}
// Check for stop mark
if ( ! matchMark ( decodedIRData . rawDataPtr - > rawbuf [ ( 2 * DENON_BITS ) + 1 ] , DENON_HEADER_MARK ) ) {
2022-11-13 04:42:07 +08:00
# if defined(LOCAL_DEBUG)
Serial . print ( F ( " Denon: " ) ) ;
Serial . println ( F ( " Stop bit mark length is wrong " ) ) ;
# endif
2021-11-08 03:44:07 +08:00
return false ;
}
// Success
2022-11-17 08:06:10 +08:00
decodedIRData . address = decodedIRData . decodedRawData & 0x1F ;
decodedIRData . command = decodedIRData . decodedRawData > > DENON_ADDRESS_BITS ;
uint8_t tFrameBits = ( decodedIRData . command > > 8 ) & 0x03 ;
2022-07-12 17:46:04 +08:00
decodedIRData . command & = 0xFF ;
2021-11-08 03:44:07 +08:00
2022-11-17 08:06:10 +08:00
// Check for (auto) repeat
2024-02-24 02:28:33 +08:00
if ( decodedIRData . initialGap < ( ( DENON_AUTO_REPEAT_DISTANCE + ( DENON_AUTO_REPEAT_DISTANCE / 4 ) ) / MICROS_PER_TICK ) ) {
2021-11-08 03:44:07 +08:00
repeatCount + + ;
2022-12-14 02:30:34 +08:00
if ( repeatCount > 1 ) { // skip first auto repeat
decodedIRData . flags = IRDATA_FLAGS_IS_REPEAT ;
}
2022-11-17 08:06:10 +08:00
if ( tFrameBits & 0x01 ) {
2022-12-14 02:30:34 +08:00
/*
* Here we are in the auto repeated frame with the inverted command
*/
2022-11-17 08:06:10 +08:00
# if defined(LOCAL_DEBUG)
Serial . print ( F ( " Denon: " ) ) ;
Serial . println ( F ( " Autorepeat received= " ) ) ;
# endif
2022-12-14 02:30:34 +08:00
decodedIRData . flags | = IRDATA_FLAGS_IS_AUTO_REPEAT ;
2021-11-08 03:44:07 +08:00
// Check parity of consecutive received commands. There is no parity in one data set.
2022-11-17 08:06:10 +08:00
if ( ( uint8_t ) lastDecodedCommand ! = ( uint8_t ) ( ~ decodedIRData . command ) ) {
2021-11-08 03:44:07 +08:00
decodedIRData . flags | = IRDATA_FLAGS_PARITY_FAILED ;
2022-11-13 04:42:07 +08:00
# if defined(LOCAL_DEBUG)
Serial . print ( F ( " Denon: " ) ) ;
2023-02-24 09:40:21 +08:00
Serial . print ( F ( " Parity check for repeat failed. Last command= " ) ) ;
2022-11-13 04:42:07 +08:00
Serial . print ( lastDecodedCommand , HEX ) ;
Serial . print ( F ( " current= " ) ) ;
Serial . println ( ~ decodedIRData . command , HEX ) ;
# endif
2021-11-08 03:44:07 +08:00
}
// always take non inverted command
2022-07-12 17:46:04 +08:00
decodedIRData . command = lastDecodedCommand ;
2021-11-08 03:44:07 +08:00
}
2022-12-14 02:30:34 +08:00
// repeated command here
2023-02-24 09:40:21 +08:00
if ( tFrameBits = = 1 | | tFrameBits = = 2 ) {
2022-12-14 02:30:34 +08:00
decodedIRData . protocol = SHARP ;
} else {
decodedIRData . protocol = DENON ;
2021-11-08 03:44:07 +08:00
}
} else {
repeatCount = 0 ;
2022-12-14 02:30:34 +08:00
// first command here
if ( tFrameBits = = 2 ) {
2022-11-17 08:06:10 +08:00
decodedIRData . protocol = SHARP ;
} else {
decodedIRData . protocol = DENON ;
}
2021-11-08 03:44:07 +08:00
}
decodedIRData . numberOfBits = DENON_BITS ;
2022-11-17 08:06:10 +08:00
2021-11-08 03:44:07 +08:00
return true ;
}
2022-08-31 19:25:29 +08:00
/*********************************************************************************
* 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
2022-11-17 08:06:10 +08:00
enableIROut ( DENON_KHZ ) ;
2022-08-31 19:25:29 +08:00
# if !(defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__))
2023-02-12 20:02:01 +08:00
// 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).");
2022-08-31 19:25:29 +08:00
# 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 ,
2023-02-24 09:40:21 +08:00
PROTOCOL_IS_MSB_FIRST ) ;
2022-08-31 19:25:29 +08:00
}
/*
* Old function without parameter aNumberOfRepeats
*/
2023-02-24 09:40:21 +08:00
void IRsend : : sendSharp ( uint16_t aAddress , uint16_t aCommand ) {
2022-08-31 19:25:29 +08:00
sendDenon ( aAddress , aCommand , true , 0 ) ;
}
2021-11-08 03:44:07 +08:00
bool IRrecv : : decodeDenonOld ( decode_results * aResults ) {
// Check we have the right amount of data
2024-02-24 02:28:33 +08:00
if ( decodedIRData . rawlen ! = 1 + 2 + ( 2 * DENON_BITS ) + 1 ) {
2021-11-08 03:44:07 +08:00
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 ;
}
2022-11-17 08:06:10 +08:00
// Try to decode as Denon protocol
2022-11-10 05:49:55 +08:00
if ( ! decodePulseDistanceWidthData ( DENON_BITS , 3 , DENON_BIT_MARK , 0 , DENON_ONE_SPACE , DENON_ZERO_SPACE , PROTOCOL_IS_MSB_FIRST ) ) {
2021-11-08 03:44:07 +08:00
return false ;
}
// Success
aResults - > value = decodedIRData . decodedRawData ;
aResults - > bits = DENON_BITS ;
aResults - > decode_type = DENON ;
decodedIRData . protocol = DENON ;
return true ;
}
/** @}*/
2022-11-13 04:42:07 +08:00
# if defined(LOCAL_DEBUG)
# undef LOCAL_DEBUG
# endif
2022-03-30 17:55:04 +08:00
# endif // _IR_DENON_HPP