rockstar_h

Rockstar Hacking

Rocksmith is music games that allow you to use real guitar to playing with. This is the fun ways to learn guitar by yourself. But sadly the game need special USB cable to connect your real guitar to the game. So, I decided to make it myself.

Our blog are bilingual you can choose language you want from the flag at the left menu.

Normally the cable bundle with the game when you buy the box. But some people (like me) may bought the digital copy online without cable include. Now you have only 2 choice. That is try to order the real cable or crack your game to bypass/allow using other USB interface. So, I decided to make another 3rd choice. The makers ways.

**WARNING** Whatever you trying to do from this blog. Do it as you own risk :-P

After digging down into the research. I found that the Rocksmith real tone cable is just a USB sound interface class 1. The hardware produced by Hercules. It embed with some special Vender ID and Hardware ID for game purpose. When cable connected the game will check those ID to verify that which is genuine one.

IMG_0002
Original USB cable: Rocksmith Real Tone Cable.

Many numbers of USB sound interface are on the market. But which one can be modify to fit our purpose?
In Thailand we have many model that imported from china. Many difference looking of it but inside are the same base system. I’m found 2 major of system.
The first one are base on mystery chip under black epoxy. This one is hard to modify. All the I/O was blocked under the blob. We’ll skip this one.The other one is more hacker friendly. CM108 the USB sound interface IC in LQFP-48 package. It’s dirt cheap and good enough for a game interface.

IMG_0004
Cheap CM108 base USB sound interface.

From datasheet. CM108 is USB Audio I/O Controller. From C-Media electronic inc. Suitable for headset or multi-media devices. CM108 are abit popular among with Maker/Hacker. Many people modify CM108 base hardware for their projects like ‘DIY ADC for ham radio’, ‘DIY Sound frequency range oscilloscope’ or even hack into the hardware to get uncompressed audio from it.
The chips are made ready to be mass product OEM by support external EEPROM for customize USB description (like Device name, Vender ID, etc..) We’ll use this feature to mimic this USB audio to be a Rocksmith real tone cable.

IMG_0006
Wiring schematics for writing data to EEPROM.

EEPROM We use is 39C46 connect to CM108 by TWI(Three Wire Interface). We need to prepare and write data to EEPROM before hookup into target hardware. Arduino use as a tools for writing data to EEPROM. We can use I2C/TWI on Arduino or software TWI library for this task. The data mode that CM108 required for interfacing is 2 byte width or 16 bit word. So Don’t forget to setup the EEPROM for this (I’m using AT39C46 that need to set pin6 [ORG] to Vcc. This make AT39C46 working in 16bit mode) Then connect EEPROM to Arduino as picture below.

IMG_0007
Writing USB description data to EEPROM.

I wrote a simple code (Arduino sketch) for this task. By using software TWI you can change the pin for I/O as you want. Program will use data that embed in sourcecode write into EEPROM. After that it’ll read data out of EEPROM once to verify with original one in source. So, If you get verification failed. Just redo this process from start again.

#define PIN_SK 52 //SCK - Digital 52
#define PIN_DO 50 //MISO - Digital 50
#define PIN_DI 51 //MOSI - Digital 51
#define PIN_CS 53 //SS - Digital 53

#define BIT_LENGTH 16

//#define _DEBUG_MODE_
#ifdef _DEBUG_MODE_
#define DEBUG_LOG(x) Serial.print(x)
#else
#define DEBUG_LOG(x)
#endif

