Open probonopd opened 6 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.
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).
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 .
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).
Interesting! Hope you can figure something out by comparing some codes.
Maybe @bengtmartensson recognizes this type of code from just looking at it?
Looks like biphase encoding to me. IrpTransmogrifier is a good tool for analyzing this.
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.
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.
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?
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.
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
This is truly amazing @bengtmartensson
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... ;-)
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.
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?
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?
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 .
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
Thank you @bengtmartensson, that should get us started.
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
Thank you. Have you been successful in sending those commands from Arduino?
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.
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:
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 😊
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.
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
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.
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:
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:
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...
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 👍
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
...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?
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.
...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.
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.
Updated the library to use SoftwareSerial.
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.
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());
}
@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.
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.
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 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(); ^~~~~ TAPControllerI 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.
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.
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.
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
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.
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
// 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
@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.
@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.
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.