Saturday, November 30, 2013
Prototype Bluetooth Module
Here's my prototype; still need to do some more testing, write some software, and I'm waiting on some parts to arrive from China but things are looking promising! :)
Tuesday, September 17, 2013
Module Differences
I thought I would explain some differences in the 2 modules I'm working on.
1- 3.5mm input version
This version accepts input from any 3.5mm (1/8") stereo plug such as iPod, iPhone, Android, whatever. You can even plug in a Bluetooth audio receiver that has a 3.5mm plug on it & then you can stream from an iPhone or Android to this device.
This version also supports iPhone music controls via the steering wheel controls; play/pause, next track, & previous track. BUT this requires that you run another wire (maybe 2?) from this module to the iPhone, to a 30 pin iPod connector. Yes, you can use a 30 pin to Lightning cable adapter & it will work for iPhone 5.
Being that this module plugs into the trunk mounted cd changer plug, you'll need to route this cable/cables from the trunk to the front if the car, along the door sill & under the carpet, behind the dash, etc. Not terribly hard, just takes a little time. I suggest either a 25' 3.5mm stereo male to male cable for audio only, or maybe an Ethernet cable for audio & iPod controls.
This version is not "upgradable" to version 2; the guts are completely different with different PCBs.
2- Bluetooth version (still in work, but this is how it should work)
This version doesn't require any wires to be run at all; the audio is wireless, and the iPhone/Android controls are wireless. The steering wheel controls will control next & previous tracks, and at this point, maybe Bluetooth syncing or power toggle, not sure yet; just a matter of software.
Both modules will display a string of up to 12 characters from the lower ASCII table (up to character 128 I think...?), whenever the radio is put into cd changer mode.
As of now, and I don't have any plans to do this, there isn't a combo board, that allows either 3.5mm or Bluetooth in one module (unless you just want to plug a Bluetooth receiver into the 3.5mm jack).
Thursday, September 12, 2013
Bluetooth PCB
http://oshpark.com/shared_projects/sIXxprRv
That's the link for my new PCB incorporating the MB-CM15113 bluetooth module from SureElectronics. I still have the software to play with, but I'm pretty sure it'll work.
More to come!
That's the link for my new PCB incorporating the MB-CM15113 bluetooth module from SureElectronics. I still have the software to play with, but I'm pretty sure it'll work.
More to come!
Wednesday, September 11, 2013
CD Connector
I found TE Connectivity apparently bought AMP, who makes the CD changer connector. You might be able to contact TE about getting some samples, for free.
Part # 827229-1
But I know that Jim at The Connector People has them for under $13/ea. They have a $50 minimum, so you need to buy 4, plus shipping.
$10 Line Minimum$50 Order Minimum
Fax: 215-956-1701
jim@connectorpeople.com
Part # 827229-1
But I know that Jim at The Connector People has them for under $13/ea. They have a $50 minimum, so you need to buy 4, plus shipping.
Jim McDermott
NTI - The Connector People ®
420 Valley RdWarrington, PA 18976$10 Line Minimum$50 Order Minimum
Fax: 215-956-1701
jim@connectorpeople.com
Ph: 215-956-1700
Saturday, September 7, 2013
Bluetooth module
So I just tried the Bluetooth module for audio; works good :)
I bought 2 different modules but only tested audio on one.
Here are the 2 modules;
I'll be working in a new board design soon :)
Monday, August 26, 2013
Updated BOM
Here's a Mouser project to all the parts:
http://www.mouser.com/ProjectManager/ProjectDetail.aspx?AccessID=89c9334eae
http://www.mouser.com/ProjectManager/ProjectDetail.aspx?AccessID=89c9334eae
Qty |
Value | Device | Package | Parts | Description |
3 | LED5MM | LED5MM | LED1, LED2, POWER | LED | |
6 | PINHD-1X1 | 1X01 | +5V, GND, LIN, RIN, RX, TX | PIN HEADER | |
1 | .1uF | C-US025-025X050 | C025-025X050 | C2 | CAPACITOR, American symbol |
1 | 0.1uF | C-US025-025X050 | C025-025X050 | C1 | CAPACITOR, American symbol |
4 | 100nF | C-US025-025X050 | C025-025X050 | C3, C4, C5, C6 | CAPACITOR, American symbol |
1 | 10K | R-US_0207/10 | 0207/10 | R5 | RESISTOR, American symbol |
2 | 10K | R-US_0207/2V | 0207/2V | R4, R6 | RESISTOR, American symbol |
4 | 10uF | C-EU025-030X050 | C025-030X050 | C11, C12, C13, C14 | CAPACITOR, European symbol |
2 | 10uF | CPOL-EUE2.5-5 | E2,5-5 | C9, C10 | POLARIZED CAPACITOR, European symbol |
1 | 1N4007-01 | 1N4007-01 | D01B | D1 | 1N4007/SM4007: General purpose silicon diode |
1 | 1uF | CPOL-EUE2.5-5 | E2,5-5 | C8 | POLARIZED CAPACITOR, European symbol |
3 | 330R | R-US_0207/2V | 0207/2V | R1, R2, R3 | RESISTOR, American symbol |
1 | 470nF | C-US025-025X050 | C025-025X050 | C7 | CAPACITOR, American symbol |
1 | 7805 | 78XXS | 78XXS | IC4 | VOLTAGE REGULATOR |
1 | 827229-1 | 827229-1 | 827229-1 | U$5 | |
2 | DRV134PA | DRV134PA | DIL08 | U$3, U$4 | Audio Balanced Line Drivers |
1 | FTDI_1-6 | FTDI_BASICPTH | FTDI_BASIC | JP1 | FTDI Basic: 3.3V and 5V |
1 | LTC1144 | LTC1144 | DIP08L-SETH | N1 | LTC1144: Switched capacitor voltage converter (Linear Technology) |
1 | MCP2515-E/P | MCP2515-E/P | DIL18 | IC1 | |
1 | MEGA8-P | MEGA8-P | DIL28-3-SETH | IC3 | MICROCONTROLLER |
2 | RESONATORPTH | RESONATORPTH | RESONATOR-PTH | U$1, U$2 | Resonator |
1 | SN65HVD251P | SN65HVD251P | DIL08 | IC2 |
Tuesday, August 13, 2013
New module
Possible new version of BlueSaab :)
This one only has a 3.5mm stereo plug for audio...working on an ethernet jack or something like that...
This one only has a 3.5mm stereo plug for audio...working on an ethernet jack or something like that...
Wednesday, August 7, 2013
Contact Info
I love helping people figure things out so they can be more self-sufficient.
If anyone has any questions, I'll be more than happy to try and answer them.
I can be reached at se4587 at oohay (backwards).com. Same thing at gmail but I don't check/use it as often.
I only had 1 person actually purchase the old cut-crimp method of wiring up a unit, so i'm curious how many people would be interested in this new version...? I see that one guy is still interested in steering wheel ipod controls :) Like I said, that feature is still there, it just needs to be wired up to an ipod connector.
If anyone has any questions, I'll be more than happy to try and answer them.
I can be reached at se4587 at oohay (backwards).com. Same thing at gmail but I don't check/use it as often.
I only had 1 person actually purchase the old cut-crimp method of wiring up a unit, so i'm curious how many people would be interested in this new version...? I see that one guy is still interested in steering wheel ipod controls :) Like I said, that feature is still there, it just needs to be wired up to an ipod connector.
Tuesday, August 6, 2013
New PCB & code
So I did some more redesigning and played with the code again. I moved away from the priority SID text because it prevented my Night Panel from working.
Here's a link to my public OSHPark.com profile. You can order PCBs (in multiples of 3) for ~$30, shipped. They're excellent quality. I'll get some pictures up soon of a newly finished board.
Also, this version uses the original CD Changer harness plug so no more splicing wires!! Literally, plug-n-play.
So right now there are several options. The board & code still supports iPod steering wheel controls, but it doesn't sound like many people need/care/want that. I'm not going to remove that, but it sounds like most people just want an audio source, and a universal one at that.
I can just put a 3.5mm stereo jack in the case and you can run a long 3.5mm male to male cable from the trunk to the dash (under the door sills and such). This should work pretty well.
Or one could install a bluetooth module in the unit, much like my car does. I made sure there were 5v and GND pins available in case anyone wanted to power a bluetooth module up.
// ----------------------------------------------
// SECUDUINO
// http://secuduino.blogspot.com/
// By Igor Real
// 16/05/2011
//
// Saab CDC Changer Emulator
// http://BlueSaab.blogspot.com/
// By Seth Evans
// 29 July 2013
// ----------------------------------------------
#include <CAN.h>
int cdbutton = 0;
int toggleshuffle = 1;
int mute = 0;
int CDCcmd[] = {
0xE0,0x00,0x3F,0x31,0xFF,0xFF,0xFF,0xD0};
int ninefivecmd[] = {
0x62,0x00,0x00,0x16,0x01,0x02,0x00,0x00};
int beep[] = {
0x80,0x04,0x00,0x00,0x00,0x00,0x00,0x00};
int playipod[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x01,0xF9};
int playpauseipod[] = {
0xFF,0x55,0x03,0x02,0x00,0x01,0xFA};
int stopipod[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x02,0xF8};
int next[] = {
0xFF,0x55,0x03,0x02,0x00,0x08,0xF3};
int prev[] = {
0xFF,0x55,0x03,0x02,0x00,0x10,0xEB};
int shuffle[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x80,0x7A};
int repeat[] = {
0xFF,0x55,0x05,0x02,0x00,0x00,0x00,0x01,0xF8};
int buttonRelease[] = {
0xFF,0x55,0x03,0x02,0x00,0x00,0xFB};
void setup() {
// set up CAN
CAN.begin(47); // Saab I-Bus is 47.619kbps
Serial.begin(9600);
//cdbutton = 0;
//toggleshuffle = 1;
CAN_TxMsg.header.rtr=0; // this value never changes
CAN_TxMsg.header.length=8; // this value never changes
// not sure if this is needed; pauses program before it loops
Serial.println("9-5 Test Code 2");
delay(2000);
}
void loop() {
//cdbutton = 1;
//PrintBus();
// CDC code needs sent every second or less so all loops
// running added together need to take less than 1000ms
// but no more or the car won't "see" the CDC
CDC();
for (int i = 0; i <= 860; i++) {
if (CAN.CheckNew()) {
CAN_TxMsg.data[0]++;
CAN.ReadFromDevice(&CAN_RxMsg);
//PrintBus();
if (CAN_RxMsg.id==0x6A1) {
CAN_TxMsg.id=0x6A2; // CD Changer
for (int c = 0; c < 8; c++) {
CAN_TxMsg.data[c]=ninefivecmd[c];
}
CAN.send(&CAN_TxMsg);
}
if (CAN_RxMsg.id==0x3C0) {
if (CAN_RxMsg.data[0]==0x80) {
switch (CAN_RxMsg.data[1]) {
case 0x24:
cdbutton = 1;
for (int j = 0; j < 8; j++) {
CAN_TxMsg.id=0x430;
CAN_TxMsg.data[j]=beep[j];
}
CAN.send(&CAN_TxMsg);
for (int j = 0; j < 8; j++) {
Serial.write(byte(playipod[j]));
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 7; i++) {
Serial.write(byte(buttonRelease[i]));
}
break;
case 0x14:
cdbutton = 0;
for (int a = 0; a <=2; a++) {
for (int j = 0; j < 8; j++) {
CAN_TxMsg.id=0x430;
CAN_TxMsg.data[j]=beep[j];
}
CAN.send(&CAN_TxMsg);
}
for (int j = 0; j < 8; j++) {
Serial.write(byte(stopipod[j]));
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 7; i++) {
Serial.write(byte(buttonRelease[i]));
}
//Serial.println("Radio");
break;
}
if (cdbutton == 1) {
switch (CAN_RxMsg.data[1]) {
case 0x59: // NXT button signal
for (int j = 0; j < 7; j++) {
Serial.write(byte(playpauseipod[j]));
}
break;
case 0x76: // Long press of CD/RDM button
if (toggleshuffle > 3) {
toggleshuffle = 1;
}
switch (toggleshuffle) {
case 1:
for (int j = 0; j < 9; j++) {
Serial.write(byte(repeat[j]));
}
break;
case 2:
for (int j = 0; j < 9; j++) {
Serial.write(byte(repeat[j]));
}
break;
case 3:
for (int j = 0; j < 9; j++) {
Serial.write(byte(repeat[j]));
}
for (int j = 0; j < 8; j++) {
Serial.write(byte(shuffle[j]));
}
break;
}
toggleshuffle++;
//break;
case 0xB1: // Audio mute on?
for (int j = 0; j < 8; j++) {
Serial.write(byte(stopipod[j]));
}
break;
case 0xB0: // Audio mute off?
for (int j = 0; j < 8; j++) {
Serial.write(byte(playipod[j]));
}
break;
case 0x35: // Seek next (Seek+)?
for (int j = 0; j < 7; j++) {
Serial.write(byte(next[j]));
}
break;
case 0x36: // Seek previous (Seek-)?
for (int j = 0; j < 7; j++) {
Serial.write(byte(prev[j]));
}
break;
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 7; i++) {
Serial.write(byte(buttonRelease[i]));
}
}
}
}
if (CAN_RxMsg.id==0x290) {
if (CAN_RxMsg.data[0]==0x80) {
if (cdbutton == 1) {
switch (CAN_RxMsg.data[2]) {
//case 0x04: // NXT button on wheel
//for (int j = 0; j < 9; j++) {
//Serial.write(byte(repeat[j]));
//}
//break;
case 0x10: // Seek+ button on wheel
//Serial.println("Next");
for (int j = 0; j < 7; j++) {
Serial.write(byte(next[j]));
}
break;
case 0x08: // Seek- button on wheel
//Serial.println("Prev");
for (int k = 0; k < 7; k++) {
Serial.write(byte(prev[k]));
}
break;
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 7; i++) {
Serial.write(byte(buttonRelease[i]));
}
}
}
}
}
delay(1);
}
if (cdbutton==1) {
//Serial.println("iPod ON");
iPodOn();
}
else {
//Serial.println("iPod OFF");
//iPodOff();
//delay(400);
}
}
void CDC() {
CAN_TxMsg.id=0x3C8; // CD Changer
for (int c = 0; c < 8; c++) {
CAN_TxMsg.data[c]=CDCcmd[c];
}
CAN.send(&CAN_TxMsg);
}
void iPodOn() {
// This loop takes 50ms
CAN_TxMsg.id=0x328; // SID audio text
CAN_TxMsg.data[0]=0x42; // message 2
CAN_TxMsg.data[1]=0x96;
CAN_TxMsg.data[2]=0x02; // Row 2
CAN_TxMsg.data[3]=0x20; // _
CAN_TxMsg.data[4]=0x3C; // <
CAN_TxMsg.data[5]=0x42; // B
CAN_TxMsg.data[6]=0x6C; // l
CAN_TxMsg.data[7]=0x75; // u
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.data[0]=0x01; // message 1
CAN_TxMsg.data[3]=0x65; // e
CAN_TxMsg.data[4]=0x74; // t
CAN_TxMsg.data[5]=0x6F; // o
CAN_TxMsg.data[6]=0x6F; // o
CAN_TxMsg.data[7]=0x74; // t
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.data[0]=0x00; // message 0
CAN_TxMsg.data[3]=0x68; // h
CAN_TxMsg.data[4]=0x3E; // >
CAN_TxMsg.data[5]=0x20; //
CAN_TxMsg.data[6]=0x20; //
CAN_TxMsg.data[7]=0x20; //
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.id=0x348; // audio text control
CAN_TxMsg.data[0]=0x11; // 11
CAN_TxMsg.data[1]=0x02; // Row 2?
CAN_TxMsg.data[2]=0x05; // 05
CAN_TxMsg.data[3]=0x18; // priority 18?
CAN_TxMsg.data[4]=0x00;
CAN_TxMsg.data[5]=0x00;
CAN_TxMsg.data[6]=0x00;
CAN_TxMsg.data[7]=0x00;
CAN.send(&CAN_TxMsg);
delay(10);
/*CAN_TxMsg.id=0x368; // SID text priority
CAN_TxMsg.data[0]=0x02; // Row 2
CAN_TxMsg.data[1]=0x18; // priority 18?
CAN_TxMsg.data[2]=0x00;
CAN_TxMsg.data[3]=0x00;
CAN_TxMsg.data[4]=0x00;
CAN_TxMsg.data[5]=0x00;
CAN_TxMsg.data[6]=0x00;
CAN_TxMsg.data[7]=0x00;
CAN.send(&CAN_TxMsg);
delay(10);
*/
}
void PrintBus() {
if (CAN_RxMsg.id==0x6A2) {
//if (CAN_RxMsg.data[0]==0x80) {
Serial.print(CAN_RxMsg.id,HEX);
Serial.print(";");
for (int i = 0; i < 8; i++) {
Serial.print(CAN_RxMsg.data[i],HEX);
Serial.print(";");
}
Serial.println("");
}
}
Here's a link to my public OSHPark.com profile. You can order PCBs (in multiples of 3) for ~$30, shipped. They're excellent quality. I'll get some pictures up soon of a newly finished board.
Also, this version uses the original CD Changer harness plug so no more splicing wires!! Literally, plug-n-play.
So right now there are several options. The board & code still supports iPod steering wheel controls, but it doesn't sound like many people need/care/want that. I'm not going to remove that, but it sounds like most people just want an audio source, and a universal one at that.
I can just put a 3.5mm stereo jack in the case and you can run a long 3.5mm male to male cable from the trunk to the dash (under the door sills and such). This should work pretty well.
Or one could install a bluetooth module in the unit, much like my car does. I made sure there were 5v and GND pins available in case anyone wanted to power a bluetooth module up.
// ----------------------------------------------
// SECUDUINO
// http://secuduino.blogspot.com/
// By Igor Real
// 16/05/2011
//
// Saab CDC Changer Emulator
// http://BlueSaab.blogspot.com/
// By Seth Evans
// 29 July 2013
// ----------------------------------------------
#include <CAN.h>
int cdbutton = 0;
int toggleshuffle = 1;
int mute = 0;
int CDCcmd[] = {
0xE0,0x00,0x3F,0x31,0xFF,0xFF,0xFF,0xD0};
int ninefivecmd[] = {
0x62,0x00,0x00,0x16,0x01,0x02,0x00,0x00};
int beep[] = {
0x80,0x04,0x00,0x00,0x00,0x00,0x00,0x00};
int playipod[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x01,0xF9};
int playpauseipod[] = {
0xFF,0x55,0x03,0x02,0x00,0x01,0xFA};
int stopipod[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x02,0xF8};
int next[] = {
0xFF,0x55,0x03,0x02,0x00,0x08,0xF3};
int prev[] = {
0xFF,0x55,0x03,0x02,0x00,0x10,0xEB};
int shuffle[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x80,0x7A};
int repeat[] = {
0xFF,0x55,0x05,0x02,0x00,0x00,0x00,0x01,0xF8};
int buttonRelease[] = {
0xFF,0x55,0x03,0x02,0x00,0x00,0xFB};
void setup() {
// set up CAN
CAN.begin(47); // Saab I-Bus is 47.619kbps
Serial.begin(9600);
//cdbutton = 0;
//toggleshuffle = 1;
CAN_TxMsg.header.rtr=0; // this value never changes
CAN_TxMsg.header.length=8; // this value never changes
// not sure if this is needed; pauses program before it loops
Serial.println("9-5 Test Code 2");
delay(2000);
}
void loop() {
//cdbutton = 1;
//PrintBus();
// CDC code needs sent every second or less so all loops
// running added together need to take less than 1000ms
// but no more or the car won't "see" the CDC
CDC();
for (int i = 0; i <= 860; i++) {
if (CAN.CheckNew()) {
CAN_TxMsg.data[0]++;
CAN.ReadFromDevice(&CAN_RxMsg);
//PrintBus();
if (CAN_RxMsg.id==0x6A1) {
CAN_TxMsg.id=0x6A2; // CD Changer
for (int c = 0; c < 8; c++) {
CAN_TxMsg.data[c]=ninefivecmd[c];
}
CAN.send(&CAN_TxMsg);
}
if (CAN_RxMsg.id==0x3C0) {
if (CAN_RxMsg.data[0]==0x80) {
switch (CAN_RxMsg.data[1]) {
case 0x24:
cdbutton = 1;
for (int j = 0; j < 8; j++) {
CAN_TxMsg.id=0x430;
CAN_TxMsg.data[j]=beep[j];
}
CAN.send(&CAN_TxMsg);
for (int j = 0; j < 8; j++) {
Serial.write(byte(playipod[j]));
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 7; i++) {
Serial.write(byte(buttonRelease[i]));
}
break;
case 0x14:
cdbutton = 0;
for (int a = 0; a <=2; a++) {
for (int j = 0; j < 8; j++) {
CAN_TxMsg.id=0x430;
CAN_TxMsg.data[j]=beep[j];
}
CAN.send(&CAN_TxMsg);
}
for (int j = 0; j < 8; j++) {
Serial.write(byte(stopipod[j]));
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 7; i++) {
Serial.write(byte(buttonRelease[i]));
}
//Serial.println("Radio");
break;
}
if (cdbutton == 1) {
switch (CAN_RxMsg.data[1]) {
case 0x59: // NXT button signal
for (int j = 0; j < 7; j++) {
Serial.write(byte(playpauseipod[j]));
}
break;
case 0x76: // Long press of CD/RDM button
if (toggleshuffle > 3) {
toggleshuffle = 1;
}
switch (toggleshuffle) {
case 1:
for (int j = 0; j < 9; j++) {
Serial.write(byte(repeat[j]));
}
break;
case 2:
for (int j = 0; j < 9; j++) {
Serial.write(byte(repeat[j]));
}
break;
case 3:
for (int j = 0; j < 9; j++) {
Serial.write(byte(repeat[j]));
}
for (int j = 0; j < 8; j++) {
Serial.write(byte(shuffle[j]));
}
break;
}
toggleshuffle++;
//break;
case 0xB1: // Audio mute on?
for (int j = 0; j < 8; j++) {
Serial.write(byte(stopipod[j]));
}
break;
case 0xB0: // Audio mute off?
for (int j = 0; j < 8; j++) {
Serial.write(byte(playipod[j]));
}
break;
case 0x35: // Seek next (Seek+)?
for (int j = 0; j < 7; j++) {
Serial.write(byte(next[j]));
}
break;
case 0x36: // Seek previous (Seek-)?
for (int j = 0; j < 7; j++) {
Serial.write(byte(prev[j]));
}
break;
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 7; i++) {
Serial.write(byte(buttonRelease[i]));
}
}
}
}
if (CAN_RxMsg.id==0x290) {
if (CAN_RxMsg.data[0]==0x80) {
if (cdbutton == 1) {
switch (CAN_RxMsg.data[2]) {
//case 0x04: // NXT button on wheel
//for (int j = 0; j < 9; j++) {
//Serial.write(byte(repeat[j]));
//}
//break;
case 0x10: // Seek+ button on wheel
//Serial.println("Next");
for (int j = 0; j < 7; j++) {
Serial.write(byte(next[j]));
}
break;
case 0x08: // Seek- button on wheel
//Serial.println("Prev");
for (int k = 0; k < 7; k++) {
Serial.write(byte(prev[k]));
}
break;
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 7; i++) {
Serial.write(byte(buttonRelease[i]));
}
}
}
}
}
delay(1);
}
if (cdbutton==1) {
//Serial.println("iPod ON");
iPodOn();
}
else {
//Serial.println("iPod OFF");
//iPodOff();
//delay(400);
}
}
void CDC() {
CAN_TxMsg.id=0x3C8; // CD Changer
for (int c = 0; c < 8; c++) {
CAN_TxMsg.data[c]=CDCcmd[c];
}
CAN.send(&CAN_TxMsg);
}
void iPodOn() {
// This loop takes 50ms
CAN_TxMsg.id=0x328; // SID audio text
CAN_TxMsg.data[0]=0x42; // message 2
CAN_TxMsg.data[1]=0x96;
CAN_TxMsg.data[2]=0x02; // Row 2
CAN_TxMsg.data[3]=0x20; // _
CAN_TxMsg.data[4]=0x3C; // <
CAN_TxMsg.data[5]=0x42; // B
CAN_TxMsg.data[6]=0x6C; // l
CAN_TxMsg.data[7]=0x75; // u
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.data[0]=0x01; // message 1
CAN_TxMsg.data[3]=0x65; // e
CAN_TxMsg.data[4]=0x74; // t
CAN_TxMsg.data[5]=0x6F; // o
CAN_TxMsg.data[6]=0x6F; // o
CAN_TxMsg.data[7]=0x74; // t
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.data[0]=0x00; // message 0
CAN_TxMsg.data[3]=0x68; // h
CAN_TxMsg.data[4]=0x3E; // >
CAN_TxMsg.data[5]=0x20; //
CAN_TxMsg.data[6]=0x20; //
CAN_TxMsg.data[7]=0x20; //
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.id=0x348; // audio text control
CAN_TxMsg.data[0]=0x11; // 11
CAN_TxMsg.data[1]=0x02; // Row 2?
CAN_TxMsg.data[2]=0x05; // 05
CAN_TxMsg.data[3]=0x18; // priority 18?
CAN_TxMsg.data[4]=0x00;
CAN_TxMsg.data[5]=0x00;
CAN_TxMsg.data[6]=0x00;
CAN_TxMsg.data[7]=0x00;
CAN.send(&CAN_TxMsg);
delay(10);
/*CAN_TxMsg.id=0x368; // SID text priority
CAN_TxMsg.data[0]=0x02; // Row 2
CAN_TxMsg.data[1]=0x18; // priority 18?
CAN_TxMsg.data[2]=0x00;
CAN_TxMsg.data[3]=0x00;
CAN_TxMsg.data[4]=0x00;
CAN_TxMsg.data[5]=0x00;
CAN_TxMsg.data[6]=0x00;
CAN_TxMsg.data[7]=0x00;
CAN.send(&CAN_TxMsg);
delay(10);
*/
}
void PrintBus() {
if (CAN_RxMsg.id==0x6A2) {
//if (CAN_RxMsg.data[0]==0x80) {
Serial.print(CAN_RxMsg.id,HEX);
Serial.print(";");
for (int i = 0; i < 8; i++) {
Serial.print(CAN_RxMsg.data[i],HEX);
Serial.print(";");
}
Serial.println("");
}
}
Saturday, July 20, 2013
Populated board
Thought I would show what a fully populated board looks like when it's ready to be put into the box (minus wires).
Update to new code
I found out the other day that the newest version of code prevents Night Panel from working, or allowing you to use OpenSID.
I think the only difference is the 348 message, bit 2, being a 1 instead of a 5. I think when it's a 1, that is the highest priority, as if Night Panel were on (no gauges lit) & your coolant temp got too hot, your SID would light up & tell you. So I think it's probably better to leave this message bit higher & just deal with flashing SID txt for a few seconds.
Monday, July 15, 2013
Fabbed circuit boards!
Got my first run of fabbed circuit boards today; they look sick! I'll def be ordering more boards through OSHPark.com :)
Friday, July 12, 2013
updated code
Here's some updated code. This should fix the flickering of the SID text when switching to Aux mode. Also removed the 0x368 messages - Henrik informed me that they weren't needed. Not much else changed I don't think. This still includes the main CDC code as well as the extra code for 9-5's.
// ----------------------------------------------
// SECUDUINO
// http://secuduino.blogspot.com/
// By Igor Real
// 16/05/2011
//
// Saab CDC Changer Emulator
// http://BlueSaab.blogspot.com/
// By Seth Evans
// 12 July 2013
// ----------------------------------------------
#include <CAN.h>
int cdbutton = 0;
int toggleshuffle = 1;
int mute = 0;
int CDCcmd[] = {
0xE0,0x00,0x3F,0x31,0xFF,0xFF,0xFF,0xD0};
int ninefivecmd[] = {
0x62,0x00,0x00,0x16,0x01,0x02,0x00,0x00};
int beep[] = {
0x80,0x04,0x00,0x00,0x00,0x00,0x00,0x00};
int playipod[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x01,0xF9};
int playpauseipod[] = {
0xFF,0x55,0x03,0x02,0x00,0x01,0xFA};
int stopipod[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x02,0xF8};
int next[] = {
0xFF,0x55,0x03,0x02,0x00,0x08,0xF3};
int prev[] = {
0xFF,0x55,0x03,0x02,0x00,0x10,0xEB};
int shuffle[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x80,0x7A};
int repeat[] = {
0xFF,0x55,0x05,0x02,0x00,0x00,0x00,0x01,0xF8};
int buttonRelease[] = {
0xFF,0x55,0x03,0x02,0x00,0x00,0xFB};
void setup() {
// set up CAN
CAN.begin(47); // Saab I-Bus is 47.619kbps
Serial.begin(9600);
//cdbutton = 0;
//toggleshuffle = 1;
CAN_TxMsg.header.rtr=0; // this value never changes
CAN_TxMsg.header.length=8; // this value never changes
// not sure if this is needed; pauses program before it loops
Serial.println("9-5 Test Code");
delay(2000);
}
void loop() {
//cdbutton = 1;
//PrintBus();
// CDC code needs sent every second or less so all loops
// running added together need to take less than 1000ms
// but no more or the car won't "see" the CDC
CDC();
for (int i = 0; i <= 860; i++) {
if (CAN.CheckNew()) {
CAN_TxMsg.data[0]++;
CAN.ReadFromDevice(&CAN_RxMsg);
//PrintBus();
if (CAN_RxMsg.id==0x6A1) {
CAN_TxMsg.id=0x6A2; // CD Changer
for (int c = 0; c < 8; c++) {
CAN_TxMsg.data[c]=ninefivecmd[c];
}
CAN.send(&CAN_TxMsg);
}
if (CAN_RxMsg.id==0x3C0) {
if (CAN_RxMsg.data[0]==0x80) {
switch (CAN_RxMsg.data[1]) {
case 0x24:
cdbutton = 1;
for (int j = 0; j < 8; j++) {
Serial.write(byte(beep[j]));
}
for (int j = 0; j < 9; j++) {
Serial.write(byte(playipod[j]));
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
break;
case 0x14:
cdbutton = 0;
for (int a = 1; a <=2; a++) {
for (int j = 0; j < 8; j++) {
Serial.write(byte(beep[j]));
}
}
for (int j = 0; j < 9; j++) {
Serial.write(byte(stopipod[j]));
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
//Serial.println("Radio");
break;
}
if (cdbutton == 1) {
switch (CAN_RxMsg.data[1]) {
case 0x59: // NXT button signal
for (int j = 0; j < 10; j++) {
Serial.write(byte(playpauseipod[j]));
}
break;
case 0x76: // Long press of CD/RDM button
if (toggleshuffle > 3) {
toggleshuffle = 1;
}
switch (toggleshuffle) {
case 1:
for (int j = 0; j < 10; j++) {
Serial.write(byte(repeat[j]));
}
break;
case 2:
for (int j = 0; j < 10; j++) {
Serial.write(byte(repeat[j]));
}
break;
case 3:
for (int j = 0; j < 10; j++) {
Serial.write(byte(repeat[j]));
}
for (int j = 0; j < 9; j++) {
Serial.write(byte(shuffle[j]));
}
break;
}
toggleshuffle++;
//break;
case 0xB1: // Audio mute on?
for (int j = 0; j < 9; j++) {
Serial.write(byte(stopipod[j]));
}
break;
case 0xB0: // Audio mute off?
for (int j = 0; j < 9; j++) {
Serial.write(byte(playipod[j]));
}
break;
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
}
}
}
if (CAN_RxMsg.id==0x290) {
if (CAN_RxMsg.data[0]==0x80) {
if (cdbutton == 1) {
switch (CAN_RxMsg.data[2]) {
//case 0x04: // NXT button on wheel
//for (int j = 0; j < 10; j++) {
//Serial.write(byte(repeat[j]));
//}
//break;
case 0x10: // Seek+ button on wheel
//Serial.println("Next");
for (int j = 0; j < 8; j++) {
Serial.write(byte(next[j]));
}
break;
case 0x08: // Seek- button on wheel
//Serial.println("Prev");
for (int k = 0; k < 8; k++) {
Serial.write(byte(prev[k]));
}
break;
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
}
}
}
}
delay(1);
}
if (cdbutton==1) {
//Serial.println("iPod ON");
iPodOn();
}
else {
//Serial.println("iPod OFF");
//iPodOff();
//delay(400);
}
}
void CDC() {
CAN_TxMsg.id=0x3C8; // CD Changer
for (int c = 0; c < 8; c++) {
CAN_TxMsg.data[c]=CDCcmd[c];
}
CAN.send(&CAN_TxMsg);
}
void iPodOn() {
// This loop takes 50ms
CAN_TxMsg.id=0x328; // SID audio text
CAN_TxMsg.data[0]=0x42; // message 2
CAN_TxMsg.data[1]=0x96;
CAN_TxMsg.data[2]=0x02; // Row 2
CAN_TxMsg.data[3]=0x20; // _
CAN_TxMsg.data[4]=0x3C; // <
CAN_TxMsg.data[5]=0x42; // B
CAN_TxMsg.data[6]=0x6C; // l
CAN_TxMsg.data[7]=0x75; // u
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.data[0]=0x01; // message 1
CAN_TxMsg.data[3]=0x65; // e
CAN_TxMsg.data[4]=0x74; // t
CAN_TxMsg.data[5]=0x6F; // o
CAN_TxMsg.data[6]=0x6F; // o
CAN_TxMsg.data[7]=0x74; // t
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.data[0]=0x00; // message 0
CAN_TxMsg.data[3]=0x68; // h
CAN_TxMsg.data[4]=0x3E; // >
CAN_TxMsg.data[5]=0x20; //
CAN_TxMsg.data[6]=0x20; //
CAN_TxMsg.data[7]=0x20; //
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.id=0x348; // audio text control
CAN_TxMsg.data[0]=0x11; // 11
CAN_TxMsg.data[1]=0x02; // Row 2?
CAN_TxMsg.data[2]=0x01; // 05 01 seems to work perfect
CAN_TxMsg.data[3]=0x18; // priority 18?
CAN_TxMsg.data[4]=0x00;
CAN_TxMsg.data[5]=0x00;
CAN_TxMsg.data[6]=0x00;
CAN_TxMsg.data[7]=0x00;
CAN.send(&CAN_TxMsg);
delay(10);
/*CAN_TxMsg.id=0x368; // SID text priority
CAN_TxMsg.data[0]=0x02; // Row 2
CAN_TxMsg.data[1]=0x18; // priority 18?
CAN_TxMsg.data[2]=0x00;
CAN_TxMsg.data[3]=0x00;
CAN_TxMsg.data[4]=0x00;
CAN_TxMsg.data[5]=0x00;
CAN_TxMsg.data[6]=0x00;
CAN_TxMsg.data[7]=0x00;
CAN.send(&CAN_TxMsg);
delay(10);
*/
}
void PrintBus() {
// if (CAN_RxMsg.id==0x3b0) {
Serial.print(CAN_RxMsg.id,HEX);
Serial.print(";");
for (int i = 0; i < 8; i++) {
Serial.print(CAN_RxMsg.data[i],HEX);
Serial.print(";");
}
Serial.println("");
//}
}
// ----------------------------------------------
// SECUDUINO
// http://secuduino.blogspot.com/
// By Igor Real
// 16/05/2011
//
// Saab CDC Changer Emulator
// http://BlueSaab.blogspot.com/
// By Seth Evans
// 12 July 2013
// ----------------------------------------------
#include <CAN.h>
int cdbutton = 0;
int toggleshuffle = 1;
int mute = 0;
int CDCcmd[] = {
0xE0,0x00,0x3F,0x31,0xFF,0xFF,0xFF,0xD0};
int ninefivecmd[] = {
0x62,0x00,0x00,0x16,0x01,0x02,0x00,0x00};
int beep[] = {
0x80,0x04,0x00,0x00,0x00,0x00,0x00,0x00};
int playipod[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x01,0xF9};
int playpauseipod[] = {
0xFF,0x55,0x03,0x02,0x00,0x01,0xFA};
int stopipod[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x02,0xF8};
int next[] = {
0xFF,0x55,0x03,0x02,0x00,0x08,0xF3};
int prev[] = {
0xFF,0x55,0x03,0x02,0x00,0x10,0xEB};
int shuffle[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x80,0x7A};
int repeat[] = {
0xFF,0x55,0x05,0x02,0x00,0x00,0x00,0x01,0xF8};
int buttonRelease[] = {
0xFF,0x55,0x03,0x02,0x00,0x00,0xFB};
void setup() {
// set up CAN
CAN.begin(47); // Saab I-Bus is 47.619kbps
Serial.begin(9600);
//cdbutton = 0;
//toggleshuffle = 1;
CAN_TxMsg.header.rtr=0; // this value never changes
CAN_TxMsg.header.length=8; // this value never changes
// not sure if this is needed; pauses program before it loops
Serial.println("9-5 Test Code");
delay(2000);
}
void loop() {
//cdbutton = 1;
//PrintBus();
// CDC code needs sent every second or less so all loops
// running added together need to take less than 1000ms
// but no more or the car won't "see" the CDC
CDC();
for (int i = 0; i <= 860; i++) {
if (CAN.CheckNew()) {
CAN_TxMsg.data[0]++;
CAN.ReadFromDevice(&CAN_RxMsg);
//PrintBus();
if (CAN_RxMsg.id==0x6A1) {
CAN_TxMsg.id=0x6A2; // CD Changer
for (int c = 0; c < 8; c++) {
CAN_TxMsg.data[c]=ninefivecmd[c];
}
CAN.send(&CAN_TxMsg);
}
if (CAN_RxMsg.id==0x3C0) {
if (CAN_RxMsg.data[0]==0x80) {
switch (CAN_RxMsg.data[1]) {
case 0x24:
cdbutton = 1;
for (int j = 0; j < 8; j++) {
Serial.write(byte(beep[j]));
}
for (int j = 0; j < 9; j++) {
Serial.write(byte(playipod[j]));
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
break;
case 0x14:
cdbutton = 0;
for (int a = 1; a <=2; a++) {
for (int j = 0; j < 8; j++) {
Serial.write(byte(beep[j]));
}
}
for (int j = 0; j < 9; j++) {
Serial.write(byte(stopipod[j]));
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
//Serial.println("Radio");
break;
}
if (cdbutton == 1) {
switch (CAN_RxMsg.data[1]) {
case 0x59: // NXT button signal
for (int j = 0; j < 10; j++) {
Serial.write(byte(playpauseipod[j]));
}
break;
case 0x76: // Long press of CD/RDM button
if (toggleshuffle > 3) {
toggleshuffle = 1;
}
switch (toggleshuffle) {
case 1:
for (int j = 0; j < 10; j++) {
Serial.write(byte(repeat[j]));
}
break;
case 2:
for (int j = 0; j < 10; j++) {
Serial.write(byte(repeat[j]));
}
break;
case 3:
for (int j = 0; j < 10; j++) {
Serial.write(byte(repeat[j]));
}
for (int j = 0; j < 9; j++) {
Serial.write(byte(shuffle[j]));
}
break;
}
toggleshuffle++;
//break;
case 0xB1: // Audio mute on?
for (int j = 0; j < 9; j++) {
Serial.write(byte(stopipod[j]));
}
break;
case 0xB0: // Audio mute off?
for (int j = 0; j < 9; j++) {
Serial.write(byte(playipod[j]));
}
break;
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
}
}
}
if (CAN_RxMsg.id==0x290) {
if (CAN_RxMsg.data[0]==0x80) {
if (cdbutton == 1) {
switch (CAN_RxMsg.data[2]) {
//case 0x04: // NXT button on wheel
//for (int j = 0; j < 10; j++) {
//Serial.write(byte(repeat[j]));
//}
//break;
case 0x10: // Seek+ button on wheel
//Serial.println("Next");
for (int j = 0; j < 8; j++) {
Serial.write(byte(next[j]));
}
break;
case 0x08: // Seek- button on wheel
//Serial.println("Prev");
for (int k = 0; k < 8; k++) {
Serial.write(byte(prev[k]));
}
break;
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
}
}
}
}
delay(1);
}
if (cdbutton==1) {
//Serial.println("iPod ON");
iPodOn();
}
else {
//Serial.println("iPod OFF");
//iPodOff();
//delay(400);
}
}
void CDC() {
CAN_TxMsg.id=0x3C8; // CD Changer
for (int c = 0; c < 8; c++) {
CAN_TxMsg.data[c]=CDCcmd[c];
}
CAN.send(&CAN_TxMsg);
}
void iPodOn() {
// This loop takes 50ms
CAN_TxMsg.id=0x328; // SID audio text
CAN_TxMsg.data[0]=0x42; // message 2
CAN_TxMsg.data[1]=0x96;
CAN_TxMsg.data[2]=0x02; // Row 2
CAN_TxMsg.data[3]=0x20; // _
CAN_TxMsg.data[4]=0x3C; // <
CAN_TxMsg.data[5]=0x42; // B
CAN_TxMsg.data[6]=0x6C; // l
CAN_TxMsg.data[7]=0x75; // u
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.data[0]=0x01; // message 1
CAN_TxMsg.data[3]=0x65; // e
CAN_TxMsg.data[4]=0x74; // t
CAN_TxMsg.data[5]=0x6F; // o
CAN_TxMsg.data[6]=0x6F; // o
CAN_TxMsg.data[7]=0x74; // t
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.data[0]=0x00; // message 0
CAN_TxMsg.data[3]=0x68; // h
CAN_TxMsg.data[4]=0x3E; // >
CAN_TxMsg.data[5]=0x20; //
CAN_TxMsg.data[6]=0x20; //
CAN_TxMsg.data[7]=0x20; //
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.id=0x348; // audio text control
CAN_TxMsg.data[0]=0x11; // 11
CAN_TxMsg.data[1]=0x02; // Row 2?
CAN_TxMsg.data[2]=0x01; // 05 01 seems to work perfect
CAN_TxMsg.data[3]=0x18; // priority 18?
CAN_TxMsg.data[4]=0x00;
CAN_TxMsg.data[5]=0x00;
CAN_TxMsg.data[6]=0x00;
CAN_TxMsg.data[7]=0x00;
CAN.send(&CAN_TxMsg);
delay(10);
/*CAN_TxMsg.id=0x368; // SID text priority
CAN_TxMsg.data[0]=0x02; // Row 2
CAN_TxMsg.data[1]=0x18; // priority 18?
CAN_TxMsg.data[2]=0x00;
CAN_TxMsg.data[3]=0x00;
CAN_TxMsg.data[4]=0x00;
CAN_TxMsg.data[5]=0x00;
CAN_TxMsg.data[6]=0x00;
CAN_TxMsg.data[7]=0x00;
CAN.send(&CAN_TxMsg);
delay(10);
*/
}
void PrintBus() {
// if (CAN_RxMsg.id==0x3b0) {
Serial.print(CAN_RxMsg.id,HEX);
Serial.print(";");
for (int i = 0; i < 8; i++) {
Serial.print(CAN_RxMsg.data[i],HEX);
Serial.print(";");
}
Serial.println("");
//}
}
Wednesday, June 5, 2013
New board design
I decided to fix up the board design. I added a jumper underneath the 328P socket, but I added all the holes for the unused pins on all the DIP sockets, so no more cutting off pins! :)
REMEMBER : This view of the board is the BOTTOM, so all the components go on the other side, and that means you have to watch out for pin 1 on all the ICs! It's a little confusing, even for me. I just hold the board like it looks below and hold the IC in the air, as it were going to match the image, and then flip the two over, and it should have the proper orientation. It also helps a lot to watch for the pin 1 indicator; the indentation in the sockets.
The reason I designed the board like this is because it makes it easier for me to manufacture the boards. I mill them out, and of course the side you mill has to be "up", so this way I don't have to reverse the file when I export it out to the routing program.
Schematic file
Board file
REMEMBER : This view of the board is the BOTTOM, so all the components go on the other side, and that means you have to watch out for pin 1 on all the ICs! It's a little confusing, even for me. I just hold the board like it looks below and hold the IC in the air, as it were going to match the image, and then flip the two over, and it should have the proper orientation. It also helps a lot to watch for the pin 1 indicator; the indentation in the sockets.
The reason I designed the board like this is because it makes it easier for me to manufacture the boards. I mill them out, and of course the side you mill has to be "up", so this way I don't have to reverse the file when I export it out to the routing program.
Schematic file
Board file
Sunday, June 2, 2013
Compatibility
I think this module is compatible with the following series:
1998 - 2002 9-3
1998 - 2003 9-3 convertible
1998 - 2005 9-5
Don't hold me to those for sure, especially the 9-5 series; I'm a 9-3 guy :)
For sale?
I'm curious to see how many people would be interested in buying one of these units for $100, shipping included, and you would get to customize your SID text (12 characters max)!
I would include the Radio Shack connector, CU3242MB case, and it would pretty much be ready to go, just need installed. It's not exactly plug-n-play though; obviously you would need to cut off your CD Changer connector & replace it with the radio shack connector. Also, the way I've been doing these is putting a RJ45 female on the audio in (from ipod/mp3/whatever) and ipod control lines (5 total wires), and then making another female RJ45 to 3.5mm (or an ipod breakout connector if you want ipod control). I would leave that end up to you. This would allow you to get any old ethernet/CAT5 cable laying around and route it under your trim panels from the trunk to the front of the car. Then you can decide how/where you want your input to be at.
A LOT of this "kit" would be custom, BY YOU. I would only supply the Aux-In unit.
What do you think??
I would include the Radio Shack connector, CU3242MB case, and it would pretty much be ready to go, just need installed. It's not exactly plug-n-play though; obviously you would need to cut off your CD Changer connector & replace it with the radio shack connector. Also, the way I've been doing these is putting a RJ45 female on the audio in (from ipod/mp3/whatever) and ipod control lines (5 total wires), and then making another female RJ45 to 3.5mm (or an ipod breakout connector if you want ipod control). I would leave that end up to you. This would allow you to get any old ethernet/CAT5 cable laying around and route it under your trim panels from the trunk to the front of the car. Then you can decide how/where you want your input to be at.
A LOT of this "kit" would be custom, BY YOU. I would only supply the Aux-In unit.
What do you think??
Saturday, June 1, 2013
Saab 9-5 working!

I installed a 2nd unit into my friend's dad's 9-5 today. Had to adjust the code slightly, but not much. Just the CD changer code. Apparently the 9-5 sends a code to the CD changer, and the CD changer has to respond with a code. Not like how the 9-3 works. But it was a simple software change and we got it working! Code is below. I'm sure it could all be contained into one program, but I haven't tested it so I don't wanna post it and it not work.
The 9-5 apparently sends a 6A1 command to the CD changer, and the CD changer has to respond with a 6A2 command that says "I'm here, I'm ok!". In the code below, this command is the "ninefivecmd" array of hex codes :) I found this information Here
Also, I wanted to add that I bought these connectors at Radio Shack for $3/ea and they worked great! 9-Position Male Polarized Connector, PN 274-229 and 9-Position Female Polarized Connector PN 274-239 You have to crimp the pins with a special tool; in my case it's called a Letherman SuperTool 300 ;)

// ----------------------------------------------
// SECUDUINO
// http://secuduino.blogspot.com/
// By Igor Real
// 16/05/2011
//
// Saab CDC Changer Emulator
// http://BlueSaab.blogspot.com/
// By Seth Evans
// 1 June 2013
// ----------------------------------------------
#include <CAN.h>
int cdbutton = 0;
int toggleshuffle = 1;
int mute = 0;
int CDCcmd[] = {
0xE0,0x00,0x3F,0x31,0xFF,0xFF,0xFF,0xD0};
int ninefivecmd[] = {
0x62,0x00,0x00,0x16,0x01,0x02,0x00,0x00};
int beep[] = {
0x80,0x04,0x00,0x00,0x00,0x00,0x00,0x00};
int playipod[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x01,0xF9};
int playpauseipod[] = {
0xFF,0x55,0x03,0x02,0x00,0x01,0xFA};
int stopipod[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x02,0xF8};
int next[] = {
0xFF,0x55,0x03,0x02,0x00,0x08,0xF3};
int prev[] = {
0xFF,0x55,0x03,0x02,0x00,0x10,0xEB};
int shuffle[] = {
0xFF,0x55,0x04,0x02,0x00,0x00,0x80,0x7A};
int repeat[] = {
0xFF,0x55,0x05,0x02,0x00,0x00,0x00,0x01,0xF8};
int buttonRelease[] = {
0xFF,0x55,0x03,0x02,0x00,0x00,0xFB};
void setup() {
// set up CAN
CAN.begin(47); // Saab I-Bus is 47.619kbps
Serial.begin(9600);
//cdbutton = 0;
//toggleshuffle = 1;
CAN_TxMsg.header.rtr=0; // this value never changes
CAN_TxMsg.header.length=8; // this value never changes
// not sure if this is needed; pauses program before it loops
delay(2000);
}
void loop() {
//cdbutton = 1;
//PrintBus();
// CDC code needs sent every second or less so all loops
// running added together need to take less than 1000ms
// but no more or the car won't "see" the CDC
CDC();
for (int i = 0; i <= 800; i++) {
if (CAN.CheckNew()) {
CAN_TxMsg.data[0]++;
CAN.ReadFromDevice(&CAN_RxMsg);
//PrintBus();
if (CAN_RxMsg.id==0x6A1) {
CAN_TxMsg.id=0x6A2; // CD Changer
for (int c = 0; c < 8; c++) {
CAN_TxMsg.data[c]=ninefivecmd[c];
}
CAN.send(&CAN_TxMsg);
}
if (CAN_RxMsg.id==0x3C0) {
if (CAN_RxMsg.data[0]==0x80) {
switch (CAN_RxMsg.data[1]) {
case 0x24:
cdbutton = 1;
for (int j = 0; j < 8; j++) {
Serial.write(byte(beep[j]));
}
for (int j = 0; j < 9; j++) {
Serial.write(byte(playipod[j]));
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
break;
case 0x14:
cdbutton = 0;
for (int a = 1; a <=2; a++) {
for (int j = 0; j < 8; j++) {
Serial.write(byte(beep[j]));
}
}
for (int j = 0; j < 9; j++) {
Serial.write(byte(stopipod[j]));
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
//Serial.println("Radio");
break;
}
if (cdbutton == 1) {
switch (CAN_RxMsg.data[1]) {
case 0x59: // NXT button signal
for (int j = 0; j < 10; j++) {
Serial.write(byte(playpauseipod[j]));
}
break;
case 0x76: // Long press of CD/RDM button
if (toggleshuffle > 3) {
toggleshuffle = 1;
}
switch (toggleshuffle) {
case 1:
for (int j = 0; j < 10; j++) {
Serial.write(byte(repeat[j]));
}
break;
case 2:
for (int j = 0; j < 10; j++) {
Serial.write(byte(repeat[j]));
}
break;
case 3:
for (int j = 0; j < 10; j++) {
Serial.write(byte(repeat[j]));
}
for (int j = 0; j < 9; j++) {
Serial.write(byte(shuffle[j]));
}
break;
}
toggleshuffle++;
//break;
case 0xB1: // Audio mute on?
for (int j = 0; j < 9; j++) {
Serial.write(byte(stopipod[j]));
}
break;
case 0xB0: // Audio mute off?
for (int j = 0; j < 9; j++) {
Serial.write(byte(playipod[j]));
}
break;
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
}
}
}
if (CAN_RxMsg.id==0x290) {
if (CAN_RxMsg.data[0]==0x80) {
if (cdbutton == 1) {
switch (CAN_RxMsg.data[2]) {
//case 0x04: // NXT button on wheel
//for (int j = 0; j < 10; j++) {
//Serial.write(byte(repeat[j]));
//}
//break;
case 0x10: // Seek+ button on wheel
//Serial.println("Next");
for (int j = 0; j < 8; j++) {
Serial.write(byte(next[j]));
}
break;
case 0x08: // Seek- button on wheel
//Serial.println("Prev");
for (int k = 0; k < 8; k++) {
Serial.write(byte(prev[k]));
}
break;
}
delay(3);
//Serial.println("Release");
for (int i = 0; i < 8; i++) {
Serial.write(byte(buttonRelease[i]));
}
}
}
}
}
delay(1);
}
if (cdbutton==1) {
//Serial.println("iPod ON");
iPodOn();
}
else {
//Serial.println("iPod OFF");
//iPodOff();
//delay(400);
}
}
void CDC() {
CAN_TxMsg.id=0x3C8; // CD Changer
for (int c = 0; c < 8; c++) {
CAN_TxMsg.data[c]=CDCcmd[c];
}
CAN.send(&CAN_TxMsg);
}
void iPodOn() {
// This loop takes 50ms
CAN_TxMsg.id=0x328; // SID audio text
CAN_TxMsg.data[0]=0x42; // message 2
CAN_TxMsg.data[1]=0x96;
CAN_TxMsg.data[2]=0x02; // Row 2
CAN_TxMsg.data[3]=0x20; // _
CAN_TxMsg.data[4]=0x69; // i
CAN_TxMsg.data[5]=0x53; // S
CAN_TxMsg.data[6]=0x61; // a
CAN_TxMsg.data[7]=0x61; // a
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.data[0]=0x01; // message 1
CAN_TxMsg.data[3]=0x62; // b
CAN_TxMsg.data[4]=0x20; // _
CAN_TxMsg.data[5]=0x41; // A
CAN_TxMsg.data[6]=0x75; // u
CAN_TxMsg.data[7]=0x78; // x
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.data[0]=0x00; // message 0
CAN_TxMsg.data[3]=0x20; // _
CAN_TxMsg.data[4]=0x20; // _
CAN_TxMsg.data[5]=0x20; //
CAN_TxMsg.data[6]=0x20; //
CAN_TxMsg.data[7]=0x20; //
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.id=0x348; // audio text control
CAN_TxMsg.data[0]=0x11;
CAN_TxMsg.data[1]=0x02; // Row 2
CAN_TxMsg.data[2]=0x05;
CAN_TxMsg.data[3]=0x18; // priority 18?
CAN_TxMsg.data[4]=0x00;
CAN_TxMsg.data[5]=0x00;
CAN_TxMsg.data[6]=0x00;
CAN_TxMsg.data[7]=0x00;
CAN.send(&CAN_TxMsg);
delay(10);
CAN_TxMsg.id=0x368; // SID text priority
CAN_TxMsg.data[0]=0x02; // Row 2
CAN_TxMsg.data[1]=0x18; // priority 18?
CAN_TxMsg.data[2]=0x00;
CAN_TxMsg.data[3]=0x00;
CAN_TxMsg.data[4]=0x00;
CAN_TxMsg.data[5]=0x00;
CAN_TxMsg.data[6]=0x00;
CAN_TxMsg.data[7]=0x00;
CAN.send(&CAN_TxMsg);
delay(10);
}
void PrintBus() {
// if (CAN_RxMsg.id==0x3b0) {
Serial.print(CAN_RxMsg.id,HEX);
Serial.print(";");
for (int i = 0; i < 8; i++) {
Serial.print(CAN_RxMsg.data[i],HEX);
Serial.print(";");
}
Serial.println("");
//}
}
Friday, May 17, 2013
Better parts list from Digikey (minus the LEDs)
Index | Quantity | Part Number | Description | Customer Reference | Unit Price | Extended Price |
1 | 1 | ATMEGA328P-PU-ND | IC MCU 8BIT 32KB FLASH 28DIP | IC3 | 3.16 | 3.16 |
2 | 1 | MCP2515-I/P-ND | IC CAN CONTROLLER W/SPI 18DIP | IC2 | 2.18 | 2.18 |
3 | 1 | 296-27968-5-ND | IC CAN TRANSCEIVER 8-DIP | IC1 | 3.02 | 3.02 |
4 | 2 | DRV134PA-ND | IC AUDIO DIFF LINE DRIVER 8-DIP | U1,U2 | 5.64 | 11.28 |
5 | 1 | LTC1144CN8#PBF-ND | IC REG SWITCHED CAP INV 8DIP | N1 | 4.92 | 4.92 |
6 | 2 | X908-ND | CER RESONATOR 16.00MHZ | U3, U5 | 0.7 | 1.4 |
7 | 3 | 330QBK-ND | RES 330 OHM 1/4W 5% CARBON FILM | R1, R3, R5 | 0.1 | 0.3 |
8 | 3 | 10KQBK-ND | RES 10K OHM 1/4W 5% CARBON FILM | R2, R4, R6 | 0.1 | 0.3 |
9 | 1 | 1N4007FSCT-ND | DIODE GEN PURPOSE 1000V 1A DO41 | D1 | 0.14 | 0.14 |
10 | 1 | 497-1443-5-ND | IC REG LDO 5V 1.5A TO220AB | IC4 | 0.55 | 0.55 |
11 | 1 | 399-4309-ND | CAP CER 0.47UF 50V 20% RADIAL | C1 | 0.49 | 0.49 |
12 | 6 | 399-4264-ND | CAP CER 0.1UF 50V 10% RADIAL | C2, C6, C7, C8, C17, C18 | 0.32 | 1.92 |
13 | 4 | P15155-ND | CAP ALUM 1.0UF 50V 20% RADIAL | C9, C10, C19, C20 | 0.46 | 1.84 |
14 | 4 | 399-3563-ND | CAP TANT 10UF 16V 10% RADIAL | C11, C12, C13, C14 | 1.3 | 5.2 |
15 | 2 | 493-3286-ND | CAP ALUM 10UF 50V 20% RADIAL | C17, C18 | 0.55 | 1.1 |
16 | 1 | A100210-ND | CONN IC SOCKET VERT 28POS TIN | IC3 SOCKET | 0.44 | 0.44 |
17 | 1 | A100207-ND | CONN IC SOCKET VERT 18POS TIN | IC2 SOCKET | 0.28 | 0.28 |
18 | 4 | A100204-ND | CONN IC SOCKET VERT 8POS TIN | IC1, N1, U1, U2 SOCKET | 0.19 | 0.76 |
Subtotal | 39.28 |
Wednesday, April 3, 2013
Logitech Bluetooth adapter added!
I was able to purchase the Logitech Bluetooth speaker adapter on Amazon through the goldbox deal; got it for $26 shipped! Tested it out, and it has great sound. I guess you get what you pay for...those chinese bluetooth streaming adapters are garbage.
I gutted the logitech and removed the 3 plugs off the motherboard (power, dual RCA, and 3.5mm). I then wired the 5v regulator from the BlueSaab board to the logitech for power, a ground wire, and then I spliced into the audio in wiring, keeping the BlueSaab board constantly connected to iPod input, but now there's a connector that attaches the logitech inputs. So basically I can disconnect the logitech board and it won't have any affect on the current capabilities/connections of the BlueSaab module.
This new board fits into the box I'm using; it's almost too perfect :)
The logitech has a button on it to initialize sync mode; So basically it works like this: if you have never connected a device to the logitech before, you HAVE to press this button to put it in sync mode. After you've synced a device to it, you never have to press that button again to connect the same device to it. If you want to connect a new device to the logitech, you'll have to pop the cover off and hit this sync button. I don't think I'll be syncing that many devices to the logitech, so I opted not to put a hole/button in the case housing just for this feature.
I gutted the logitech and removed the 3 plugs off the motherboard (power, dual RCA, and 3.5mm). I then wired the 5v regulator from the BlueSaab board to the logitech for power, a ground wire, and then I spliced into the audio in wiring, keeping the BlueSaab board constantly connected to iPod input, but now there's a connector that attaches the logitech inputs. So basically I can disconnect the logitech board and it won't have any affect on the current capabilities/connections of the BlueSaab module.
This new board fits into the box I'm using; it's almost too perfect :)
The logitech has a button on it to initialize sync mode; So basically it works like this: if you have never connected a device to the logitech before, you HAVE to press this button to put it in sync mode. After you've synced a device to it, you never have to press that button again to connect the same device to it. If you want to connect a new device to the logitech, you'll have to pop the cover off and hit this sync button. I don't think I'll be syncing that many devices to the logitech, so I opted not to put a hole/button in the case housing just for this feature.
Friday, March 29, 2013
Peddling...
yeah, so if you feel compelled to send any moolah my way for this site's info, I'd appreciate it...and if not, that's cool too :-)
Tuesday, February 26, 2013
Parts list & notes
Some notes on the circuit board...In order to make the circuit board one layer (plus the one jumper), I removed any unused pins on the ICs...but I removed these pins on the SOCKETS, not the ICs. This makes removing/reinstalling ICs easy without having to modify them. Just pay attention to orientation :)
Also, if you don't want to pay for the DRV134PA drivers, you can actually request a sample of 1-3 of them from Texas Instruments for free! :D
Also, if you don't want to pay for the DRV134PA drivers, you can actually request a sample of 1-3 of them from Texas Instruments for free! :D
Partlist | ||||||||||
Exported from Seth Saab Interface PTH CU3242.brd at 2/26/2013 9:13:58 AM | ||||||||||
EAGLE Version 6.4.0 Copyright (c) 1988-2013 CadSoft | ||||||||||
Assembly variant: | ||||||||||
Part | Value | Package | Library | Position | (mm) | Orientation | ||||
C1 | 470nF | C025-025X050 | rcl | (49.25 | 19.25) | R0 | ||||
C2 | .1uF | C025-025X050 | rcl | (50.5 | 12) | R90 | ||||
C6 | 0.1uF | C025-025X050 | rcl | (72.665 | 17.455) | MR270 | ||||
C7 | 100nF | C025-025X050 | rcl | (28.6 | 10.5) | MR270 | ||||
C8 | 100nF | C025-025X050 | rcl | (31.95 | 16.4) | MR270 | ||||
C9 | 1uF | E2,5-5 | resistor | (43.44 | 17.98) | MR0 | ||||
C10 | 1uF | E2,5-5 | resistor | (29.9 | 22.4) | MR0 | ||||
C11 | 10uF | C025-030X050 | rcl | (9.985 | 35.045) | MR180 | ||||
C12 | 10uF | C025-030X050 | rcl | (10.015 | 49.675) | MR0 | ||||
C13 | 10uF | C025-030X050 | rcl | (9.82 | 15.045) | MR180 | ||||
C14 | 10uF | C025-030X050 | rcl | (9.93 | 30.175) | MR0 | ||||
C15 | 10uF | E2,5-5 | resistor | (26 | 47.875) | MR180 | ||||
C16 | 10uF | E2,5-5 | resistor | (29.875 | 28.75) | MR0 | ||||
C17 | 100nF | C025-025X050 | rcl | (31.95 | 10.5) | MR270 | ||||
C18 | 100nF | C025-025X050 | rcl | (28.6 | 16.4) | MR270 | ||||
C19 | 1uF | E2,5-5 | resistor | (43.44 | 25.265) | MR0 | ||||
C20 | 1uF | E2,5-5 | resistor | (33.645 | 34.405) | MR0 | ||||
CANBUS | 1X02 | pinhead | (25.395 | 56.215) | MR180 | |||||
D1 | 1N4007-01 | D01B | diodes | (54 | 19.125) | R0 | ||||
FTDI | 22-27-2061-06 | 6410-06 | con-molex | (60.775 | 13.245) | MR0 | ||||
GND | 1X01 | pinhead | (13.765 | 55.755) | MR0 | |||||
IC1 | SN65HVD251P | DIL08 | ti-can-seth | (25.255 | 64.585) | MR180 | ||||
IC2 | MCP2515-E/P | DIL18 | mcp2515-seth | (47.58 | 61.465) | MR180 | ||||
IC3 | MEGA8-P | DIL28-3-SETH | atmel-seth | (56.485 | 40.15) | MR0 | ||||
IC4 | 7805 | 78XXS | v-reg | (53.965 | 22.605) | MR180 | ||||
LED1 | LED5MM | led | (70.75 | 50) | MR0 | |||||
LED2 | LED5MM | led | (70.75 | 58) | MR0 | |||||
LED3 | LED5MM | led | (61.25 | 30.25) | R180 | |||||
L_IN | 1X01 | pinhead | (16.515 | 49.815) | MR0 | |||||
L_OUT | 1X02 | pinhead | (4.8 | 42.045) | MR90 | |||||
N1 | LTC1144 | DIP08L-SETH | ic-seth | (27.35 | 39.365) | MR180 | ||||
PWR_IN | 1X02 | pinhead | (43.305 | 12.71) | MR0 | |||||
R1 | 330R | 0207/10 | rcl | (60.25 | 50) | MR0 | ||||
R2 | 10K | 0207/10 | rcl | (67.665 | 24.895) | MR180 | ||||
R3 | 330R | 0207/10 | rcl | (63 | 53.5) | MR0 | ||||
R4 | 10K | 0207/2V | rcl | (38.5 | 53.5) | R180 | ||||
R5 | 10K | 0204/7 | rcl | (18.125 | 64.625) | R90 | ||||
R6 | 330R | 0207/2V | rcl | (55.25 | 30.24) | R180 | ||||
RX | 1X01 | pinhead | (62 | 18.75) | MR0 | |||||
R_IN | 1X01 | pinhead | (16.45 | 31.315) | MR0 | |||||
R_OUT | 1X02 | pinhead | (4.88 | 22.705) | MR90 | |||||
TX | 1X01 | pinhead | (64.625 | 18.75) | R0 | |||||
U$1 | DRV134PA | DIL08 | BurrBrownAudioParts | (12.555 | 42.19) | MR180 | ||||
U$2 | DRV134PA | DIL08 | BurrBrownAudioParts | (12.47 | 22.69) | MR180 | ||||
U$3 | RESONATORPTH | RESONATOR-PTH | SparkFun-3-2-07 | (47.25 | 31.875) | MR0 | ||||
U$5 | RESONATORPTH | RESONATOR-PTH | SparkFun-3-2-07 | (52.75 | 70.25) | MR180 |
Tuesday, February 19, 2013
Wiring
I kinda forgot to update on my wiring...
This first diagram is how I have the connector wired where the original CD changer connector used to be. I have an 8-pin molex connector here now, just extra I had laying around. I think this connector is actually too small for the wiring in the car, but it's working so far. I would probably suggest a larger connector, with larger pins to accomodate the wire size better.
I decided to use an ethernet cable to make all the connections modular. One end of the ethernet cable goes to the front of the car, the other to the trunk. I cut off one end of the ethernet cable to make routing it easier, and then I crimped on a 5-pin Molex connector like the 8-pin above. I have an RJ45 receptacle that's wired to my iPod dock connector, which of course plugs into my iPod/iPhone.
I used the schematics here to determine what pins I needed off the iPod.
Inside the iPod connector, I put a 500K ohm resistor from 21 to ground to allow the iPod to accept serial communication so we can control the iPod, and I *THINK* I put a 10K ohm resistor from 5V in to both 25 and 27 (USB D+ and D-); this should put 2V on those pins, making the iPod draw 500mA to charge. Notice there is a switch inline with the power adapter, so I can turn off the charger at will (there's engine noise when the charger is on).
Also, I *MIGHT* have the iPod TX/RX lines swapped...I've gotten so confused with all the revisions of this damn thing that I think I might have them swapped. Not a big deal, it's easy to change them.
This schematic is a basic overview of the wiring involved from the iSaabAux board to the car and to the iPod. Not shown is the DB25 connectors I used to go from inside the case to the outside. You can use whatever you want of course, so that's not mandatory.
Monday, February 18, 2013
Newest hardware
Here are some pictures of my latest version of the iSaabAux input. I'm going to get an old female DB25 molded plug & replace this one without a housing, but this one works for now.
I cut a hole in the side of this enclosure for the 25 pin connector; it seemed like the best way to get all 18 wires outside the box.
Thursday, February 14, 2013
Here are the schematic & board files (EagleCad) so you can make your own iSaabAux board.
Schematic
Board file
I'm going to use this enclosure, a Bud Industries CU-3242-MB.
Schematic
Board file
I'm going to use this enclosure, a Bud Industries CU-3242-MB.
Subscribe to:
Posts (Atom)