223 lines
7.6 KiB
C++
223 lines
7.6 KiB
C++
|
|
#include "IRremote.h"
|
||
|
|
|
||
|
|
//==============================================================================
|
||
|
|
// BBBB OOO SSSS EEEEE
|
||
|
|
// B B O O S E
|
||
|
|
// BB B O O SSS EEEE
|
||
|
|
// B B O O S E
|
||
|
|
// BBBB OOO SSSS EEEEE
|
||
|
|
//==============================================================================
|
||
|
|
//
|
||
|
|
// Bose Wave Radio CD Remote Control
|
||
|
|
// |-------------------------------------|
|
||
|
|
// | On/Off Sleep VolUp |
|
||
|
|
// | Play/Pause Stop VolDown |
|
||
|
|
// | FM AM Aux |
|
||
|
|
// | Tune Down Tune Up Mute |
|
||
|
|
// | 1 2 3 |
|
||
|
|
// | 4 5 6 |
|
||
|
|
// |-------------------------------------|
|
||
|
|
//
|
||
|
|
// Support for Bose Wave Radio CD provided by https://github.com/uvotguy.
|
||
|
|
//
|
||
|
|
// This protocol was reverse engineered by capturing IR signals from a working
|
||
|
|
// remote. Multiple signals were captured on my oscilloscope, and the timing
|
||
|
|
// values were averaged.
|
||
|
|
//
|
||
|
|
// IR codes are 8 bits. Transmission starts with a header: a mark and a space.
|
||
|
|
// The header is followed by an 8-bit command, where a bit is a mark and a short
|
||
|
|
// space (1) or a long space (0). The command is followed by the complement of
|
||
|
|
// the command (8 bits). A transmission ends with a short mark.
|
||
|
|
//
|
||
|
|
// As seen on my trusty oscilloscope, there is no repeat code. Instead, when I
|
||
|
|
// press and hold a button on my remote, it sends a command, makes a 51.2ms space,
|
||
|
|
// and resends the command, etc, etc.
|
||
|
|
//
|
||
|
|
// It may be worth noting that these values do NOT match those in the LIRC
|
||
|
|
// remote database (http://lirc.sourceforge.net/remotes/bose/).
|
||
|
|
|
||
|
|
#define CMD_ON_OFF 0xff
|
||
|
|
#define CMD_MUTE 0xfe
|
||
|
|
#define CMD_VOL_UP 0xfd
|
||
|
|
#define CMD_VOL_DOWN 0xfc
|
||
|
|
#define CMD_PRESET_6 0xfb
|
||
|
|
#define CMD_SLEEP 0xfa
|
||
|
|
#define CMD_FM 0xf9
|
||
|
|
#define CMD_AUX 0xf8
|
||
|
|
#define CMD_AM 0xf7
|
||
|
|
#define CMD_PLAY_PAUSE 0xf6
|
||
|
|
#define CMD_STOP 0xf5
|
||
|
|
#define CMD_TUNE_UP 0xf4
|
||
|
|
#define CMD_TUNE_DOWN 0xf3
|
||
|
|
#define CMD_PRESET_1 0xf2
|
||
|
|
#define CMD_PRESET_2 0xf1
|
||
|
|
#define CMD_PRESET_3 0xf0
|
||
|
|
#define CMD_PRESET_4 0xef
|
||
|
|
#define CMD_PRESET_5 0xee
|
||
|
|
|
||
|
|
#define BOSEWAVE_BITS 8
|
||
|
|
#define BOSEWAVE_HEADER_MARK 1061
|
||
|
|
#define BOSEWAVE_HEADER_SPACE 1456
|
||
|
|
#define BOSEWAVE_BIT_MARK 534
|
||
|
|
#define BOSEWAVE_ONE_SPACE 468
|
||
|
|
#define BOSEWAVE_ZERO_SPACE 1447
|
||
|
|
#define BOSEWAVE_END_MARK 614
|
||
|
|
#define BOSEWAVE_REPEAT_SPACE 51200
|
||
|
|
|
||
|
|
//+=============================================================================
|
||
|
|
#if SEND_BOSEWAVE
|
||
|
|
unsigned int rawSignal[35];
|
||
|
|
void IRsend::sendBoseWave(unsigned char code) {
|
||
|
|
|
||
|
|
int index = 0;
|
||
|
|
// Header
|
||
|
|
rawSignal[index++] = BOSEWAVE_HEADER_MARK;
|
||
|
|
rawSignal[index++] = BOSEWAVE_HEADER_SPACE;
|
||
|
|
|
||
|
|
// 8 bit command
|
||
|
|
for (unsigned char mask = 0x80; mask; mask >>= 1) {
|
||
|
|
rawSignal[index++] = BOSEWAVE_BIT_MARK;
|
||
|
|
if (code & mask) {
|
||
|
|
rawSignal[index++] = BOSEWAVE_ONE_SPACE;
|
||
|
|
} else {
|
||
|
|
rawSignal[index++] = BOSEWAVE_ZERO_SPACE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 8 bit command complement
|
||
|
|
for (unsigned char mask = 0x80; mask; mask >>= 1) {
|
||
|
|
rawSignal[index++] = BOSEWAVE_BIT_MARK;
|
||
|
|
if (code & mask) {
|
||
|
|
rawSignal[index++] = BOSEWAVE_ZERO_SPACE;
|
||
|
|
} else {
|
||
|
|
rawSignal[index++] = BOSEWAVE_ONE_SPACE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// End transmission
|
||
|
|
rawSignal[index++] = BOSEWAVE_END_MARK;
|
||
|
|
|
||
|
|
// Transmit
|
||
|
|
this->sendRaw(rawSignal, 35, 38);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
//+=============================================================================
|
||
|
|
#if DECODE_BOSEWAVE
|
||
|
|
bool IRrecv::decodeBoseWave() {
|
||
|
|
unsigned char command = 0; // Decoded command
|
||
|
|
unsigned char complement = 0; // Decoded command complement
|
||
|
|
|
||
|
|
int index = 0; // Index in to results array
|
||
|
|
|
||
|
|
DBG_PRINTLN("Decoding Bose Wave ...");
|
||
|
|
|
||
|
|
// Check we have enough data
|
||
|
|
if (irparams.rawlen < (2 * BOSEWAVE_BITS * 2) + 3) {
|
||
|
|
DBG_PRINT("\tInvalid data length found: ");
|
||
|
|
DBG_PRINTLN(results.rawlen);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check header "mark"
|
||
|
|
index = 1;
|
||
|
|
if (!MATCH_MARK(results.rawbuf[index], BOSEWAVE_HEADER_MARK)) {
|
||
|
|
DBG_PRINT("\tInvalid Header Mark. Expecting ");
|
||
|
|
DBG_PRINT(BOSEWAVE_HEADER_MARK);
|
||
|
|
DBG_PRINT(". Got ");
|
||
|
|
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
index++;
|
||
|
|
|
||
|
|
// Check header "space"
|
||
|
|
if (!MATCH_SPACE(results.rawbuf[index], BOSEWAVE_HEADER_SPACE)) {
|
||
|
|
DBG_PRINT("\tInvalid Header Space. Expecting ");
|
||
|
|
DBG_PRINT(BOSEWAVE_HEADER_SPACE);
|
||
|
|
DBG_PRINT(". Got ");
|
||
|
|
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
index++;
|
||
|
|
|
||
|
|
// Decode the data bits
|
||
|
|
for (int ii = 7; ii >= 0; ii--) {
|
||
|
|
// Check bit "mark". Mark is always the same length.
|
||
|
|
if (!MATCH_MARK(results.rawbuf[index], BOSEWAVE_BIT_MARK)) {
|
||
|
|
DBG_PRINT("\tInvalid command Mark. Expecting ");
|
||
|
|
DBG_PRINT(BOSEWAVE_BIT_MARK);
|
||
|
|
DBG_PRINT(". Got ");
|
||
|
|
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
index++;
|
||
|
|
|
||
|
|
// Check bit "space"
|
||
|
|
if (MATCH_SPACE(results.rawbuf[index], BOSEWAVE_ONE_SPACE)) {
|
||
|
|
command |= (0x01 << ii);
|
||
|
|
} else if (MATCH_SPACE(results.rawbuf[index], BOSEWAVE_ZERO_SPACE)) {
|
||
|
|
// Nothing to do for zeroes.
|
||
|
|
} else {
|
||
|
|
DBG_PRINT("\tInvalid command Space. Got ");
|
||
|
|
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
index++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Decode the command complement bits. We decode it here as the complement
|
||
|
|
// of the complement (0=1 and 1=0) so we can easily compare it to the command.
|
||
|
|
for (int ii = 7; ii >= 0; ii--) {
|
||
|
|
// Check bit "mark". Mark is always the same length.
|
||
|
|
if (!MATCH_MARK(results.rawbuf[index], BOSEWAVE_BIT_MARK)) {
|
||
|
|
DBG_PRINT("\tInvalid complement Mark. Expecting ");
|
||
|
|
DBG_PRINT(BOSEWAVE_BIT_MARK);
|
||
|
|
DBG_PRINT(". Got ");
|
||
|
|
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
index++;
|
||
|
|
|
||
|
|
// Check bit "space"
|
||
|
|
if (MATCH_SPACE(results.rawbuf[index], BOSEWAVE_ONE_SPACE)) {
|
||
|
|
// Nothing to do.
|
||
|
|
} else if (MATCH_SPACE(results.rawbuf[index], BOSEWAVE_ZERO_SPACE)) {
|
||
|
|
complement |= (0x01 << ii);
|
||
|
|
} else {
|
||
|
|
DBG_PRINT("\tInvalid complement Space. Got ");
|
||
|
|
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
index++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (command != complement) {
|
||
|
|
DBG_PRINT("\tComplement is not correct. Command=0x");
|
||
|
|
DBG_PRINT(command, HEX);
|
||
|
|
DBG_PRINT(" Complement=0x");
|
||
|
|
DBG_PRINTLN(complement, HEX);
|
||
|
|
return false;
|
||
|
|
} else {
|
||
|
|
DBG_PRINTLN("\tValid command");
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check end "mark"
|
||
|
|
if (MATCH_MARK(results.rawbuf[index], BOSEWAVE_END_MARK) == 0) {
|
||
|
|
DBG_PRINT("\tInvalid end Mark. Got ");
|
||
|
|
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Success
|
||
|
|
results.bits = BOSEWAVE_BITS;
|
||
|
|
results.value = command;
|
||
|
|
results.decode_type = BOSEWAVE;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
bool IRrecv::decodeBoseWave(decode_results *aResults) {
|
||
|
|
bool aReturnValue = decodeBoseWave();
|
||
|
|
*aResults = results;
|
||
|
|
return aReturnValue;
|
||
|
|
}
|
||
|
|
#endif
|