probonopd / Lifestyle

Controlling 27.145 MHz BOSE Lifestyle with ESP8266 and Raspberry Pi
18 stars 6 forks source link

Document SER-DATA-IN protocol #2

Open probonopd opened 6 years ago

probonopd commented 6 years ago

Let's document the SER-DATA-IN protocol of the Acoustimass module so that we can use the Acoustimass module without the original Music Center.

Update 2023: See below for documentation provided by Bose.

garci66 commented 5 years ago

I am have a slightly different accoustimass system (lifestyle 12) and my control center is half dead. My subwoofer has a slightly different connector (its a regular DIN instead of mini-DIN) and does not accept SPDIF but I would expect the serial protocol to be the same.

So far, the protocol is not evident.. but seems simple enought to be "clonable" from a working system.

The serial line is always pulled up. I am seeing what seems to be the encoded commands using a similar method to the NEC codes from the remote (as in short and long pulses) but the pulses seem to be 1msec or 2msec in duration. There is a 8 msec "start" bit of sorts and also a 2-msec "stop" bit. The comands seem to be 13 bit in length which is quite weird. Might be 12-bit + parity but I havent't checked yet.

I think its totally possible to control the accoustimass system without the console. I'll have to keep trying.

probonopd commented 5 years ago

Excellent. Let me know if I can help by looking at something, although I do not have access to the system right now (might take a couple of weeks).

garci66 commented 5 years ago

Im still trying to figure out the encoding to be honest. But I think we can just dump the commands in a format similar to the "raw" format similar to irdb. Should be easy enough to reproduce. Basically the line has a 5V pull-up and there a transistor should pull it down. I have a model 5-V music center and an accoustimass 12 subwoofer/amp.

I will see if I can hack something up.

On Thu, Jul 11, 2019 at 2:59 AM probonopd notifications@github.com wrote:

Excellent. Let me know if I can help by looking at something, although I do not have access to the system right now (might take a couple of weeks).

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/probonopd/Lifestyle/issues/2?email_source=notifications&email_token=ACQV3WF6Q5KZTSP3F4XMVNLP63D2NA5CNFSM4ETMAE22YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODZVTA7A#issuecomment-510341244, or mute the thread https://github.com/notifications/unsubscribe-auth/ACQV3WEP45LQQEGRK32Q2BDP63D2NANCNFSM4ETMAE2Q .

garci66 commented 5 years ago

Here are some images of the traces I captured last night. The narrow pulses are 1msec in width and the wide ones are 2msec. The long pulse down at the start (some sort of "start bit") is 8msec.

From what I am seeing, it seems that the encoding is something similar to the IR encoding with short-short or long-short pulses. And then the "stop" bit seems to be the only "long" low bit (as well as the start).

IMG_20190710_223450 IMG_20190710_235625 IMG_20190710_235636 IMG_20190710_235716

probonopd commented 5 years ago

Interesting! Hope you can figure something out by comparing some codes.

Maybe @bengtmartensson recognizes this type of code from just looking at it?

bengtmartensson commented 5 years ago

Looks like biphase encoding to me. IrpTransmogrifier is a good tool for analyzing this.

garci66 commented 5 years ago

I though it was bi-phase but if you look carefully, there are no "long" zeros (other than the start and stop bits). So far, it seems to be more a case of "pulse width modulation" where the low portion is always 1msec (except for start/stop bits) and the high part is either 1msec or 2 msec. I arbitrarily chose "1" to be 2msec pulses and 0 for 1 msec pulses.

Using this mechanism, I was able to decode all the codes from the remote. Code length is still weird (as in 13 bits or 20 bits in total).. but I guess BOSE was not expecting to be compatible or interoperable with anyone else.

