Translator needed: C++ I2c protocol to arduino

Hi,
Ive been having a lot of trouble getting a wireless wii nunchuk connected to my diecimila. The wireless 'chuck use a different initiation routine than the wired ones and it varies between the multiple 3rd party brands. Member ILAN has gotten my brand of wireless nunchuk ( Nyko Kana) to work reliably, but he is using an AVR ATTINY 461.
He was kind enough to post his initiation routine but I am having no luck trying to alter the existing wireless sketch to follow his. Here is the original wireless sketch written for a blazepro nunchuk:

Code:
// read out a Wii Nunchuck controller
// adapted to work with wireless Nunchuck controllers of third party vendors by Michael Dreher <michael@5dot1.de>

// adapt to your hardware config
#define POWER_VIA_PORT_C2_C3 1    // use port pins port C2 and C3 as power supply of the Nunchuck (direct plug using wiichuck adapter)
#define DEBUG_RCV_TEL 1

#define USE_NEW_WAY_INIT 1        // use "The New Way" of initialization <http://wiibrew.org/wiki/Wiimote#The_New_Way>
#define WII_IDENT_LEN ((byte)6)
#define WII_TELEGRAM_LEN ((byte)6)
#define WII_NUNCHUCK_TWI_ADR ((byte)0x52)

#include <Wire.h>
#include <string.h>
#include <utility\twi.h>
#undef int
#include <stdio.h>

uint8_t outbuf[WII_TELEGRAM_LEN];            // array to store arduino output
int cnt = 0;
int ledPin = 13;

void setup ()
{
  Serial.begin (115200);

#ifdef POWER_VIA_PORT_C2_C3    // power supply of the Nunchuck via port C2 and C3
  PORTC &=~ _BV(PORTC2);
  PORTC |=  _BV(PORTC3);
  DDRC |= _BV(PORTC2) | _BV(PORTC3);  // make outputs
  delay(100);  // wait for things to stabilize
#endif

  Wire.begin(); // initialize i2c
  // we need to switch the TWI speed, because the nunchuck uses Fast-TWI
  // normally set in hardware\libraries\Wire\utility\twi.c twi_init()
  // this is the way of doing it without modifying the original files
#define TWI_FREQ_NUNCHUCK 400000L
  TWBR = ((CPU_FREQ / TWI_FREQ_NUNCHUCK) - 16) / 2;

  nunchuck_init(0); // send the initialization handshake

  // display the identification bytes, must be "00 00 A4 20 00 00" for the Nunchuck
  byte i;
  if(readControllerIdent(outbuf) == 0)
  {
    Serial.print("Ident=");
    for (i = 0; i < WII_TELEGRAM_LEN; i++)
    {
      Serial.print(outbuf[i], HEX);
      Serial.print(' ');
    }
    Serial.println();
  }

  Serial.println("Finished setup");
}

// params:
//   timeout: abort when timeout (in ms) expires, 0 for unlimited timeout
//   return:  0 == ok, 1 == timeout
byte nunchuck_init (unsigned short timeout)
{
  byte rc = 1;

#ifndef USE_NEW_WAY_INIT
  // look at <http://wiibrew.org/wiki/Wiimote#The_Old_Way> at "The Old Way"
  Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR);      // transmit to device 0x52
  Wire.send (0x40);            // sends memory address
  Wire.send (0x00);            // sends sent a zero.  
  Wire.endTransmission ();      // stop transmitting
#else
  // disable encryption
  // look at <http://wiibrew.org/wiki/Wiimote#The_New_Way> at "The New Way"

  unsigned long time = millis();
  do
  {
    Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR);      // transmit to device 0x52
    Wire.send (0xF0);            // sends memory address
    Wire.send (0x55);            // sends data.  
    if(Wire.endTransmission() == 0) // stop transmitting
    {
      Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR);      // transmit to device 0x52
      Wire.send (0xFB);            // sends memory address
      Wire.send (0x00);            // sends sent a zero.  
      if(Wire.endTransmission () == 0)      // stop transmitting
      {
        rc = 0;
      }
    }
  }
  while (rc != 0 && (!timeout || ((millis() - time) < timeout)));
#endif

  return rc;
}


