Skip to content

Add bosewaveradio support #690

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion IRremote.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
#define DECODE_LEGO_PF 0 // NOT WRITTEN
#define SEND_LEGO_PF 1

#define DECODE_BOSEWAVE 1
#define SEND_BOSEWAVE 1

//------------------------------------------------------------------------------
// When sending a Pronto code we request to send either the "once" code
// or the "repeat" code
Expand Down Expand Up @@ -119,6 +122,7 @@ typedef
DENON,
PRONTO,
LEGO_PF,
BOSEWAVE,
}
decode_type_t;

Expand Down Expand Up @@ -251,6 +255,10 @@ class IRrecv
# if DECODE_LEGO_PF
bool decodeLegoPowerFunctions (decode_results *results) ;
# endif
//......................................................................
# if DECODE_BOSEWAVE
bool decodeBoseWave (decode_results *results) ;
# endif
} ;

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -335,9 +343,13 @@ class IRsend
# if SEND_PRONTO
void sendPronto (char* code, bool repeat, bool fallback) ;
# endif
//......................................................................
//......................................................................
# if SEND_LEGO_PF
void sendLegoPowerFunctions (uint16_t data, bool repeat = true) ;
# endif
//......................................................................
# if SEND_BOSEWAVE
void sendBoseWave (unsigned char code) ;
# endif
} ;

Expand Down
109 changes: 109 additions & 0 deletions examples/BoseWaveSendDemo/BoseWaveSendDemo.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include <boarddefs.h>
#include <IRremote.h>
#include <IRremoteInt.h>

/*
* Based on IRremote: IRsendDemo by Ken Shirriff
*
* Prompt user for a code to send. Make sure your 940-950nm IR LED is
* connected to the default digital output. Place your Bose Wave Radio
* CD in the line of sight of your LED, and send commands!
*/
void menu() {
Serial.println("0: On / Off");
Serial.println("1: Volume Up");
Serial.println("2: Volume Down");
Serial.println("3: Tune Up");
Serial.println("4: Tune Down");
Serial.println("5: AM");
Serial.println("6: FM");
Serial.println("7: Preset 1");
Serial.println("8: Preset 2");
Serial.println("9: Preset 3");
Serial.println("a: Preset 4");
Serial.println("b: Preset 5");
Serial.println("c: Preset 6");
Serial.println("d: Mute");
Serial.println("e: Play/Pause");
Serial.println("f: Stop");
Serial.println("g: Aux");
Serial.println("h: Sleep");
}

IRsend irsend;
bool prompt;

void setup()
{
Serial.begin(9600);
prompt = true;
}

void loop() {
if (prompt) {
menu();
}
prompt = false;

if (Serial.available()) {
int answer = Serial.read();
if (answer == -1) {
delay(300);
} else if (answer == 48) { // 0
irsend.sendBoseWave(0xFF); // On/Off
prompt = true;
} else if (answer == 49) { // 1
irsend.sendBoseWave(0xFD); // Volume Up
prompt = true;
} else if (answer == 50) { // 2
irsend.sendBoseWave(0xFC); // Volume Down
prompt = true;
} else if (answer == 51) { // 3
irsend.sendBoseWave(0xF4); // Tune Up
prompt = true;
} else if (answer == 52) { // 4
irsend.sendBoseWave(0xF3); // Tune Down
prompt = true;
} else if (answer == 53) { // 5
irsend.sendBoseWave(0xF7); // AM
prompt = true;
} else if (answer == 54) { // 6
irsend.sendBoseWave(0xF9); // FM
prompt = true;
} else if (answer == 55) { // 7
irsend.sendBoseWave(0xF2); // Preset 1
prompt = true;
} else if (answer == 56) { // 8
irsend.sendBoseWave(0xF1); // Preset 2
prompt = true;
} else if (answer == 57) { // 9
irsend.sendBoseWave(0xF0); // Preset 3
prompt = true;
} else if (answer == 97) { // a
irsend.sendBoseWave(0xEF); // Preset 4
prompt = true;
} else if (answer == 98) { // b
irsend.sendBoseWave(0xEE); // Preset 5
prompt = true;
} else if (answer == 99) { // c
irsend.sendBoseWave(0xFB); // Preset 6
prompt = true;
} else if (answer == 100) { // d
irsend.sendBoseWave(0xFE); // Mute
prompt = true;
} else if (answer == 101) { // e
irsend.sendBoseWave(0xF6); // Pause
prompt = true;
} else if (answer == 102) { // f
irsend.sendBoseWave(0xF5); // Stop
prompt = true;
} else if (answer == 103) { // g
irsend.sendBoseWave(0xF8); // Aux
prompt = true;
} else if (answer == 104) { // h
irsend.sendBoseWave(0xFA); // Sleep
prompt = true;
}
delay(300);
}
}
3 changes: 3 additions & 0 deletions examples/IRrecvDump/IRrecvDump.ino
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ void dump(decode_results *results) {
else if (results->decode_type == WHYNTER) {
Serial.print("Decoded Whynter: ");
}
else if (results.decode_type == BOSEWAVE) {
Serial.print("Decoded Bose Wave Radio / CD: ");
}
Serial.print(results->value, HEX);
Serial.print(" (");
Serial.print(results->bits, DEC);
Expand Down
1 change: 1 addition & 0 deletions examples/IRrecvDumpV2/IRrecvDumpV2.ino
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ void encoding (decode_results *results)
case AIWA_RC_T501: Serial.print("AIWA_RC_T501"); break ;
case PANASONIC: Serial.print("PANASONIC"); break ;
case DENON: Serial.print("Denon"); break ;
case BOSEWAVE: Serial.print("BOSEWAVE"); break ;
}
}

