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! :) 


This module is missing the Bluetooth chip


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!

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.

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


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...



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.

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("");
  }
}

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("");
  //}
}

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



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??

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.

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

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.