// params:
//   ident [out]: pointer to buffer where 6 bytes of identification is stored. Buffer must be at least 6 bytes long.
//                A list of possible identifications can be found here: <http://wiibrew.org/wiki/Wiimote#The_New_Way>
//   return:  0 == ok, 1 == error
byte readControllerIdent(byte* pIdent)
{
  byte rc = 1;

  // read identification
  Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR);      // transmit to device 0x52
  Wire.send (0xFA);            // sends memory address of ident in controller
  if(Wire.endTransmission () == 0)      // stop transmitting
  {
    byte i;
    Wire.requestFrom (WII_NUNCHUCK_TWI_ADR, WII_TELEGRAM_LEN);      // request data from nunchuck
    for (i = 0; (i < WII_TELEGRAM_LEN) && Wire.available (); i++)
    {
      pIdent[i] = Wire.receive();      // receive byte as an integer
    }
    if(i == WII_TELEGRAM_LEN)
    {
      rc = 0;
    }
  }
  return rc;
}

void clearTwiInputBuffer(void)
{
  // clear the receive buffer from any partial data
  while( Wire.available ())
    Wire.receive ();
}


void send_zero ()
{
  // I don't know why, but it only works correct when doing this exactly 3 times
  // otherwise only each 3rd call reads data from the controller (cnt will be 0 the other times)
  for(byte i = 0; i < 3; i++)
  {
    Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR);      // transmit to device 0x52
    Wire.send (0x00);            // sends one byte
    Wire.endTransmission ();      // stop transmitting
    //delay(1);
  }
}

void loop ()
{
  delay (1000);
  send_zero (); // send the request for next bytes
  Wire.requestFrom (WII_NUNCHUCK_TWI_ADR, WII_TELEGRAM_LEN);      // request data from nunchuck

  for (cnt = 0; (cnt < WII_TELEGRAM_LEN) && Wire.available (); cnt++)
  {
    outbuf[cnt] = nunchuk_decode_byte (Wire.receive ());      // receive byte as an integer
    digitalWrite (ledPin, HIGH);      // sets the LED on
  }

  // debugging
#ifdef DEBUG_RCV_TEL
  Serial.print("avail=");
  Serial.print(Wire.available(), DEC);
  Serial.print("  cnt=");
  Serial.println(cnt, DEC);
#endif

  clearTwiInputBuffer();

  // If we recieved the 6 bytes, then go print them
  if (cnt >= WII_TELEGRAM_LEN)
  {
    print ();
  }

}

// Print the input data we have recieved
// accel data is 10 bits long
// so we read 8 bits, then we have to add
// on the last 2 bits.  That is why I
// multiply them by 2 * 2
void print ()
{
  int joy_x_axis = outbuf[0];
  int joy_y_axis = outbuf[1];
  int accel_x_axis = outbuf[2] * 2 * 2;
  int accel_y_axis = outbuf[3] * 2 * 2;
  int accel_z_axis = outbuf[4] * 2 * 2;

  int z_button = 0;
  int c_button = 0;

  // byte outbuf[5] contains bits for z and c buttons
  // it also contains the least significant bits for the accelerometer data
  // so we have to check each bit of byte outbuf[5]
  if ((outbuf[5] >> 0) & 1)
  {
    z_button = 1;
  }
  if ((outbuf[5] >> 1) & 1)
  {
    c_button = 1;
  }

  if ((outbuf[5] >> 2) & 1)
  {
    accel_x_axis += 2;
  }
  if ((outbuf[5] >> 3) & 1)
  {
    accel_x_axis += 1;
  }

  if ((outbuf[5] >> 4) & 1)
  {
    accel_y_axis += 2;
  }
  if ((outbuf[5] >> 5) & 1)
  {
    accel_y_axis += 1;
  }

  if ((outbuf[5] >> 6) & 1)
  {
    accel_z_axis += 2;
  }
  if ((outbuf[5] >> 7) & 1)
  {
    accel_z_axis += 1;
  }

  Serial.print (joy_x_axis, DEC);
  Serial.print ("\t");

  Serial.print (joy_y_axis, DEC);
  Serial.print ("\t");

  Serial.print (accel_x_axis, DEC);
  Serial.print ("\t");

  Serial.print (accel_y_axis, DEC);
  Serial.print ("\t");

  Serial.print (accel_z_axis, DEC);
  Serial.print ("\t");

  Serial.print (z_button, DEC);
  Serial.print ("\t");

  Serial.print (c_button, DEC);
  Serial.print ("\t");

  Serial.print ("\r\n");
}