union DATA{
  uint16_t  W; 
  uint8_t   B[2];
};                                                                                                                                   
uint8_t DESC_DATA[] = { 0x05,0x67,0xBA,0x12,0xFF,0x00,0xFF,0xFF,\
                        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
                        0xFF,0xFF,0xFF,0xFF,0x18,0x00,0x52,0x6F,\
                        0x63,0x6B,0x73,0x6D,0x69,0x74,0x68,0x20,\
                        0x47,0x75,0x69,0x74,0x61,0x72,0x20,0x41,\
                        0x64,0x61,0x70,0x74,0x65,0x72,0x00,0xFF,\
                        0xFF,0xFF,0xFF,0xFF,0x07,0x00,0x55,0x42,\
                        0x49,0x53,0x4F,0x46,0x54,0x00,0xFF,0xFF,\
                        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
                        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
                        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
uint8_t DESC_COUNT = 88;

void mwiOut(uint16_t value,uint8_t bitOrder,uint8_t bitAmount)
{
  uint8_t dataPin = PIN_DI;
  uint8_t clockPin = PIN_SK;
  uint8_t x = (bitAmount>BIT_LENGTH)?BIT_LENGTH:bitAmount;
  uint8_t i;
  uint8_t dataBit = 0;

  DEBUG_LOG("W[");
  for (i = 0; i < x; i++)
  {
    if (bitOrder == LSBFIRST)
    {
      dataBit = (1 & ( value >> i));
    }
    else	
    {
      dataBit = (1 & ( value >> ((BIT_LENGTH-1)-i)));
    }
    digitalWrite(dataPin,dataBit);
    DEBUG_LOG(dataBit);
    digitalWrite(clockPin, HIGH);
    digitalWrite(clockPin, LOW);	
  }
  DEBUG_LOG("]");
}

uint16_t mwiIn(uint8_t bitOrder,uint8_t bitAmount)
{
  uint16_t value = 0;
  uint8_t dataPin = PIN_DO;
  uint8_t clockPin = PIN_SK;
  uint8_t i;
  uint8_t x = (bitAmount>BIT_LENGTH)?BIT_LENGTH:bitAmount;

  DEBUG_LOG("R[");
  for (i = 0; i < x; ++i) {
    digitalWrite(clockPin, HIGH);
    digitalWrite(clockPin, LOW);
    DEBUG_LOG(digitalRead(dataPin));
    if (bitOrder == LSBFIRST)
      value |= digitalRead(dataPin) << i;
    else
      value |= digitalRead(dataPin) << ((BIT_LENGTH-1) - i);
  }
  DEBUG_LOG("]");
  return value;
}

void waitReady(void)
{
  // Wait ready operation
  EEPROM_ENABLE(true);
  bool bReady = false;
  do
  {
    bReady = (digitalRead(PIN_DO)==HIGH);
    digitalWrite(PIN_SK, HIGH);
    digitalWrite(PIN_SK, LOW);
    Serial.print(".");
  }while(!bReady);
  Serial.println("DONE!");
  EEPROM_ENABLE(false);
}

void EEPROM_ENABLE(bool value)
{
  if(value)
  {
    digitalWrite(PIN_CS, HIGH);
    digitalWrite(PIN_SK, LOW);
    digitalWrite(PIN_DI, LOW);
  }
  else
  {
    digitalWrite(PIN_CS, LOW);
    digitalWrite(PIN_SK, LOW);
    digitalWrite(PIN_DI, LOW);
  }
}

void EEPROM_EWEN()
{
  uint16_t cmd = 0b1001100000000000;

  EEPROM_ENABLE(true);
  mwiOut(cmd,MSBFIRST,9);
  EEPROM_ENABLE(false);
}

void EEPROM_EWDS()
{
  uint16_t cmd = 0b1000000000000000;

  EEPROM_ENABLE(true);
  mwiOut(cmd,MSBFIRST,9);
  EEPROM_ENABLE(false);
}

uint16_t EEPROM_READ(uint16_t address)
{
  uint16_t value = 0;
  uint16_t cmd = 0b1100000000000000;
  uint16_t add = address << 10;

  EEPROM_ENABLE(true);
  mwiOut(cmd,MSBFIRST,3);
  mwiOut(add,MSBFIRST,6);
  value = mwiIn(MSBFIRST,16);
  EEPROM_ENABLE(false);
  return value;
}

void EEPROM_WRITE(uint16_t address,uint16_t data)
{
  uint16_t cmd = 0b1010000000000000;
  uint16_t add = address << 10;

  // Write operation
  EEPROM_ENABLE(true);
  mwiOut(cmd,MSBFIRST,3);
  mwiOut(add,MSBFIRST,6);
  mwiOut(data,MSBFIRST,16);
  EEPROM_ENABLE(false);
  waitReady();
}

void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);
  Serial.println("ROCKSMITH EEPROM WRITER (AT93C46)");

  // setup software 3-Wire interface
  pinMode(PIN_SK, OUTPUT);
  pinMode(PIN_CS, OUTPUT);
  pinMode(PIN_DI, OUTPUT);
  pinMode(PIN_DO, INPUT);
  EEPROM_ENABLE(false);
}