I have attached captures in "IRDB RAW" format (as in indicating the length in micro-seconds for each pulse, whether low or high for all the keys. I have not attempted to make any sense out of each yet, but im pretty confident that just reproducing the same codes will trigger the accoustimass amp to switch inputs, change volume. mute, etc..

We should also note that there are 50 msecs between two codes (plenty of keys send two codes).

The circuit is super simple. A pull-up drives it yo 5V and we pull down the line with an arduino directly or through a transisitor.

bose remote codes.xlsx bose remote codes.txt

If we just want to control the sub, we can just trigger those codes and I guess the accoustimass will react in the same way as if the control center would be connected.

garci66 commented 5 years ago

For example, using the encoding I described above, and SSSS being the 8-msec long Start bit and TTTT the 2msec stop bit, these are the keys for volume and surround vol:

VOL+  SSSS|1001100010001|TTTT
VOL-  SSSS|1001100010010|TTTT
SVOL+ SSSS|1001100011001|TTTT
SVOL- SSSS|1001100011010|TTTT
MUTE  SSSS|1001100010101|TTTT

And for the function switch (surround mode)

SURR: SSSS|100110001110100000100|TTTT
S+CE: SSSS|100110001110100000011|TTTT
STER: SSSS|100110001110100000010|TTTT

Finally, some of the Function keys:

VIDEO: SSSS|1011000011010|TTTT
VIDEO: SSSS|1001100010011|TTTT

FM:    SSSS|1010101001010|TTTT
FM:    SSSS|1001100010011|TTTT
AM:    SSSS|1010100111010|TTTT
AM:    SSSS|1001100010011|TTTT

All the keys are logged in the excel and CSV file

It seems as if the second key press of the function key is the same for all functions. Which could be an attempt to turn on the subwoofer just in case.

probonopd commented 5 years ago

Wow, awesome work @garci66. I am trying to convert those codes into something IrScrutinizer understands, so that it can easily be converted from there into various formats.

Looking at VIDEO as an example, I wonder whether

--START|, -8028, +2000, -1008, +996, -1012, +1996, -1012, +1996, -1012, +992, -1012, +996, -1008, +996, -1012, +992, -1012, +2000, -1008, +2000, -1008, +996, -1012, +1996, -1012, +992, -2016,|END--

can be written as

+8000, -8028, +2000, -1008, +996, -1012, +1996, -1012, +1996, -1012, +992, -1012, +996, -1008, +996, -1012, +992, -1012, +2000, -1008, +2000, -1008, +996, -1012, +1996, -1012, +992, -2016

or even be cleaned up a bit to read

+8000, -8000, +2000, -1000, +1000, -1000, +2000, -1000, +2000, -1000, +1000, -1000, +1000, -1000, +1000, -1000, +1000, -1000, +2000, -1000, +2000, -1000, +1000, -1000, +2000, -1000, +1000, -2000

Which would translate, according to IrScrutinizer, to Pronto Hex

0000 006D 000E 0000 0130 0130 004C 0026 0026 0026 004C 0026 004C 0026 0026 0026 0026 0026 0026 0026 0026 0026 004C 0026 004C 0026 0026 0026 004C 0026 0026 004C

Does this look right?

probonopd commented 5 years ago

I am a bit confused as to why something else than the would get sent to the Acoustimass module regarding the input source such as VIDEO, AM, FM, CD, TAPE or actions like REWIND. Isn't that something that is entirely handled in the Music Center?

Or are you talking about controlling the Music Center, not the Acoustimass module?

Both are interesting, but my end goal is to be able to se the Acoustimass module without the Control Center.

bengtmartensson commented 5 years ago

Just to show you what you can do with IrpTransmogrifier:

First a slightly edited version of bose remote codes.txt above: bose.remote.codes-edited4transmogrifier.txt

Transmogrifying:

$ irptransmogrifier analyze  --trailingg 2000 --bit-usage  --parametertable --named  bose.remote.codes-edited4transmogrifier.txt    
VIDEO              {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x61a}
VIDEO-alt          {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x313}
FM                 {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x54a}
FM-alt             {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x313}
AM                 {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x53a}
AM-alt             {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x313}
CD                 {1005,msb}<-1,1|1,-1>(1,A:3,-2){A=0x4}
CD-alt             {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x55a}
CD-alter           {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x313}
CD (already in CD) {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x313}
TAPE               {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x42a}
TAPE-alt           {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x313}
STOP               {1005,msb}<-1,1|1,-1>(8,-2,A:3,-2){A=0x6}
Play / pause       {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x611}
SKIP back          {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x613}
SKIP FWD           {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x612}
SEEK back press    {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x615}
SEEK back release  {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x61a}
Seek fwd press     {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x614}
seek fwd release   {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x61a}
SURR vol +         {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x319}
SURR vol -         {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x31a}
VOL +              {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x311}
VOL -              {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x312}
SURROUND           {1005,msb}<1,-1|1,-2>(8,-2,A:20,2,-2){A=0x31d04}
STEREO+CENTER      {1005,msb}<1,-1|1,-2>(8,-2,A:20,2,-2){A=0x31d03}
STEREO             {1005,msb}<1,-1|1,-2>(8,-2,A:20,2,-2){A=0x31d02}
MUTE               {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x315}
OFF                {1005,msb}<1,-1|1,-2>(8,-2,A:12,2,-2){A=0x315}

Bit usage analysis:
A       **000*****0*******
Duplicates analysis:
A       (a:1)(a:1)000(a:1)(a:1)***0*******      1,1,3,1,1,1,1,1

Parameter table:
VIDEO                   61a
VIDEO-alt               313
FM                      54a
FM-alt                  313
AM                      53a
AM-alt                  313
CD                      4
CD-alt                  55a
CD-alter                313
CD (already in CD)      313
TAPE                    42a
TAPE-alt                313
STOP                    6
Play / pause            611
SKIP back               613
SKIP FWD                612
SEEK back press         615
SEEK back release       61a
Seek fwd press          614
seek fwd release        61a
SURR vol +              319
SURR vol -              31a
VOL +                   311
VOL -                   312
SURROUND                31d04
STEREO+CENTER           31d03
STEREO                  31d02
MUTE                    315
OFF                     315
probonopd commented 5 years ago

This is truly amazing @bengtmartensson

garci66 commented 5 years ago

I don't think you need your first "+8000" part on the signals.. basically the line is always idle at +5v (it's pulled up by both the accoustimass and the console it seems. (or on the accoustimass side when it's powered up). Other than that, the graph you show seems perfect.

If we are using an aruduino and its internall pullups then we need to leave the line "idle" at "1" or "high-z". And then we start by writing a 0 for 8msec (the start bit), then we write a the whole pattern and finally we write a 0 for 2msec (the stop bit).

If we're using an external transistor and external pullup we might need to invert the output first but not sure. The system seems to have a 10K pull-up according to the service manual.

Also, regarding why other keys (than volume, mute, surround) get passed along.. the service manual says the following:

When an external source is selected (AUX, VIDEO, or TAPE), the transport commands (FF, FR, etc.) are passed through the serial data jack via Q401 and its associated circuitry.

I guess this means that you could have a BOSE (or bose compatible) tape deck and receive commands via the serial Bus (and why the control center has two serial ports in parallel so that you can connect other devices).

Finally, just wanted to mention that I used the remote and the music center configured with the "house code" of 0000 and also the speaker config for 00 (I believe its speakers A). didn't test what happens when using other settings.

I will try a very simple arduino sketch to send basic commands to the sub and see if it "reacts accordingly". Not sure how many "orphan" accoustimass amps are lying around without a console, but it would be good that we're able to "revive" them... ;-)

garci66 commented 5 years ago

But just to clarify, all those commands were captured between the Accoustimass sub and the music center and my objective is the same as yours, being able to control an accoustimass amp without the music center. (in fact, all of this data came while I was fixing a music center for a friend but I started looking at getting rid of it just in case the music center was mostly dead). My idea was to replace the music center for a raspberry pi and basically make it act as a spotify receiver and trigger the volume commands / surround / etc from the raspberry as well.

garci66 commented 5 years ago

And one more thing.. it seems I need to capture the "OFF" key again!.. damn... if you look at the timestamp, I copy-pasted the same dump as mute and not the OFF pattern... and I think OFF is quite useful!

And it seems that the code identified by IRtransmogrifier as "313" would be something like "power on" or something of sorts.. as it seems to be sent as the second command for every command. Maybe it wasn't identifying the sub as powered on?

probonopd commented 5 years ago

The Arduino sketch also would need to take care of switching on the amp, I guess.

Maybe @bengtmartensson can show us how to use https://github.com/bengtmartensson/AGirs to send the required signals using an Arudino?

garci66 commented 5 years ago

From everything I saw the amp switches on with any of the source commands or the command shown as 131 on the decode. I still need to test it.

I need to capture the off command as well.

Of using a 5v Arduino then we can drive the pin directly.

On Sat, Jul 13, 2019, 19:43 probonopd notifications@github.com wrote:

The Arduino sketch also would need to take care of switching on the amp, I guess.

Maybe @bengtmartensson https://github.com/bengtmartensson can show us how to use https://github.com/bengtmartensson/AGirs to send the required signals using an Arudino?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/probonopd/Lifestyle/issues/2?email_source=notifications&email_token=ACQV3WHHLJGV5LZJ6UOY6OLP7JK7RA5CNFSM4ETMAE22YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODZ32U2I#issuecomment-511158889, or mute the thread https://github.com/notifications/unsubscribe-auth/ACQV3WDTYDSTCFI3EQXUT7TP7JK7RANCNFSM4ETMAE2Q .

bengtmartensson commented 5 years ago

Maybe @bengtmartensson can show us how to use https://github.com/bengtmartensson/AGirs to send the required signals using an Arudino?

AGirs is more thought of as an interactive server, reads from a Stream (typically Serial or Tcp); sure, it can be done, but seems a bit unnatural. However, using Infrared4Auduino (which sits "under" AGirs) can be a good idea.

So I used an experimental version of IrpTransmogrifier (see this), command line

tools/irptransmogrifier analyze  --trailingg 2000  --parametertable --named  bose.remote.codes-edited4transmogrifier.txt --decoder pwm2 --girr  > probono.girr

which produced the result: probono.girr.zip

Automatic generation of code for arbitrary IRP protocols is unfortunately not implemented yet. But we can use the raw code generator of IrScrutinizer to generate code for Infrared4Arduino/IRremote/IrLib: arduino_raw_2019-07-15_17-40-12.ino.zip

probonopd commented 5 years ago

Thank you @bengtmartensson, that should get us started.

garci66 commented 5 years ago

The following is the capture for power off (which was missing from the capture)

17:42:27.368 -> --START|SSSS|, +2000, -1008, +996, -1008, +996, -1012, +1996, -1012, +1996, -1012, +1996, -1012, +1996, -1012, +1996, -1012, +1996, -1012, +996, -1008, +2000, -1008, +2000, -1012, +992|TTTT|END

17:37:59.987 -> , +75908472SSSS|1001111110110|TTTT|END

probonopd commented 5 years ago

Thank you. Have you been successful in sending those commands from Arduino?

garci66 commented 5 years ago

did a try last night but did not succeed. (I only have the subwoofer so its hard to test the audio). The sub has no leds or anyhting so its really hard to know if it received any command.

dexinnet commented 4 years ago

Hey there, would like to join the project, have been searching the net for hours now :+1:

I have a working Lifestyle 12 system (acoustimass & music center) using the 9-Pin DIN connector -> 2xRCA + 3,5mm jack (9v power on voltage, 5v data, gnd). Currently, the music center is used only to turn the acoustimass on and off. Also have a spare 5v arduino and some experience with reverse engineering / bit banging proprietary wireless protocols. But I'm not into electronics, voltages & milliamperes.

Could you tell me how to wire the arduino in between the two devices without risking to blow out any of the chips? Especially with regard to the 9v power on voltage I think it wouldn't be wise simply connecting it to a 9v psu - but how much current should one use?

Thanks in advance! :+1:

potokslow commented 3 years ago

Hi, Did anyone manage to get the acoustimass functional without the music center?

I got a PS48 III speaker recently (I think it's otherwise known as Lifestyle 28 Series III) with incomplete set of satellite speakers, but without controller / music center. I managed to get it to a point where LEDs start blinking when unit is provided 10V on the turn-on line, but that's all - nothing can be heard despite connecting the input lines to a generic sound source. I guess I need to provide control signal(s) to get it fully functional, just not sure how to go about it, or if it's actually a real option.

When searching online, I got across an old post with information seemingly describing a way to control "Lifestyle 28II, 38 or 48" via generic serial port - https://us.v-cdn.net/6031006/uploads/vbulletin_attachments/7/2/0/539.doc (found on https://proforums.harman.com/amx/discussion/193/rs232-control-of-bose-lifestyle).

I haven't tried anything further yet, prefer to check my chances first. Did any of you succeed in controlling the unit in a DIY way? Please let me know if trying to use the device without original controller is realistic.

Thank you 😊

741Z commented 1 year ago

Hi,

I can confirm that an Lifestyle® 8 Series II system can be controlled via 4800 baud TTL signals . You can easily us an Arduino to send commands or even a RS-232 port from a PC as long as you have some thing to convert the signals to TTL . I have also used the program located at this site https://terencewrose.webador.co.uk/ to control the unit with no issues.

I am halfway through writing code to convert a standard TV remote to control the units with the help of an Arduino Uno. It is very straight forward as standard libraries already exist to decode IR signals and to create software based comm ports.

741Z commented 1 year ago

Here are some control codes

initialize system tn 0,0,0,0,0,0,0,0,0 sk 31,3f,ff sk 31,11,0f sk 31,d0,2f sk 51,af,ff

+1db sk 31,1f,ff

Mid volume sk 31,11,0f

2spk mode sk 31,d0,2f

3spk mode sk 31,d0,3f

5spk mode sk 31,d0,4f

Digital select sk 51,af,ff

Analog select sk 42,af,ff

Mute on sk 31,4f,ff

Mute off sk 31,3f,ff

probonopd commented 1 year ago

I am halfway through writing code to convert a standard TV remote to control the units with the help of an Arduino Uno. It is very straight forward as standard libraries already exist to decode IR signals and to create software based comm ports.

Wow @741Z I am very much looking forward to that.

probonopd commented 1 year ago

The 89 pages Bose manual Part Number 199401-TG1 ("Troubleshooting Guide Powered Acoustimass® -25 and -30 Series II Speaker System AM-25P II/ AM-30P II Digital Bass Module") has the information we've been after.

Section 3: Computer Aided Troubleshooting Procedures is to be used if you have a PC that can be used to communicate with the Digital Signal Processor PCB of the bass module, and is the preferred method of troubleshooting.

The recommended test setup involves a special Bose cable and a third-party serial converter box and is described on p. 68:

image

The TTL to RS232 Converter for the PC is described on p. 80:

TTL to RS232 Converter The serial port uses ±12V inverted logic where logical 0 = +12V and logical 1 = -12V. The bass box uses “TTL” logic where logical 0 = 0V and logical 1 = +5V. The B+B converter box simply inverts and level-shifts the data flowing both ways. Full details of the converter are available at www.bb-elec.com. Search in the converters section for the Model 232TTL.

The codes are described on pp. 80:

image

image

Bose did (does?) have excellent manuals. It's a shame they didn't come in the box. I'd have loved to have this information back in the day when the device was new.

I mean, it really explains stuff...

image

resmh commented 1 year ago

Hi,

I can confirm that an Lifestyle® 8 Series II system can be controlled via 4800 baud TTL signals . You can easily us an Arduino to send commands or even a RS-232 port from a PC as long as you have some thing to convert the signals to TTL . I have also used the program located at this site https://terencewrose.webador.co.uk/ to control the unit with no issues.

I am halfway through writing code to convert a standard TV remote to control the units with the help of an Arduino Uno. It is very straight forward as standard libraries already exist to decode IR signals and to create software based comm ports.

Thank you so much! I still posess the unit and look forward to start tinkering with it again 👍

probonopd commented 1 year ago
TAP Command Description
tv print firmware revisions
vr print uC checksum
rs reset pcb
rc reset DSPs
rd reset codec
de dump the contents of EEPROM
we xx,yy Write data "xx" (hex) to EEPROM address "yy" (hex)
ce 0 re-calculate and store EEPROM checksum
ef xx fill EEPROM with data "xx" (hex)
sk 51,af,ff select AUX input (digital)
sk 61,af,ff select VID1 input (analog)
ad x print uC ADC port voltage, where "x" equals:
0 bass pot position
1 treble pot position
2 thermistor voltage
3 3.3V supply
4 SPDIF detect
5 codec reference voltage
6 twddler DC offset
7 turn-on signal
(result is 8-bit, 0=0V, FF=5V)
sk 42,af,ff select TAPE input (analog)
sk 31,1f,ff volume up 1dB
sk 31,2f,ff volume down 1dB
sk 31,1x,xf set volume to -xx volume
e.g.
sk 31,10,0f 00dB
sk 31,11,2f -12dB
sk 31,13,4f -34dB
sk 31,9f,ff center/surround volume up (3-speaker / 5-speaker)
sk 31,af,ff center/surround volume down
sk 31,9x,xf set center/surround volume
e.g.,
sk 31,90,0f +7dB
sk 31,90,1f +6dB
sk 31,90,7f 0dB
sk 31,91,4f -7dB
sk 31,91,5f -8dB
sk 31,4f,ff mute
sk 31,3f,ff un-mute
sk 31,d0,2f select 2-speaker mode
sk 31,d0,3f select 3-speaker mode
sk 31,d0,4f select 5-speaker mode
sk 3f,6f,ff off
tn 3,0,0,0,0,0,0,0,0 passthrough, with all signal processing
tn 6,0,0,0,0,0,0,0,0 passthrough, with no signal processing
tn 0,0,0,0,0,0,0,0,0 exit test mode, restore normal signal processing
tn 4,0,0,0,0,0,0,0,0 request DSP checksum calculation
dp 10,0,2,0,12 fetch and print DSP checksum calculation
dp 10,0,0,0,0 peek at DSP 1 address 0
dp 20,0,0,0,0 peek at DSP 2 address 0
sk 31,ex,yf x=8 2-speaker
x=9 3-speaker
x=A 5-speaker
y=4 single bits, as follows
DRC off/on
1_to_5 off/on

Here in a format suitable for pasting into source code:

// TAP Command                  Description
// --------------------------------------------
// tv                          print firmware revisions
// vr                          print uC checksum
// rs                          reset pcb
// rc                          reset DSPs
// rd                          reset codec
// de                          dump the contents of EEPROM
// we xx,yy                    Write data "xx" (hex) to EEPROM address "yy" (hex)
// ce 0                        re-calculate and store EEPROM checksum
// ef xx                       fill EEPROM with data "xx" (hex)
// sk 51,af,ff                 select AUX input (digital)
// sk 61,af,ff                 select VID1 input (analog)
// ad x                        print uC ADC port voltage, where "x" equals:
//                             0    bass pot position
//                             1    treble pot position
//                             2    thermistor voltage
//                             3    3.3V supply
//                             4    SPDIF detect
//                             5    codec reference voltage
//                             6    twddler DC offset
//                             7    turn-on signal
//                             (result is 8-bit, 0=0V, FF=5V)
// sk 42,af,ff                 select TAPE input (analog)
// sk 31,1f,ff                 volume up 1dB
// sk 31,2f,ff                 volume down 1dB
// sk 31,1x,xf                 set volume to -xx volume
//                             e.g.
//                             sk 31,10,0f  00dB
//                             sk 31,11,2f  -12dB
//                             sk 31,13,4f  -34dB
// sk 31,9f,ff                 center/surround volume up (3-speaker / 5-speaker)
// sk 31,af,ff                 center/surround volume down
// sk 31,9x,xf                 set center/surround volume
//                             e.g.,
//                             sk 31,90,0f  +7dB
//                             sk 31,90,1f  +6dB
//                             sk 31,90,7f   0dB
//                             sk 31,91,4f  -7dB
//                             sk 31,91,5f  -8dB
// sk 31,4f,ff                 mute
// sk 31,3f,ff                 un-mute
// sk 31,d0,2f                 select 2-speaker mode
// sk 31,d0,3f                 select 3-speaker mode
// sk 31,d0,4f                 select 5-speaker mode
// sk 3f,6f,ff                 off
// tn 3,0,0,0,0,0,0,0,0        passthrough, with all signal processing
// tn 6,0,0,0,0,0,0,0,0        passthrough, with no signal processing
// tn 0,0,0,0,0,0,0,0,0        exit test mode, restore normal signal processing
// tn 4,0,0,0,0,0,0,0,0        request DSP checksum calculation
// dp 10,0,2,0,12              fetch and print DSP checksum calculation
// dp 10,0,0,0,0               peek at DSP 1 address 0
// dp 20,0,0,0,0               peek at DSP 2 address 0
// sk 31,ex,yf                 x=8  2-speaker
//                             x=9  3-speaker
//                             x=A  5-speaker
//                             y=4 single bits, as follows
//                             DRC off/on
//                             1_to_5 off/on
// Source: Bose manual Part Number 199401-TG1 pp. 80
probonopd commented 1 year ago

...and with that, I wonder whether this Arduino "mute/unmute sketch" would toggle mute on and off:

#include <Arduino.h>

bool isMuted = false;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT); // Set built-in LED as an OUTPUT
  digitalWrite(LED_BUILTIN, LOW); // Initial state of the LED is OFF

  Serial.begin(4800, SERIAL_8N1); // Start serial communication
}

void loop() {
  // Mute the audio and turn on the LED
  Serial.println("sk 31,4f,ff"); // Send mute command
  digitalWrite(LED_BUILTIN, HIGH);

  delay(5000); // Sleep for 5 seconds

  // Unmute the audio and turn off the LED
  Serial.println("sk 31,3f,ff"); // Send unmute command
  digitalWrite(LED_BUILTIN, LOW);

  delay(5000); // Sleep for 5 seconds
}

Unfortunately I don't have the device at hand currently. Maybe @741Z can confirm?

probonopd commented 1 year ago

Quickly put together an Arduino library that makes this easier to use: https://github.com/probonopd/TAPController/

Would love code reviews and tests. Unfortunately I don't have the device at hand currently.

741Z commented 1 year ago

...and with that, I wonder whether this Arduino "mute/unmute sketch" would toggle mute on and off:

#include <Arduino.h>

bool isMuted = false;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT); // Set built-in LED as an OUTPUT
  digitalWrite(LED_BUILTIN, LOW); // Initial state of the LED is OFF

  Serial.begin(4800, SERIAL_8N1); // Start serial communication
}