// Decode data format that original Nunchuck uses with old init sequence. This never worked with
// other controllers (e.g. wireless Nunchuck from other vendors)
char nunchuk_decode_byte (char x)
{
#ifndef USE_NEW_WAY_INIT
  x = (x ^ 0x17) + 0x17;
#endif
  return x;
}

and I like to alter it by replicating ILAN’s recommended routine:

BEGIN INIT LOOP
0xA4
0xF0
0x55

30 msec DELAY

0xA4
0xFB
0x00

23 msec DELAY

0xA4
0xFA //identity request

45 usec DELAY

0xA5 //identitity READ

23 msec DELAY

0xA4
0xF0
0xAA //Enable Encryption

30 msec DELAY

0xA4
0x40
0x00
0x00
0x00
0x00
0x00
0x00 //Send First 6 bytes of Encryption Key

30 msec DELAY

0xA4
0x46
0x00
0x00
0x00
0x00
0x00
0x00 //Send Second 6 bytes of Encryption Key

30 msec DELAY

0xA4
0x4C
0x00
0x00
0x00
0x00 //Send Last 4 bytes of Encryption Key

30 msec DELAY

END INIT LOOP (REPEAT LOOP FROM BEGINNING IF ANY I2C ERRORS OCCUR)

READ DATA LOOP BEGIN:

0xA4
0x00 //Request Nunchuck Data

500 usec DELAY

0xA5 //Read Nunchuck Data

4 msec DELAY

READ DATA LOOP END

The original thread: tp://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1259091426/0
I am sure this is super simple for anyone with more programming experience than me and should take just a moment. I have been trying learn /understand I2C protocol but as of now, I am too dense for any of it to stick…
While I usually subscribe to the “teach a man to fish” philosophy, I am begging someone to just help me make the changes. I have been blindly hacking at this thing with no sign of progress, please put me out of my misery.
Thanks in advance

Have you seen these projects. They use various wireless nunchucks on the arduino. There code may help. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1215475673 http://www.instructables.com/id/Wireless-Wii-Nunchuck-control-of-Arduino-projects/ http://sites.google.com/site/onewheeledselfbalancing/Home/wii-nunchuck-arduino-interface

Thanks, but Ive already seen them. The first is a wired nunchuk with an xbee the other two are by the guy who started the thread I posted and have the same code.

Hi Charbot,

As you know I have my wireless Chuck working but it is a "Blue Ocean" one which is USB rechargeable and only lasts about 2 hrs.

I have transplanted all internals into the (bigger) shell of a defunct BlazePro wireless chuck and am running it off 3 AAA batteries. Ugly but it works.

I would like to change to a Nyko Kama as then can just use 2 AA batteries and get plenty of endurance plus they are cheap chucks to buy.

I have been working with someone on this. He has taken Ilans code and got it to work on an AVR microcontroller (non-arduino) programmed in C. Furthermore the same software will work with both a standard wired chuck AND a Nyko Kama wireless chuck - ideal therefore as a general purpose remote control system.

He kindly rewrote it for me to try with an Arduino. On my arduino it works fine with a wired chuck but not with the Nyko Kama. As you found, the dongle wont even light up no matter what you try.

Further investigation shows that both he and Ilan are both in US and use a DIFFERENT version of the wireless Nyko Kama to the one available in Europe.

The one they use is wider than a normal chuck, has coloured c/z buttons (red/blue) and the dongle is different: It just has one sync button which then also lights up blue.

Whenever I buy a Nyko Kama here, it looks very similar to the normal Nintendo chuck, and the dongle has both an on/off button and a blue sync button/light.

So, my problem is: a) Does my Nyko not work because it is slightly different to those in the US that 2 people now DO have working (but not with an arduino board) or b) Is my Nyko fine (even though it is a bit different) and an error has crept in when their C code was rewritten for the arduino.

My wiring to the arduino must be OK as the wired chuck works fine.

What I need from somewhere is a US Nyko Kama to try (i.e. the wide one with the coloured c/z buttons on it) then I will know that if it still doesn't work it must be a small coding issue. I cannot buy one anywhere in the EU, only from US on ebay with extreme postage charges for some reason.

The reason there are 2 Kama variants is Nintendo sued them and they in the end agreed to "change the shape so it looks less like a Nintendo chuck" maybe this only applies to the US market which is why these US ones are little bit different to the ones I can get hold of.

So, still working on this problem. Tantalisingly close to a solution. I need a US spec Kama!

Best wishes

John