void loop()
{
  Serial.print("EEPROM_ENABLE(TRUE):");
  EEPROM_ENABLE(true);
  Serial.println(" DONE!");
  Serial.print("EEPROM_EWEN:");
  EEPROM_EWEN();
  Serial.println(" DONE!");
  for(int i=0;i<=DESC_COUNT;i+=2)
  {
    Serial.print("EEPROM_WRITE(");
    Serial.print(i);
    Serial.print("/");
    Serial.print(DESC_COUNT);
    Serial.print(")");
    EEPROM_WRITE((i>>1),((DESC_DATA[i+1]<<8)|(DESC_DATA[i])));
  }
  Serial.print("EEPROM_EWDS:");
  EEPROM_EWDS();
  Serial.println(" DONE!");

  Serial.println();
  Serial.println("VERIFY EEPROM");
  DATA temp;
  bool error = false;
  for(uint16_t i=0;i<=44;i++)
  {
    temp.W = EEPROM_READ(i);
    Serial.print("EEPROM_READ(0x");
    Serial.print(i,HEX);
    Serial.print("):0x");
    Serial.print(temp.W,HEX);

    if((temp.B[0]==DESC_DATA[(i<<1)])&&(temp.B[1]==DESC_DATA[(i<<1)+1]))
    {
      Serial.println(" PASSED!");
    }
    else
    {
      Serial.println(" FAILED!");
      error = true;
    }
  }

  if(error)
    Serial.println("DATA ERROR. PROGRAM TERMINATED!");
  else
    Serial.println("ALL PROCESS DONE!");

  delay(1000);
  exit(0);
}

After we made EEPROM ready with data. I’ll hook it to the target hardware by wiring directly to CM108 I/O pin. Becareful CM108 are LQFP-48 package with 0.5mm pitch between pin. you need fine hands to done this step. For wiring I use 0.7mm pitch IDE-HDD pair-wired. If you have a better choice just do it. Connect EEPROM into target hardware as schematic below.

IMG_0008
Schematics for install EEPROM on-board.

My trick for this is. Don’t forget to clean I/O pin and copper wire. Remove most of oxide as you can do. Then apply a light layer of tin to the I/O pin by soldering iron. (You can use flux if you want) Make sure you don’t apply too much tin and heat on I/O pin this can harm you target hardware. Then apply thin to end of wire. Clean the tip of soldering iron. Put the wire with thin on top of I/O pin (you can use some of tape to hold it in place) Then apply some flux into it and gently apply heat from soldering iron. Make sure all I/O pin are connected to wire.
Don’t forget to use multimeter to check the connection. Because this connection are very wake. Find you way to hold the connection rigidly if you don’t want to get headache from fixing it.

IMG_0010
Don’t forget to checking the connection.

So, We got it. At this point we’ll checking the hardware by connect it into PC. Check that all basic audio functions still working perfectly. Then check the Hardware ID and Vender ID in device manager that changing to something we want as picture below. Then I just replaced mic-in female jack with 1/4 female jack for guitar in put. So, you can connect directly from guitar to this jack. Or put some pre-amp in between for better input level.

IMG_0011
Hardware IDs changed after hacked.

Let’s start running the game and bang! It’s worked! The game detected our hardware as a genuine one. The sound quality and time delay is good enough for the game. I got some low input level problem but it’s not a big deal. We can prevent it by connect pre-amp in between or turn on ‘Automatic Gain’ in host OS.

In-Game tuning test
In-Game tuning test. Working good!

Hooray~! I’m very happy with this. Everything working fine! Myself also got many ‘things’ from this project. Not just fun but also knowledge. However, I’m just trying my cable only on Windows PC and not try on other platform like XBOX or PlayStation yet because I don’t have them. But if you wanna try. Do it as your own risk!

For now on I need to decided that what I wanna do next between make things or make music :-)

PS. I’m also have a facebook pages. If you want real fast update from me. Just like it :-)
https://www.facebook.com/thegearwalker