2022-10-02 16:00:58 +08:00
/*
* ir_BangOlufsen . hpp
*
* Contains functions for receiving and sending Bang & Olufsen IR and Datalink ' 86 protocols
2022-10-12 23:57:57 +08:00
* To receive B & O and ENABLE_BEO_WITHOUT_FRAME_GAP is NOT defined , you must set RECORD_GAP_MICROS to
* at least 16000 to accommodate the unusually long 3. start space .
2022-10-02 16:00:58 +08:00
*
* This file is part of Arduino - IRremote https : //github.com/Arduino-IRremote/Arduino-IRremote.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* MIT License
*
2023-04-17 23:54:24 +08:00
* Copyright ( c ) 2022 - 2023 Daniel Wallner and Armin Joachimsmeyer
2022-10-02 16:00:58 +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 .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
# ifndef _IR_BANG_OLUFSEN_HPP
# define _IR_BANG_OLUFSEN_HPP
//==============================================================================
//
//
// Bang & Olufsen
//
//
//==============================================================================
// https://www.mikrocontroller.net/attachment/33137/datalink.pdf
2022-10-03 02:45:57 +08:00
// https://www.mikrocontroller.net/articles/IRMP_-_english#B&O
2022-10-02 16:00:58 +08:00
// This protocol is unusual in two ways:
// 1. The carrier frequency is 455 kHz
// You can build your own receiver as Bang & Olufsen did (check old schematics) or use a TSOP7000
2022-12-30 01:46:09 +08:00
// Vishay stopped producing TSOP7000 since 2009 so you will probably only find counterfeits:
2022-10-02 16:00:58 +08:00
// https://www.vishay.com/files/whatsnew/doc/ff_FastFacts_CounterfeitTSOP7000_Dec72018.pdf
// It is also likely that you will need an oscilloscope to debug a counterfeit TSOP7000
// The specimen used to test this code was very noisy and had a very low output current
// A somewhat working fix was to put a 4n7 capacitor across the output and ground followed by a pnp emitter follower
// Other examples may require a different treatment
// This particular receiver also did receive lower frequencies but rather poorly and with a lower delay than usual
// If you need to parallel a receiver with another one you may need to delay the signal to get in phase with the other receiver
// 2. A stream of messages can be sent back to back with a new message immediately following the previous stop space
// It might be that this only happens over IR and not on the datalink protocol
// You can choose to support this or not:
2024-04-26 03:16:40 +08:00
// Mode 1: Mode with gaps between frames
// Set RECORD_GAP_MICROS to at least 16000 to accept the unusually long 3. start space
// Can only receive single messages. Back to back repeats will result in overflow
// Mode 2: Break at start mode
// Define ENABLE_BEO_WITHOUT_FRAME_GAP and set RECORD_GAP_MICROS to less than 15000
// to treat the 3. start space of 15.5 ms as a gap between messages, which makes decoding easier :-).
// The receiving of a transmission will then result in a dummy decode of the first 2 start bits with 0 bits data
// followed by a 15.5 ms gap and a data frame with one start bit (originally sent as 4. start bit).
2022-10-03 02:45:57 +08:00
// If the receiver is not resumed within a ms or so, partial messages will be decoded
2022-10-02 16:00:58 +08:00
// Debug printing in the wrong place is very likely to break reception
// Make sure to check the number of bits to filter dummy and incomplete messages
2022-10-03 02:45:57 +08:00
// !!! We assume that the real implementations never set the official first header bit to anything other than 0 !!!
// !!! We therefore use 4 start bits instead of the specified 3 and in turn ignore the first header bit of the specification !!!
2022-10-02 16:00:58 +08:00
2023-11-03 05:03:25 +08:00
// IR messages are 16 bits long. Datalink messages have different lengths.
2022-10-02 16:00:58 +08:00
// This implementation supports up to 40 bits total length split into 8 bit data/command and a header/address of variable length
// Header data with more than 16 bits is stored in decodedIRData.extra
2022-10-03 02:45:57 +08:00
// B&O is a pulse distance protocol, but it has 3 bit values 0, 1 and (equal/repeat) as well as a special start and trailing bit.
2024-04-26 03:16:40 +08:00
//
2022-10-03 02:45:57 +08:00
// MSB first, 4 start bits + 8 to 16? bit address + 8 bit command + 1 special trailing bit + 1 stop bit.
// Address can be longer than 8 bit.
/*
* Options for this decoder
2023-11-03 05:03:25 +08:00
*
2022-10-03 02:45:57 +08:00
*/
2023-11-03 05:03:25 +08:00
# define ENABLE_BEO_WITHOUT_FRAME_GAP // Requires additional 30 bytes program memory. Enabled by default, see https://github.com/Arduino-IRremote/Arduino-IRremote/discussions/1181
2022-10-03 02:45:57 +08:00
//#define SUPPORT_BEO_DATALINK_TIMING_FOR_DECODE // This also supports headers up to 32 bit. Requires additional 150 bytes program memory.
# if defined(DECODE_BEO)
# if defined(ENABLE_BEO_WITHOUT_FRAME_GAP)
2024-04-26 03:16:40 +08:00
# if RECORD_GAP_MICROS > 15000
# warning If defined ENABLE_BEO_WITHOUT_FRAME_GAP, RECORD_GAP_MICROS must be set to <= 15000 by "#define RECORD_GAP_MICROS 13000"
2022-10-03 02:45:57 +08:00
# endif
# else
# if RECORD_GAP_MICROS < 16000
2024-04-26 03:16:40 +08:00
# error If not defined ENABLE_BEO_WITHOUT_FRAME_GAP, RECORD_GAP_MICROS must be set to a value >= 16000 by "#define RECORD_GAP_MICROS 16000"
2022-10-03 02:45:57 +08:00
# endif
# endif
# endif
2022-10-02 16:00:58 +08:00
# define BEO_DATA_BITS 8 // Command or character
# define BEO_UNIT 3125 // All timings are in microseconds
# define BEO_IR_MARK 200 // The length of a mark in the IR protocol
# define BEO_DATALINK_MARK (BEO_UNIT / 2) // The length of a mark in the Datalink protocol
2022-10-03 02:45:57 +08:00
# define BEO_PULSE_LENGTH_ZERO BEO_UNIT // The length of a one to zero transition
# define BEO_PULSE_LENGTH_EQUAL (2 * BEO_UNIT) // 6250 The length of an equal bit
# define BEO_PULSE_LENGTH_ONE (3 * BEO_UNIT) // 9375 The length of a zero to one transition
# define BEO_PULSE_LENGTH_TRAILING_BIT (4 * BEO_UNIT) // 12500 The length of the stop bit
# define BEO_PULSE_LENGTH_START_BIT (5 * BEO_UNIT) // 15625 The length of the start bit
// It is not allowed to send two ones or zeros, you must send a one or zero and a equal instead.
2022-10-02 16:00:58 +08:00
//#define BEO_LOCAL_DEBUG
//#define BEO_LOCAL_TRACE
# ifdef BEO_LOCAL_DEBUG
2022-10-03 02:45:57 +08:00
# define BEO_DEBUG_PRINT(...) Serial.print(__VA_ARGS__)
# define BEO_DEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
# else
# define BEO_DEBUG_PRINT(...) void()
# define BEO_DEBUG_PRINTLN(...) void()
2022-10-02 16:00:58 +08:00
# endif
# ifdef BEO_LOCAL_TRACE
2022-10-03 02:45:57 +08:00
# undef BEO_TRACE_PRINT
# undef BEO_TRACE_PRINTLN
# define BEO_TRACE_PRINT(...) Serial.print(__VA_ARGS__)
# define BEO_TRACE_PRINTLN(...) Serial.println(__VA_ARGS__)
# else
# define BEO_TRACE_PRINT(...) void()
# define BEO_TRACE_PRINTLN(...) void()
2022-10-02 16:00:58 +08:00
# endif
/************************************
* Start of send and decode functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-10-03 02:45:57 +08:00
/*
* TODO aNumberOfRepeats are handled not correctly if ENABLE_BEO_WITHOUT_FRAME_GAP is defined
*/
void IRsend : : sendBangOlufsen ( uint16_t aHeader , uint8_t aData , int_fast8_t aNumberOfRepeats , int8_t aNumberOfHeaderBits ) {
2022-11-13 04:42:07 +08:00
for ( int_fast8_t i = 0 ; i < aNumberOfRepeats + 1 ; + + i ) {
2022-10-03 02:45:57 +08:00
sendBangOlufsenRaw ( ( uint32_t ( aHeader ) < < 8 ) | aData , aNumberOfHeaderBits + 8 , i ! = 0 ) ;
2022-10-02 16:00:58 +08:00
}
}
2022-10-03 02:45:57 +08:00
void IRsend : : sendBangOlufsenDataLink ( uint32_t aHeader , uint8_t aData , int_fast8_t aNumberOfRepeats , int8_t aNumberOfHeaderBits ) {
2022-11-13 04:42:07 +08:00
for ( int_fast8_t i = 0 ; i < aNumberOfRepeats + 1 ; + + i ) {
2022-10-03 02:45:57 +08:00
sendBangOlufsenRawDataLink ( ( uint64_t ( aHeader ) < < 8 ) | aData , aNumberOfHeaderBits + 8 , i ! = 0 , true ) ;
}
}
2022-10-02 16:00:58 +08:00
2022-10-03 02:45:57 +08:00
/*
* @ param aBackToBack If true send data back to back , which cannot be decoded if ENABLE_BEO_WITHOUT_FRAME_GAP is NOT defined
*/
void IRsend : : sendBangOlufsenRaw ( uint32_t aRawData , int_fast8_t aBits , bool aBackToBack ) {
2023-03-29 19:28:06 +08:00
# if defined(USE_NO_SEND_PWM) || defined(SEND_PWM_BY_TIMER) || BEO_KHZ == 38 // BEO_KHZ == 38 is for unit test which runs the B&O protocol with 38 kHz
2023-02-24 09:40:21 +08:00
2022-10-03 02:45:57 +08:00
/*
2023-03-29 19:28:06 +08:00
* 455 kHz PWM is currently only supported with SEND_PWM_BY_TIMER defined , otherwise maximum is 180 kHz
2022-10-03 02:45:57 +08:00
*/
2023-03-25 01:13:36 +08:00
# if !defined(USE_NO_SEND_PWM)
2023-03-29 19:28:06 +08:00
# if defined(SEND_PWM_BY_TIMER)
enableHighFrequencyIROut ( BEO_KHZ ) ;
# elif (BEO_KHZ == 38)
2023-03-25 01:13:36 +08:00
enableIROut ( BEO_KHZ ) ; // currently only for unit test
2023-03-29 19:28:06 +08:00
# endif
2023-03-25 01:13:36 +08:00
# endif
2022-10-03 02:45:57 +08:00
// AGC / Start - 3 bits + first constant 0 header bit described in the official documentation
2022-10-02 16:00:58 +08:00
if ( ! aBackToBack ) {
2022-10-03 02:45:57 +08:00
mark ( BEO_IR_MARK ) ;
}
space ( BEO_PULSE_LENGTH_ZERO - BEO_IR_MARK ) ;
mark ( BEO_IR_MARK ) ;
space ( BEO_PULSE_LENGTH_ZERO - BEO_IR_MARK ) ;
mark ( BEO_IR_MARK ) ;
space ( BEO_PULSE_LENGTH_START_BIT - BEO_IR_MARK ) ;
// First bit of header is assumed to be a constant 0 to have a fixed state to begin with the equal decisions.
// So this first 0 is treated as the last bit of AGC
mark ( BEO_IR_MARK ) ;
space ( BEO_PULSE_LENGTH_ZERO - BEO_IR_MARK ) ;
bool tLastBitValueWasOne = false ;
// Header / Data
uint32_t mask = 1UL < < ( aBits - 1 ) ;
for ( ; mask ; mask > > = 1 ) {
if ( tLastBitValueWasOne & & ! ( aRawData & mask ) ) {
mark ( BEO_IR_MARK ) ;
space ( BEO_PULSE_LENGTH_ZERO - BEO_IR_MARK ) ;
tLastBitValueWasOne = false ;
} else if ( ! tLastBitValueWasOne & & ( aRawData & mask ) ) {
mark ( BEO_IR_MARK ) ;
space ( BEO_PULSE_LENGTH_ONE - BEO_IR_MARK ) ;
tLastBitValueWasOne = true ;
} else {
mark ( BEO_IR_MARK ) ;
space ( BEO_PULSE_LENGTH_EQUAL - BEO_IR_MARK ) ;
}
2022-10-02 16:00:58 +08:00
}
2022-10-03 02:45:57 +08:00
// Stop
mark ( BEO_IR_MARK ) ;
space ( BEO_PULSE_LENGTH_TRAILING_BIT - BEO_IR_MARK ) ;
mark ( BEO_IR_MARK ) ;
2022-10-02 16:00:58 +08:00
2022-10-03 02:45:57 +08:00
# else
( void ) aRawData ;
( void ) aBits ;
( void ) aBackToBack ;
# endif
}
/*
2022-11-14 22:00:43 +08:00
* Version with 64 bit aRawData , which can send both timings , but costs more program memory
2022-10-03 02:45:57 +08:00
* @ param aBackToBack If true send data back to back , which cannot be decoded if ENABLE_BEO_WITHOUT_FRAME_GAP is NOT defined
* @ param aUseDatalinkTiming if false it does the same as sendBangOlufsenRaw ( )
*/
void IRsend : : sendBangOlufsenRawDataLink ( uint64_t aRawData , int_fast8_t aBits , bool aBackToBack , bool aUseDatalinkTiming ) {
2022-10-12 23:57:57 +08:00
# if defined(USE_NO_SEND_PWM) || BEO_KHZ == 38 // BEO_KHZ == 38 is for unit test which runs the B&O protocol with 38 kHz instead 0f 455 kHz
2022-10-03 02:45:57 +08:00
uint16_t tSendBEOMarkLength = aUseDatalinkTiming ? BEO_DATALINK_MARK : BEO_IR_MARK ;
/*
* 455 kHz PWM is currently not supported , maximum is 180 kHz
*/
2023-02-24 09:40:21 +08:00
# if !defined(USE_NO_SEND_PWM)
2022-10-03 02:45:57 +08:00
enableIROut ( BEO_KHZ ) ;
2023-02-24 09:40:21 +08:00
# endif
2022-10-03 02:45:57 +08:00
// AGC / Start - 3 bits + first constant 0 header bit described in the official documentation
if ( ! aBackToBack ) {
mark ( tSendBEOMarkLength ) ;
}
space ( BEO_PULSE_LENGTH_ZERO - tSendBEOMarkLength ) ;
mark ( tSendBEOMarkLength ) ;
space ( BEO_PULSE_LENGTH_ZERO - tSendBEOMarkLength ) ;
mark ( tSendBEOMarkLength ) ;
space ( BEO_PULSE_LENGTH_START_BIT - tSendBEOMarkLength ) ;
// First bit of header is assumed to be a constant 0 to have a fixed state to begin with the equal decisions.
// So this first 0 is treated as the last bit of AGC
mark ( tSendBEOMarkLength ) ;
space ( BEO_PULSE_LENGTH_ZERO - tSendBEOMarkLength ) ;
bool tLastBitValueWasOne = false ;
// Header / Data
uint32_t mask = 1UL < < ( aBits - 1 ) ;
2022-10-02 16:00:58 +08:00
for ( ; mask ; mask > > = 1 ) {
2022-10-03 02:45:57 +08:00
if ( tLastBitValueWasOne & & ! ( aRawData & mask ) ) {
mark ( tSendBEOMarkLength ) ;
space ( BEO_PULSE_LENGTH_ZERO - tSendBEOMarkLength ) ;
tLastBitValueWasOne = false ;
} else if ( ! tLastBitValueWasOne & & ( aRawData & mask ) ) {
mark ( tSendBEOMarkLength ) ;
space ( BEO_PULSE_LENGTH_ONE - tSendBEOMarkLength ) ;
tLastBitValueWasOne = true ;
2022-10-02 16:00:58 +08:00
} else {
2022-10-03 02:45:57 +08:00
mark ( tSendBEOMarkLength ) ;
space ( BEO_PULSE_LENGTH_EQUAL - tSendBEOMarkLength ) ;
2022-10-02 16:00:58 +08:00
}
}
2022-10-03 02:45:57 +08:00
// Stop
mark ( tSendBEOMarkLength ) ;
space ( BEO_PULSE_LENGTH_TRAILING_BIT - tSendBEOMarkLength ) ;
mark ( tSendBEOMarkLength ) ;
2022-10-02 16:00:58 +08:00
2022-10-03 02:45:57 +08:00
# else
( void ) aRawData ;
( void ) aBits ;
( void ) aUseDatalinkTiming ;
( void ) aBackToBack ;
# endif
2022-10-02 16:00:58 +08:00
}
2022-10-03 02:45:57 +08:00
# define BEO_MATCH_DELTA (BEO_UNIT / 2 - MICROS_PER_TICK)
static bool matchBeoLength ( uint16_t aMeasuredTicks , uint16_t aMatchValueMicros ) {
const uint16_t tMeasuredMicros = aMeasuredTicks * MICROS_PER_TICK ;
return aMatchValueMicros - BEO_MATCH_DELTA < tMeasuredMicros & & tMeasuredMicros < aMatchValueMicros + BEO_MATCH_DELTA ;
2022-10-02 16:00:58 +08:00
}
bool IRrecv : : decodeBangOlufsen ( ) {
2022-10-03 02:45:57 +08:00
# if defined(ENABLE_BEO_WITHOUT_FRAME_GAP)
2024-02-24 02:28:33 +08:00
if ( decodedIRData . rawlen ! = 6 & & decodedIRData . rawlen < 36 ) { // 16 bits minimum
2022-10-02 16:00:58 +08:00
# else
2024-02-24 02:28:33 +08:00
if ( decodedIRData . rawlen < 44 ) { // 16 bits minimum
2022-10-02 16:00:58 +08:00
# endif
return false ;
}
2022-10-03 02:45:57 +08:00
# if defined(SUPPORT_BEO_DATALINK_TIMING_FOR_DECODE)
uint16_t protocolMarkLength = 0 ; // contains BEO_IR_MARK or BEO_DATALINK_MARK depending of 4. mark received
uint64_t tDecodedRawData = 0 ;
# else
uint32_t tDecodedRawData = 0 ;
2022-10-02 16:00:58 +08:00
# endif
2022-10-03 02:45:57 +08:00
uint8_t tLastDecodedBitValue = 0 ; // the last start bit is assumed to be zero
uint8_t tPulseNumber = 0 ;
uint8_t tBitNumber = 0 ;
BEO_TRACE_PRINT ( F ( " Pre gap: " ) ) ;
2024-02-24 02:28:33 +08:00
BEO_TRACE_PRINT ( decodedIRData . initialGap * 50 ) ;
2022-10-03 02:45:57 +08:00
BEO_TRACE_PRINT ( F ( " raw len: " ) ) ;
2024-02-24 02:28:33 +08:00
BEO_TRACE_PRINTLN ( decodedIRData . rawlen ) ;
2022-10-03 02:45:57 +08:00
# if defined(ENABLE_BEO_WITHOUT_FRAME_GAP)
/*
2024-04-26 03:16:40 +08:00
* Check if we have the AGC part of the first frame , i . e . start bit 1 and 2.
2022-10-03 02:45:57 +08:00
*/
2024-02-24 02:28:33 +08:00
if ( decodedIRData . rawlen = = 6 ) {
2022-10-03 02:45:57 +08:00
if ( ( matchMark ( decodedIRData . rawDataPtr - > rawbuf [ 3 ] , BEO_IR_MARK )
| | matchMark ( decodedIRData . rawDataPtr - > rawbuf [ 3 ] , BEO_DATALINK_MARK ) )
& & ( matchSpace ( decodedIRData . rawDataPtr - > rawbuf [ 4 ] , BEO_PULSE_LENGTH_ZERO - BEO_IR_MARK )
| | matchSpace ( decodedIRData . rawDataPtr - > rawbuf [ 4 ] , BEO_PULSE_LENGTH_ZERO - BEO_DATALINK_MARK ) ) ) {
BEO_TRACE_PRINT ( : : getProtocolString ( BANG_OLUFSEN ) ) ;
2024-04-26 03:16:40 +08:00
BEO_TRACE_PRINTLN ( F ( " B&O: AGC only part (start bits 1 + 2 of 4) detected " ) ) ;
2022-10-03 02:45:57 +08:00
} else {
return false ; // no B&O protocol
}
} else {
/*
* Check if leading gap is trailing bit of first frame
*/
2024-02-24 02:28:33 +08:00
if ( ! matchSpace ( decodedIRData . initialGap , BEO_PULSE_LENGTH_START_BIT ) ) {
2022-10-03 02:45:57 +08:00
BEO_TRACE_PRINT ( : : getProtocolString ( BANG_OLUFSEN ) ) ;
BEO_TRACE_PRINTLN ( F ( " : Leading gap is wrong " ) ) ; // Leading gap is trailing bit of first frame
return false ; // no B&O protocol
2022-10-02 16:00:58 +08:00
}
2022-10-03 02:45:57 +08:00
if ( matchMark ( decodedIRData . rawDataPtr - > rawbuf [ 1 ] , BEO_IR_MARK ) ) {
2024-04-26 03:16:40 +08:00
# if defined(SUPPORT_BEO_DATALINK_TIMING_FOR_DECODE)
2022-10-03 02:45:57 +08:00
protocolMarkLength = BEO_IR_MARK ;
} else if ( matchMark ( decodedIRData . rawDataPtr - > rawbuf [ 1 ] , BEO_DATALINK_MARK ) ) {
protocolMarkLength = BEO_DATALINK_MARK ;
2024-04-26 03:16:40 +08:00
# endif
2022-10-03 02:45:57 +08:00
} else {
BEO_TRACE_PRINT ( : : getProtocolString ( BANG_OLUFSEN ) ) ;
BEO_TRACE_PRINTLN ( F ( " : mark length is wrong " ) ) ;
return false ;
2022-10-02 16:00:58 +08:00
}
2022-10-03 02:45:57 +08:00
// skip first zero header bit
2024-02-24 02:28:33 +08:00
for ( uint8_t tRawBufferMarkIndex = 3 ; tRawBufferMarkIndex < decodedIRData . rawlen ; tRawBufferMarkIndex + = 2 ) {
2022-10-03 02:45:57 +08:00
# else
2024-02-24 02:28:33 +08:00
for ( uint8_t tRawBufferMarkIndex = 1 ; tRawBufferMarkIndex < decodedIRData . rawlen ; tRawBufferMarkIndex + = 2 ) {
2024-04-26 03:16:40 +08:00
# endif // defined(ENABLE_BEO_WITHOUT_FRAME_GAP)
2022-10-02 16:00:58 +08:00
2022-10-03 02:45:57 +08:00
uint16_t markLength = decodedIRData . rawDataPtr - > rawbuf [ tRawBufferMarkIndex ] ;
uint16_t spaceLength = decodedIRData . rawDataPtr - > rawbuf [ tRawBufferMarkIndex + 1 ] ;
BEO_TRACE_PRINT ( tPulseNumber ) ;
BEO_TRACE_PRINT ( ' ' ) ;
BEO_TRACE_PRINT ( markLength * MICROS_PER_TICK ) ;
BEO_TRACE_PRINT ( ' ' ) ;
BEO_TRACE_PRINT ( spaceLength * MICROS_PER_TICK ) ;
BEO_TRACE_PRINT ( F ( " ( " ) ) ;
BEO_TRACE_PRINT ( ( markLength + spaceLength ) * MICROS_PER_TICK ) ;
BEO_TRACE_PRINTLN ( F ( " ) " ) ) ;
# if !defined(ENABLE_BEO_WITHOUT_FRAME_GAP)
/*
* Handle the first 4 start bits
* Check if the 3. bit is the long start bit . If we see the long start bit earlier , synchronize bit counter .
*/
if ( tPulseNumber < 4 ) {
if ( tPulseNumber < 2 ) {
// bit 0 and 1
if ( matchSpace ( spaceLength , BEO_PULSE_LENGTH_START_BIT - BEO_IR_MARK ) ) {
BEO_TRACE_PRINTLN ( F ( " : detected long start bit -> synchronize state now " ) ) ;
tPulseNumber = 2 ;
2022-10-02 16:00:58 +08:00
}
} else {
2022-10-03 02:45:57 +08:00
if ( tPulseNumber = = 3 ) {
if ( matchMark ( markLength , BEO_IR_MARK ) ) {
2024-04-26 03:16:40 +08:00
# if defined(SUPPORT_BEO_DATALINK_TIMING_FOR_DECODE)
2022-10-03 02:45:57 +08:00
protocolMarkLength = BEO_IR_MARK ;
} else if ( matchMark ( markLength , BEO_DATALINK_MARK ) ) {
protocolMarkLength = BEO_DATALINK_MARK ;
2024-04-26 03:16:40 +08:00
# endif
2022-10-03 02:45:57 +08:00
} else {
BEO_DEBUG_PRINT ( : : getProtocolString ( BANG_OLUFSEN ) ) ;
BEO_DEBUG_PRINTLN ( F ( " : 4. (start) mark length is wrong " ) ) ;
return false ;
}
2022-10-02 16:00:58 +08:00
}
2022-10-03 02:45:57 +08:00
// bit 2 and 3
if ( ! matchBeoLength ( markLength + spaceLength ,
( tPulseNumber = = 2 ) ? BEO_PULSE_LENGTH_START_BIT : BEO_PULSE_LENGTH_ZERO ) ) {
BEO_DEBUG_PRINT ( : : getProtocolString ( BANG_OLUFSEN ) ) ;
BEO_DEBUG_PRINTLN ( F ( " : Start length is wrong " ) ) ;
2022-10-02 16:00:58 +08:00
return false ;
}
}
2022-10-03 02:45:57 +08:00
} else {
2024-04-26 03:16:40 +08:00
# endif // !defined(ENABLE_BEO_WITHOUT_FRAME_GAP)
2022-10-03 02:45:57 +08:00
/*
* Decode header / data
* First check for length of mark
*/
# if defined(SUPPORT_BEO_DATALINK_TIMING_FOR_DECODE)
2022-10-02 16:00:58 +08:00
if ( ! matchMark ( markLength , protocolMarkLength ) ) {
2022-10-03 02:45:57 +08:00
# else
if ( ! matchMark ( markLength , BEO_IR_MARK ) ) {
# endif
BEO_DEBUG_PRINT ( : : getProtocolString ( BANG_OLUFSEN ) ) ;
BEO_DEBUG_PRINTLN ( F ( " : Mark length is wrong " ) ) ;
2022-10-02 16:00:58 +08:00
return false ;
}
2022-10-03 02:45:57 +08:00
/*
* Check for stop after receiving at least 8 bits for data and 4 bits for header
*/
if ( tBitNumber > BEO_DATA_BITS + 4 ) {
if ( matchBeoLength ( markLength + spaceLength , BEO_PULSE_LENGTH_TRAILING_BIT ) ) {
BEO_DEBUG_PRINT ( : : getProtocolString ( BANG_OLUFSEN ) ) ;
BEO_DEBUG_PRINTLN ( F ( " : Trailing bit detected " ) ) ;
break ;
2022-10-02 16:00:58 +08:00
}
2022-10-03 02:45:57 +08:00
# if !defined(ENABLE_BEO_WITHOUT_FRAME_GAP)
2024-02-24 02:28:33 +08:00
if ( tRawBufferMarkIndex > = decodedIRData . rawlen - 3 ) { // (rawlen - 3) is index of trailing bit mark
2022-10-03 02:45:57 +08:00
BEO_DEBUG_PRINT ( : : getProtocolString ( BANG_OLUFSEN ) ) ;
BEO_DEBUG_PRINTLN ( F ( " : End of buffer, but no trailing bit detected " ) ) ;
2022-10-02 16:00:58 +08:00
return false ;
}
2022-10-03 02:45:57 +08:00
# endif
2022-10-02 16:00:58 +08:00
}
2022-10-03 02:45:57 +08:00
/*
* Decode bit
*/
if ( tLastDecodedBitValue = = 0 & & matchBeoLength ( markLength + spaceLength , BEO_PULSE_LENGTH_ONE ) ) {
tLastDecodedBitValue = 1 ;
} else if ( tLastDecodedBitValue = = 1 & & matchBeoLength ( markLength + spaceLength , BEO_PULSE_LENGTH_ZERO ) ) {
tLastDecodedBitValue = 0 ;
} else if ( ! matchBeoLength ( markLength + spaceLength , BEO_PULSE_LENGTH_EQUAL ) ) {
BEO_DEBUG_PRINT ( : : getProtocolString ( BANG_OLUFSEN ) ) ;
BEO_DEBUG_PRINT ( F ( " : Index= " ) ) ;
BEO_DEBUG_PRINT ( tRawBufferMarkIndex ) ;
BEO_DEBUG_PRINT ( F ( " Length " ) ) ;
BEO_DEBUG_PRINT ( ( markLength + spaceLength ) * MICROS_PER_TICK ) ;
BEO_DEBUG_PRINTLN ( F ( " is wrong " ) ) ;
2022-10-02 16:00:58 +08:00
return false ;
}
2022-10-03 02:45:57 +08:00
tDecodedRawData < < = 1 ;
tDecodedRawData | = tLastDecodedBitValue ;
+ + tBitNumber ;
BEO_TRACE_PRINT ( F ( " Bits " ) ) ;
BEO_TRACE_PRINT ( tBitNumber ) ;
BEO_TRACE_PRINT ( F ( " " ) ) ;
BEO_TRACE_PRINT ( uint32_t ( tDecodedRawData > > BEO_DATA_BITS ) , HEX ) ;
BEO_TRACE_PRINT ( F ( " " ) ) ;
BEO_TRACE_PRINTLN ( uint8_t ( tDecodedRawData & ( ( 1 < < BEO_DATA_BITS ) - 1 ) ) , HEX ) ;
// End of bit decode
# if !defined(ENABLE_BEO_WITHOUT_FRAME_GAP)
2022-10-02 16:00:58 +08:00
}
2022-10-03 02:45:57 +08:00
# else
/*
* Check for last bit after decoding it
*/
2024-02-24 02:28:33 +08:00
if ( tRawBufferMarkIndex > = decodedIRData . rawlen - 3 ) { // (rawlen - 3) is index of last bit mark
2022-10-03 02:45:57 +08:00
BEO_TRACE_PRINT ( : : getProtocolString ( BANG_OLUFSEN ) ) ;
BEO_TRACE_PRINTLN ( F ( " : Last bit reached " ) ) ;
break ;
}
# endif
2022-10-02 16:00:58 +08:00
2022-10-03 02:45:57 +08:00
+ + tPulseNumber ;
}
# if defined(ENABLE_BEO_WITHOUT_FRAME_GAP)
2022-10-02 16:00:58 +08:00
}
2022-10-03 02:45:57 +08:00
# endif
2022-10-02 16:00:58 +08:00
decodedIRData . protocol = BANG_OLUFSEN ;
2022-10-03 02:45:57 +08:00
decodedIRData . address = tDecodedRawData > > BEO_DATA_BITS ; // lower header tBitNumber
decodedIRData . command = tDecodedRawData & ( ( 1 < < BEO_DATA_BITS ) - 1 ) ; // lower 8 tBitNumber
decodedIRData . extra = tDecodedRawData > > ( BEO_DATA_BITS + 16 ) ; // upper header tBitNumber
decodedIRData . numberOfBits = tBitNumber ;
2022-10-02 16:00:58 +08:00
decodedIRData . flags = IRDATA_FLAGS_IS_MSB_FIRST ;
2022-10-03 02:45:57 +08:00
decodedIRData . decodedRawData = tDecodedRawData ;
2022-10-02 16:00:58 +08:00
return true ;
}
# endif // _IR_BANG_OLUFSEN_HPP