void loop() {
  // Mute the audio and turn on the LED
  Serial.println("sk 31,4f,ff"); // Send mute command
  digitalWrite(LED_BUILTIN, HIGH);

  delay(5000); // Sleep for 5 seconds

  // Unmute the audio and turn off the LED
  Serial.println("sk 31,3f,ff"); // Send unmute command
  digitalWrite(LED_BUILTIN, LOW);

  delay(5000); // Sleep for 5 seconds
}

Unfortunately I don't have the device at hand currently. Maybe @741Z can confirm?

I am not sure where you are sending your serial signal. I use the library SoftwareSerial on the Arduino to send the data to some defined I/O pins. You should think about sending an initialisation string that puts the unit in the correct state for your use case. For example if the are in DTS mode and send an analogue signal you won't hear anything out of the unit.

741Z commented 1 year ago

The simplest way to start talking to the unit is to buy a $2 USB to TTL Serial Cable from Aliexpress and install something like Terra term or some other terminal that will talk to a comm port.

probonopd commented 1 year ago

Updated the library to use SoftwareSerial.

741Z commented 1 year ago

Below is a simple code for use on an Arduno uno, it is slightly tweaked code from one of the examples provided on with SoftwareSerial library. When you run the serial monitor in the Arduino IDE ( set in this code at 19200 Baud) you will be able to talk to the Bose speaker via pins 1 and 2 of the Arduino . The response back from the speaker will show in the serial monitor. Using this code will confirm that you are correctly talking to the speaker.

