A program allowing the output of one or two Wii Nunchucks to be read via I2C and decoded for use.

Dependencies:   mbed

WiiNunchuckReader.cpp

Committer:
snatch59
Date:
2009-12-13
Revision:
0:d51f5e2478c1

File content as of revision 0:d51f5e2478c1:

/*
* WiiNunchuckReader. A program allowing the output of one or two
* Wii Nunchucks to be read via I2C and decoded for use, using the mbed 
* microcontroller and its associated libraries.
*
* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
*
* This file is part of WiiNunchuckReader.
*
* WiiNunchuckReader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* WiiNunchuckReader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WiiNunchuckReader.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "WiiNunchuckReader.h"

// constructor
WiiNunchuckReader::WiiNunchuckReader(PinName sda, PinName scl) : 
    nunchuckPort(sda, scl),
    joyX(0), joyY(0), accelX(0), accelY(0), accelZ(0),
    buttonC(0), buttonZ(0), nunchuckInit(false)
{
}

void WiiNunchuckReader::RequestRead()
{
    // don't expect client to remember to send an init to the nunchuck
    // so do it for them here
    if (!nunchuckInit)
    {
        nunchuckInit = NunchuckInit();
    }
    
    if (nunchuckInit)    // don't start reading if init failed
    {
        if (NunchuckRead())
        {
            // only decode successful reads
            NunchuckDecode();
        }
    }
}

bool WiiNunchuckReader::NunchuckInit()
{
    bool success = false;
    
    const BYTE cmd[] = {NUNCHUCK_REGADDR, 0x00};    
    if (I2C_OK == nunchuckPort.write(NUNCHUCK_ADDR, (const char*)cmd, sizeof(cmd))) success = true;
    
    return success;
}

bool WiiNunchuckReader::NunchuckRead()
{
    bool success = false;
    
    // write the address we want to read from
    const BYTE cmd[] = {0x00};
    if (I2C_OK == nunchuckPort.write(NUNCHUCK_ADDR, (const char*)cmd, sizeof(cmd)))
    {
        // the Wii Nunchuck is non-standard I2C
        // and can't manage setting the read address and immediately supplying the data
        // so wait a bit
        wait(I2C_READ_DELAY);
        
        if (I2C_OK == nunchuckPort.read(NUNCHUCK_ADDR, readBuf, sizeof(readBuf))) success = true;
    }
    
    return success;
}

void WiiNunchuckReader::NunchuckDecode()
{
    joyX = (int)readBuf[JOY_X];
    joyY = (int)readBuf[JOY_Y];
    
    // the accelerometer axis values are really 10 bit values
    // so shift the 8 bit values read from the nunchuck
    // 2 bits to the right
    accelX = (int)readBuf[ACCEL_X] << 2;
    accelY = (int)readBuf[ACCEL_Y] << 2;
    accelZ = (int)readBuf[ACCEL_Z] << 2;
    
    DecodeAdditional();
}

void WiiNunchuckReader::DecodeAdditional()
{
    // the nunchcuk buttons have their own idea of state
    int buttonState = readBuf[ADDITIONAL] & MASK_CZ;
    switch (buttonState)
    {
      case 3:
        buttonZ = 0;
        buttonC = 0;
        break;
      case 2:
        buttonZ = 1;
        buttonC = 1;
        break;
      case 1:
        buttonZ = 0;
        buttonC = 1;
        break;
      case 0:
        buttonZ = 1;
        buttonC = 0;
        break;
    }

    // and the accelerometer axis - for each axis value add bit 1 and bit 0
    // as required
    if (readBuf[ADDITIONAL] & MASK_ACCLX1) accelX += 2;
    if (readBuf[ADDITIONAL] & MASK_ACCLX2) accelX += 1;
    if (readBuf[ADDITIONAL] & MASK_ACCLY1) accelY += 2;
    if (readBuf[ADDITIONAL] & MASK_ACCLY2) accelY += 1;
    if (readBuf[ADDITIONAL] & MASK_ACCLZ1) accelZ += 2;
    if (readBuf[ADDITIONAL] & MASK_ACCLZ2) accelZ += 1;
}