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

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WiiNunchuckReader.cpp Source File

WiiNunchuckReader.cpp

00001 /*
00002 * WiiNunchuckReader. A program allowing the output of one or two
00003 * Wii Nunchucks to be read via I2C and decoded for use, using the mbed 
00004 * microcontroller and its associated libraries.
00005 *
00006 * Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
00007 *
00008 * This file is part of WiiNunchuckReader.
00009 *
00010 * WiiNunchuckReader is free software: you can redistribute it and/or modify
00011 * it under the terms of the GNU General Public License as published by
00012 * the Free Software Foundation, either version 3 of the License, or
00013 * (at your option) any later version.
00014 * 
00015 * WiiNunchuckReader is distributed in the hope that it will be useful,
00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 * GNU General Public License for more details.
00019 *
00020 * You should have received a copy of the GNU General Public License
00021 * along with WiiNunchuckReader.  If not, see <http://www.gnu.org/licenses/>.
00022 */
00023 
00024 #include "WiiNunchuckReader.h"
00025 
00026 // constructor
00027 WiiNunchuckReader::WiiNunchuckReader(PinName sda, PinName scl) : 
00028     nunchuckPort(sda, scl),
00029     joyX(0), joyY(0), accelX(0), accelY(0), accelZ(0),
00030     buttonC(0), buttonZ(0), nunchuckInit(false)
00031 {
00032 }
00033 
00034 void WiiNunchuckReader::RequestRead()
00035 {
00036     // don't expect client to remember to send an init to the nunchuck
00037     // so do it for them here
00038     if (!nunchuckInit)
00039     {
00040         nunchuckInit = NunchuckInit();
00041     }
00042     
00043     if (nunchuckInit)    // don't start reading if init failed
00044     {
00045         if (NunchuckRead())
00046         {
00047             // only decode successful reads
00048             NunchuckDecode();
00049         }
00050     }
00051 }
00052 
00053 bool WiiNunchuckReader::NunchuckInit()
00054 {
00055     bool success = false;
00056     
00057     const BYTE cmd[] = {NUNCHUCK_REGADDR, 0x00};    
00058     if (I2C_OK == nunchuckPort.write(NUNCHUCK_ADDR, (const char*)cmd, sizeof(cmd))) success = true;
00059     
00060     return success;
00061 }
00062 
00063 bool WiiNunchuckReader::NunchuckRead()
00064 {
00065     bool success = false;
00066     
00067     // write the address we want to read from
00068     const BYTE cmd[] = {0x00};
00069     if (I2C_OK == nunchuckPort.write(NUNCHUCK_ADDR, (const char*)cmd, sizeof(cmd)))
00070     {
00071         // the Wii Nunchuck is non-standard I2C
00072         // and can't manage setting the read address and immediately supplying the data
00073         // so wait a bit
00074         wait(I2C_READ_DELAY);
00075         
00076         if (I2C_OK == nunchuckPort.read(NUNCHUCK_ADDR, readBuf, sizeof(readBuf))) success = true;
00077     }
00078     
00079     return success;
00080 }
00081 
00082 void WiiNunchuckReader::NunchuckDecode()
00083 {
00084     joyX = (int)readBuf[JOY_X];
00085     joyY = (int)readBuf[JOY_Y];
00086     
00087     // the accelerometer axis values are really 10 bit values
00088     // so shift the 8 bit values read from the nunchuck
00089     // 2 bits to the right
00090     accelX = (int)readBuf[ACCEL_X] << 2;
00091     accelY = (int)readBuf[ACCEL_Y] << 2;
00092     accelZ = (int)readBuf[ACCEL_Z] << 2;
00093     
00094     DecodeAdditional();
00095 }
00096 
00097 void WiiNunchuckReader::DecodeAdditional()
00098 {
00099     // the nunchcuk buttons have their own idea of state
00100     int buttonState = readBuf[ADDITIONAL] & MASK_CZ;
00101     switch (buttonState)
00102     {
00103       case 3:
00104         buttonZ = 0;
00105         buttonC = 0;
00106         break;
00107       case 2:
00108         buttonZ = 1;
00109         buttonC = 1;
00110         break;
00111       case 1:
00112         buttonZ = 0;
00113         buttonC = 1;
00114         break;
00115       case 0:
00116         buttonZ = 1;
00117         buttonC = 0;
00118         break;
00119     }
00120 
00121     // and the accelerometer axis - for each axis value add bit 1 and bit 0
00122     // as required
00123     if (readBuf[ADDITIONAL] & MASK_ACCLX1) accelX += 2;
00124     if (readBuf[ADDITIONAL] & MASK_ACCLX2) accelX += 1;
00125     if (readBuf[ADDITIONAL] & MASK_ACCLY1) accelY += 2;
00126     if (readBuf[ADDITIONAL] & MASK_ACCLY2) accelY += 1;
00127     if (readBuf[ADDITIONAL] & MASK_ACCLZ1) accelZ += 2;
00128     if (readBuf[ADDITIONAL] & MASK_ACCLZ2) accelZ += 1;
00129 }