I will share the code that converts from using and IR remote to control the speaker shortly.

include

SoftwareSerial mySerial(2, 3); // RX, TX

void setup() { // Open serial communications and wait for port to open: Serial.begin(19200); while (!Serial) { ; // wait for serial port to connect. Needed for Native USB only

}

Serial.println("let's go!");

// set the data rate for the SoftwareSerial port mySerial.begin(4800); // mySerial.println("Hello, world?"); }

void loop() // run over and over { if (mySerial.available()) Serial.write(mySerial.read()); if (Serial.available()) mySerial.write(Serial.read());

}

probonopd commented 1 year ago

@741Z any chance you could give my library a try?

741Z commented 1 year ago

@741Z any chance you could give my library a try?

There is a global recall for a lot of these units. Mine is out for repair, my guess is I won't see it back for another 6-8 weeks.

JeyZed123 commented 8 months ago

I am facing the same issue, the Sub is the only working component left.

@probonopd I've tried your Code, both from this Thread and the Library one with.

I couldn't get any good result, nothing seems to work an the Bose. With the library I didn't get very far. There are some errors when compiling:

/var/folders/kg/6601vtgs30db0vsrd205gj100000gn/T/arduino_modified_sketch_56594/MuteUnmuteExample.ino: In function 'void loop()': MuteUnmuteExample:16:3: error: 'tapController' was not declared in this scope tapController.muteAudio(); ^~~~~ /var/folders/kg/6601vtgs30db0vsrd205gj100000gn/T/arduino_modified_sketch_56594/MuteUnmuteExample.ino:16:3: note: suggested alternative: 'TAPController' tapController.muteAudio(); ^~~~~ TAPController