Expand Down
1 change: 1 addition & 0 deletions examples/IRremoteInfo/IRremoteInfo.ino
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ void dumpProtocols() {
Serial.print(F("DISH: ")); printSendEnabled(SEND_DISH); printDecodeEnabled(DECODE_DISH);
Serial.print(F("SHARP: ")); printSendEnabled(SEND_SHARP); printDecodeEnabled(DECODE_SHARP);
Serial.print(F("DENON: ")); printSendEnabled(SEND_DENON); printDecodeEnabled(DECODE_DENON);
Serial.print(F("BOSEWAVE: ")); printSendEnabled(SEND_BOSEWAVE); printDecodeEnabled(DECODE_BOSEWAVE);
Serial.print(F("PRONTO: ")); printSendEnabled(SEND_PRONTO); Serial.println(F("(Not Applicable)"));
}

Expand Down
219 changes: 219 additions & 0 deletions ir_BoseWave.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
#include "IRremote.h"
#include "IRremoteInt.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_HDR_MARK 1061
#define BOSEWAVE_HDR_SPACE 1456
#define BOSEWAVE_BIT_MARK 534
#define BOSEWAVE_ONE_SPACE 468
#define BOSEWAVE_ZERO_SPACE 1447
#define BOSEWAVE_END_MARK 614
#define BOSEWAVE_RPT_SPACE 51200

//+=============================================================================
#if SEND_BOSEWAVE
void IRsend::sendBoseWave (unsigned char code)
{
unsigned int rawSignal[35];
int index = 0;
// Header
rawSignal[index++] = BOSEWAVE_HDR_MARK;
rawSignal[index++] = BOSEWAVE_HDR_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 (decode_results *results)
{
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_HDR_MARK)) {
DBG_PRINT("\tInvalid Header Mark. Expecting ");
DBG_PRINT(BOSEWAVE_HDR_MARK);
DBG_PRINT(". Got ");
DBG_PRINTLN(results->rawbuf[index] * USECPERTICK);
return false ;
}
index++;

// Check header "space"
if (!MATCH_SPACE(results->rawbuf[index], BOSEWAVE_HDR_SPACE)) {
DBG_PRINT("\tInvalid Header Space. Expecting ");
DBG_PRINT(BOSEWAVE_HDR_SPACE);
DBG_PRINT(". Got ");
DBG_PRINTLN(results->rawbuf[index] * USECPERTICK);
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] * USECPERTICK);
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] * USECPERTICK);
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] * USECPERTICK);
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] * USECPERTICK);
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] * USECPERTICK);
return false ;
}

// Success
results->bits = BOSEWAVE_BITS;
results->value = command;
results->decode_type = BOSEWAVE;

return true;
}
#endif