I tried to tweet both codes and implemented the starting procedure. Nothing did anything Maybe this helps you troubleshooting, if needed Itry to be of help.

include

bool isMuted = false;

void setup() { pinMode(LED_BUILTIN, OUTPUT); // Set built-in LED as an OUTPUT digitalWrite(LED_BUILTIN, LOW); // Initial state of the LED is OFF

Serial.begin(4800, SERIAL_8N1); // Start serial communication }

void loop() { // Initialize startup and turn on the LED Serial.println("tn 0,0,0,0,0,0,0,0,0"); //reset to dnormal signal processing delay(50); Serial.println("sk 31,4f,ff"); // Send mute command delay(50); Serial.println("sk 31,11,0f"); //Set Volume to medium delay(50); Serial.println("sk 31,d0,4f"); //Select 5 speaker setup delay(50); Serial.println("sk 42,af,ff"); //select Tape Analog Input delay(50); digitalWrite(LED_BUILTIN, HIGH);

delay(10000); // Sleep for 10 seconds

// Unmute the audio and turn off the LED Serial.println("sk 31,3f,ff"); // Send unmute command digitalWrite(LED_BUILTIN, LOW);

delay(5000); // Sleep for 5 seconds

}

741Z commented 8 months ago

I am facing the same issue, the Sub is the only working component left.

@probonopd I've tried your Code, both from this Thread and the Library one with.

I couldn't get any good result, nothing seems to work an the Bose. With the library I didn't get very far. There are some errors when compiling:

/var/folders/kg/6601vtgs30db0vsrd205gj100000gn/T/arduino_modified_sketch_56594/MuteUnmuteExample.ino: In function 'void loop()': MuteUnmuteExample:16:3: error: 'tapController' was not declared in this scope tapController.muteAudio(); ^~~~~ /var/folders/kg/6601vtgs30db0vsrd205gj100000gn/T/arduino_modified_sketch_56594/MuteUnmuteExample.ino:16:3: note: suggested alternative: 'TAPController' tapController.muteAudio(); ^~~~~ TAPController

I tried to tweet both codes and implemented the starting procedure. Nothing did anything Maybe this helps you troubleshooting, if needed Itry to be of help. #include

bool isMuted = false;

void setup() { pinMode(LED_BUILTIN, OUTPUT); // Set built-in LED as an OUTPUT digitalWrite(LED_BUILTIN, LOW); // Initial state of the LED is OFF

Serial.begin(4800, SERIAL_8N1); // Start serial communication }

void loop() { // Initialize startup and turn on the LED Serial.println("tn 0,0,0,0,0,0,0,0,0"); //reset to dnormal signal processing delay(50); Serial.println("sk 31,4f,ff"); // Send mute command delay(50); Serial.println("sk 31,11,0f"); //Set Volume to medium delay(50); Serial.println("sk 31,d0,4f"); //Select 5 speaker setup delay(50); Serial.println("sk 42,af,ff"); //select Tape Analog Input delay(50); digitalWrite(LED_BUILTIN, HIGH);

delay(10000); // Sleep for 10 seconds

// Unmute the audio and turn off the LED Serial.println("sk 31,3f,ff"); // Send unmute command digitalWrite(LED_BUILTIN, LOW);

delay(5000); // Sleep for 5 seconds

}

I have not looked at your code too closely, however, something does not seem right here. During the initial debug process you probably want 2 serial ports, one serial port accessible via the USB port so you ( most code samples refer to this port as "serial", and then you need to define the software serial port, often called "myserial" is some of the sample code on the internet. Don't forget to also define the I/O pins of the TX and RX pins .

Reference info here https://docs.arduino.cc/learn/built-in-libraries/software-serial.

I have been writing some code that converts a generic IR remote signals to control the Bose amplifier. Once I have done a bit more polishing of the code I will share it here.

JeyZed123 commented 8 months ago

Thanks for the reply. If I understand correctly, the Serial. always refers to the TX and RX ports of the board. Also outputted via USB.

If you have a code that can get the Bose Subwoofer to work I be grateful, so I could find out if maybe that ist the problem or not.

Mine is a Acoustimass 8 with the 8 PIN connector. On the cable the 3.5mm jack and white and red Chinch for input.

741Z commented 8 months ago

Thanks for the reply. If I understand correctly, the Serial. always refers to the TX and RX ports of the board. Also outputted via USB.

If you have a code that can get the Bose Subwoofer to work I be grateful, so I could find out if maybe that ist the problem or not.

Mine is a Acoustimass 8 with the 8 PIN connector. On the cable the 3.5mm jack and white and red Chinch for input.

My comments below refer to an Arduino Uno. Things may be different if you are using something different , Example ESP32

"Serial" is generally the hardware serial port accessible via usb. For debug and monitoring comms coming back from the bose unit, I would be continuing to keep this port on. With "software Serial" you define a second port to talk to the bose amp, an example could be pin 10 and 11 of an Arduino uno. The output of the Arduino Uno is TTL ( aka 5v= 1 and 0 volt = 0 ) which which works perfectly with the bose ( never plug an RS-232 cable directly into the bose amp as this is much higher voltage and may damage the bose). The bose will work with only: gnd, RX pin, and the "power on" pin. However, if you also connect the bose TX pin you can read back things like temperature and bass and treble settings.

JeyZed123 commented 8 months ago

Thanks, I fidelt around but nothing really worked. And how would you connect the TX? Wouldn't that connect RX and TX together cause there is only one data Port? Sorry for all the questions I already feel silly, but as having trouble getting anykind of progress as it seems, my thought feel a little blocked

741Z commented 8 months ago

Thanks, I fidelt around but nothing really worked. And how would you connect the TX? Wouldn't that connect RX and TX together cause there is only one data Port? Sorry for all the questions I already feel silly, but as having trouble getting anykind of progress as it seems, my thought feel a little blocked

This image shows the pins for TX and RX on the Bose plug.

https://cloud.githubusercontent.com/assets/2480569/21572405/dbf18478-ced8-11e6-9ec8-199eccb8d46c.jpg

You can buy the plugs from Ali Express for about $1-$2 each. In the short term if you have single wire Dupont pin connectors handy, you can make contact with the relevant pins. Don't forget Comms ground and Audio Ground ( Common) are different, and nothing will work unless the Bose power on pin is seeing 9-10 volts.

A simpler way to kick things off is buy a usb to TTL out cable from Ali Express ( $1-$3 ) and use a terminal emulator on your PC ( Tera Term is an option). You can then talk directly to the Bose amp. This will confirm all your basic electrical connections are working correctly. The Bose service manuals have example of how to connect a PC via a comm port to the Bose unit.

741Z commented 6 months ago

As promised here is the code that works. Feel free to contact me if you have questions. Use at your own risk. no warranties provided .

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

include //used to read IR remote signals

include

// Ver 17_Publish //Written by SK March 2024 - https://github.com/741Z

/* This is some basic code to control some of the earlier Bose Acoustimass amplifiers using an Arduino Uno. There are many ways it could be enhance, perhaps porting to a ESP32 with a simple web interface.

Communication : You will need to connect from the relevant pins of the Arduino to the connector pins on the BOSE. Connecting to the TX pin of the Bose unit ( RX pin on the Arduino) is not strictly necessary, but can give some handy information on the units operation. For example temperature readings. Monitor via terminal: If you are using a simple terminal session to monitor the comm port via USB, most commands are mirrored via the terminal session. The current code also sends some plan text to the monitor session to help understand what is going on. You could always turn this feature off, but, as the code does not tax the MCU too much, it does not really matter.

Display LEDs: Pins 6 and 7 are connected to LED’s they will give some simple indication of status and operation.

Power and volume buttons : Pins 3 thru 5 are used to provide simple on/off, volume up/down functionally.

IR remote control : A standard IR receiver module ( less that $1 on Ali express) is used to receive IR signals via pin 2. Most IR remotes can be used, just create some simple code to decode the signals of the remote control you have and them map the code to the command you want to perform in the code.

Powering up the Bose Amplifier: Not the unit needs a specific voltage at one of the pins to turn on the units triac via an opto couple. You will need to construct a specific circuit to provide this power to the unit. This code sends power to pin 8 to power up the power circuit. However, the Bose manuals show a temporary way to use a 9 volt battery to do the same job for testing purposes.

NOTE 1: If you only connect the 3 digital push buttons, connect the TX/RX pins and provide the correct voltage to the power up pin that should be sufficient to prove out your code and connections.

NOTE 2 don't forget to include libraries IRremote.hpp & SoftwareSerial.h>

Text V1.0 */

// Set TX and RX pins for Bose comms SoftwareSerial mySerial(10, 11); // RX, TX

//int IRsignal Set IRinput to pin 2 IRrecv IR(2);

// set up IO const int PowerPin = 3; // the number of the pushbutton pin //pin 3 Power button const int VolDownPin = 4; // the number of the pushbutton pin //pin 4 Vol Down button const int VolUpPin = 5; // the number of the pushbutton pin //pin 5 Vol UP button const int GreenLed = 6; //pin 6 Green led const int RedLed = 7; //pin 7 Red Led const int PowerOpto = 8; //pin 8 Power Opto circuit . Used to turn on Opto to send 10 volts to Bose unit to turn on

// Variable setup bool PowerState = false ; // Set power state to false/off at start up bool FirstPowerState = false ; // Used to track unit has just been powered up bool MuteState = false ; // Set Mute state to false/off at start up . Mute = True = Mute = On

int buttonState = 0; // variable for reading the Power pushbutton status int VolDownbuttonState = 0; // variable for reading the Vol Down pushbutton status int VolUpbuttonState = 0; // variable for reading the Vol Down pushbutton status

void setup() { // initialize the LED pin as an output: pinMode(GreenLed, OUTPUT); pinMode(RedLed, OUTPUT); pinMode(PowerOpto, OUTPUT);

// initialize the pushbutton pin as an input: pinMode(PowerPin, INPUT_PULLUP); // input with pull up turned on pinMode(VolDownPin, INPUT_PULLUP); // input with pull up turned on pinMode(VolUpPin, INPUT_PULLUP); // input with pull up turned on

IR.enableIRIn(); Serial.begin (9600); // Set serial Baud rate to communicate with terminal mySerial.begin(4800); // set the data rate for the SoftwareSerial port on Bose unit

delay (1000); // wait for initialization Serial.println("let's go!"); // Simple word to confirm PC terminal is working

} // End setup loop

void loop() {

//blink both green and red leds until unit has been sent "power on" command up after MCU being powered up if (FirstPowerState == false) { digitalWrite(GreenLed, HIGH); //Turn On Leds digitalWrite(RedLed, HIGH); delay(200); digitalWrite(GreenLed, LOW); //Turn Off Leds digitalWrite(RedLed, LOW); delay(200); }

// read the state of the pushbutton value: buttonState = digitalRead(PowerPin); VolDownbuttonState = digitalRead(VolDownPin); VolUpbuttonState = digitalRead(VolUpPin);

// Check if power button pushed if (buttonState == LOW) {
while (buttonState == LOW) { // hold here until button lifted buttonState = digitalRead(PowerPin);//do nothing } PowerToggle(); delay(500); // Use as a bit of a debounce protection }

// Volume Down button Note : Holding button will mean function will continue to repeat if (VolDownbuttonState == LOW) {
VolDown(); delay(100); // Use as a bit of a debounce protection }

// Volume Up button Note : Holding button will mean function will continue to repeat if (VolUpbuttonState == LOW) {
VolUp(); delay(100); // Use as a bit of a debounce protection }

if (IR.decode()) {

Serial.println(IR.decodedIRData.decodedRawData,HEX) ; // Send recieved IR code to Terminal session via USB

// Action recieved IR code

switch (IR.decodedIRData.decodedRawData ) { case 0xF10E7F00: // Volume up VolUp(); // Call Volume up function break; case 0xF00F7F00: // Volume down VolDown(); // Call Volume Down function break; case 0xEF107F00: // Power Toggle PowerToggle(); //call function break;
case 0xEE117F00: // Mute toggle MuteToggle(); break; case 0xAB547F00: // Orange Key Serial.println( "print firmware revisions"); mySerial.println ("tv"); //print firmware revisions ListentoSerial(); //fucntion to send recived data from Bose unit and send to terminal via USB port break; case 0xB34C7F00: // Green Key Serial.println( " print uC checksum"); mySerial.println ("vr"); // print uC checksum ListentoSerial(); //fucntion to send recived data from Bose unit and send to terminal via USB port break; case 0xA9567F00: // Yellow Key Serial.println( " dump the contents of EEPROM"); mySerial.println ("de"); // dump the contents of EEPROM ListentoSerial(); //fucntion to send recived data from Bose unit and send to terminal via USB port break; case 0xAA557F00: // Blue Key Serial.println( " thermistor voltage"); mySerial.println ("ad 2"); // ListentoSerial(); //fucntion to send recived data from Bose unit and send to terminal via USB port break; case 0xEC137F00: // Display Key Serial.println( " bass pot position"); mySerial.println ("ad 0"); // ListentoSerial(); //fucntion to send recived data from Bose unit and send to terminal via USB port Serial.println( " treble pot position"); mySerial.println ("ad 1"); // ListentoSerial(); //fucntion to send recived data from Bose unit and send to terminal via USB port break;

default: Serial.println( "Defaultx"); break;

} // End case statement

delay (500); IR.resume ();

} }

//Functions

int PowerToggle(){ Serial.println ("Power Toggle"); if (PowerState == false)
{ // Power ON

    mySerial.println ("tn 0,0,0,0,0,0,0,0,0"); //  will need to convert output to TTL comm port 
    mySerial.println ("sk 31,3f,ff");
    mySerial.println ("sk 31,11,0f");
    mySerial.println ("sk 31,d0,2f");
    mySerial.println ("sk 51,af,ff");
    LedBlink();
    digitalWrite(GreenLed, HIGH);   //Turn On Leds 
    digitalWrite(RedLed, LOW); //Turn Off Leds 
    PowerState = true ;  // Set Powerstate to true
    Serial.println ("Power on");
    digitalWrite(PowerOpto, HIGH);   //Turn on Amp via Opto couple 
    FirstPowerState = true ;  // clear first powerstate flag
    delay (2000); // Allow time for unit to warm up before sending configuration 
  }
   else 
   {  // power off code 
    LedBlink();
    digitalWrite(GreenLed, LOW);   //Turn On Leds 
    digitalWrite(RedLed, HIGH); //Turn Off Leds 
    PowerState = false ;  // Set Powerstate to off
     mySerial.println ("sk 3f,6f,ff");
    Serial.println ("Power Off");
    delay (500); //short delay before turn off

    digitalWrite(PowerOpto, LOW); //Turn Off Amp via Opto couple 
   }
  return ;

} //end PowerToggle function

int MuteToggle(){ // int result; Serial.println ("Mute Toggle");

  if (MuteState == false)  
  {
    LedBlink();  
    Serial.println( "Mute on");
    mySerial.println ("sk 31,4f,ff"); //  will need to convert to toggle output
    MuteState = true;
  }
   else 
   {  // muteoff code 
      LedBlink();
     Serial.println( "Mute off");
      mySerial.println ("sk 31,3f,ff"); //  will need to convert to toggle output
      Serial.println ("Power off");
      MuteState = false;
   }
  return ;

} // End mutetoggle function

int VolUp() { Serial.println("+1db"); mySerial.println ("sk 31,1f,ff"); // Converted output to TTL comm port LedBlink(); return ; } // End function

int VolDown() { Serial.println("-1db"); mySerial.println ("sk 31,2f,ff"); // will need to convert output to TTL comm port LedBlink(); return ; } // End function

int LedBlink() //Function to Blink LED to indicate signal { digitalWrite(RedLed, HIGH); //Turn Red Led On delay(100); digitalWrite(RedLed, LOW); //Turn OFF Red Leds if (PowerState == false) { delay(100); digitalWrite(RedLed, HIGH); //Turn Red Led On } return ; } // End function

int ListentoSerial() // loop to display comms from amplifier {

while (mySerial.available()>0) Serial.write(mySerial.read()); delay(10); while (mySerial.available()>0) Serial.write(mySerial.read()); Serial.println("Listen Serial complete"); return ; } // End function

Hagit60 commented 5 months ago

@741Z Great work. Thanks for the info. If I understand correctly, the serial code for 'Power ON' is: 'tn 0,0,0,0,0,0,0,0,0' from TXD of the serial port to the SER-DATA-IN pin 12 of the Bose plug sent. This to make the TTL comm understand a command? In my case it is a command in baudRate 4800, dataBits 8, stopBits 1, 5v. The turn-on switch is switched on with 9v via pin 6 and 7. Not a single command is understood. Are there any other triggers needed for the TTL comm command to be understood? Or does INIT TAP/r have a role somewhere? Please some help.

Hagit60 commented 5 months ago

@741Z Great work. Thanks for the info. If I understand correctly, the serial code for 'Power ON' is: 'tn 0,0,0,0,0,0,0,0,0' from TXD of the serial port to the SER-DATA-IN pin 12 of the Bose plug sent. This to make the TTL comm understand a command? In my case it is a command in baudRate 4800, dataBits 8, stopBits 1, 5v. The turn-on switch is switched on with 9v via pin 6 and 7. Not a single command is understood. Are there any other triggers needed for the TTL comm command to be understood? Or does INIT TAP/r have a role somewhere? Please some help.

I think I have solved my question. The tn 0,0,0,0,0,0,0,0,0 code is for DSP off.