Mindstorms 3rd Party ROBOTC Drivers RobotC
[Home] [Download] [Submit a bug/suggestion] [ROBOTC Forums] [Blog] [Support this project]

dexterind-nxtchuck.h

Go to the documentation of this file.
00001 /*!@addtogroup Dexter_Industries
00002 * @{
00003 * @defgroup NXTCHUCK NXTChuck Sensor
00004 * Dexter Industries NXTChuck Sensor driver
00005 * @{
00006 */
00007 /*
00008  * $Id: dexterind-nxtchuck.h 133 2013-03-10 15:15:38Z xander $
00009  */
00010 
00011 #ifndef __NXTCHUCK_H__
00012 #define __NXTCHUCK_H__
00013 /** \file dexterind-nxtchuck.h
00014  * \brief Dexter Industries NXTChuck Sensor driver
00015  *
00016  * dexterind-nxtchuck.h provides an API for the Dexter Industries NXTChuck Sensor.
00017  *
00018  * Changelog:
00019  * - 0.1: Initial release
00020  *
00021  * Credits:
00022  * - Big thanks to Dexter Industries for providing me with the hardware necessary to write and test this.
00023  *
00024  * License: You may use this code as you wish, provided you give credit where its due.
00025  *
00026  * THIS CODE WILL ONLY WORK WITH ROBOTC VERSION 3.59 AND HIGHER. 
00027 
00028  * \author Xander Soldaat (xander_at_botbench.com)
00029  * \date 02 November 2012
00030  * \version 0.1
00031  * \example dexterind-nxtchuck-test1.c
00032  */
00033 
00034 #pragma systemFile
00035 
00036 #ifndef __COMMON_H__
00037 #include "common.h"
00038 #endif
00039 
00040 #define NXTCHUCK_COM_ERROR                        0
00041 #define NXTCHUCK_COM_SUCCESS                      1
00042 
00043 #define NXTCHUCK_I2C_ADDRESS                      0xA4
00044 
00045 #define NXTCHUCK_DEVICE_UNKNOWN                   1
00046 #define NXTCHUCK_DEVICE_NUNCHUK                   2
00047 #define NXTCHUCK_DEVICE_CLASSIC_CONTROLLER        3
00048 #define NXTCHUCK_DEVICE_GH_GUITAR                 4
00049 #define NXTCHUCK_DEVICE_GH_DRUMS                  5
00050 #define NXTCHUCK_DEVICE_DJH_TURNTABLE             6
00051 #define NXTCHUCK_DEVICE_BALANCE_BOARD             7
00052 #define NXTCHUCK_DEVICE_MOTION_PLUS_ACTIVE        8
00053 #define NXTCHUCK_DEVICE_MOTION_PLUS_ACTIVE_N_PT   9
00054 #define NXTCHUCK_DEVICE_MOTION_PLUS_ACTIVE_CC_PT  10
00055 #define NXTCHUCK_DEVICE_MOTION_PLUS_INACTIVE      11
00056 #define NXTCHUCK_DEVICE_MOTION_PLUS_NL_ACTIVE     12
00057 #define NXTCHUCK_DEVICE_MOTION_PLUS_NL_N_PT       13
00058 #define NXTCHUCK_DEVICE_MOTION_PLUS_NL_CC_PT      14
00059 #define NXTCHUCK_DEVICE_NUNCHUK_BLACK             15
00060 
00061 #define NXTCHUCK_N_BTN_Z                          0x01
00062 #define NXTCHUCK_N_BTN_C                          0x02
00063 
00064 #define NXTCHUCK_CC_BTN_RT 0x0002 // Right shoulder button
00065 #define NXTCHUCK_CC_BTN_P  0x0004 // Start button
00066 #define NXTCHUCK_CC_BTN_H  0x0008 // Home button
00067 #define NXTCHUCK_CC_BTN_M  0x0010 // Select button
00068 #define NXTCHUCK_CC_BTN_LT 0x0020 // Left Shoulder button
00069 #define NXTCHUCK_CC_BTN_DD 0x0040 // d-pad down
00070 #define NXTCHUCK_CC_BTN_DR 0x0080 // d-pad right
00071 #define NXTCHUCK_CC_BTN_DU 0x0100 // d-pad up
00072 #define NXTCHUCK_CC_BTN_DL 0x0200 // d-pad left
00073 #define NXTCHUCK_CC_BTN_ZR 0x0400 // Right-Z button
00074 #define NXTCHUCK_CC_BTN_X  0x0800 // x button
00075 #define NXTCHUCK_CC_BTN_A  0x1000 // a button
00076 #define NXTCHUCK_CC_BTN_Y  0x2000 // y button
00077 #define NXTCHUCK_CC_BTN_B  0x4000 // b button
00078 #define NXTCHUCK_CC_BTN_ZL 0x8000 // Left-Z button
00079 
00080 tByteArray NXTCHUCK_I2CRequest;        /*!< Array to hold I2C command data */
00081 tByteArray NXTCHUCK_I2CReply;          /*!< Array to hold I2C reply data */
00082 
00083 bool NXTCHUCKinitialised[] = {false, false, false, false};  /*!< Has the NXTChuck been initialised yet? */
00084 
00085 typedef struct
00086 {
00087   ubyte ident;
00088   ubyte stickX;
00089   ubyte stickY;
00090   int accelX;
00091   int accelY;
00092   int accelZ;
00093   bool buttonC;
00094   bool buttonZ;
00095   ubyte buttons;
00096 } tNunchuck;
00097 
00098 
00099 typedef struct
00100 {
00101   byte stickLX;
00102   byte stickLY;
00103   byte stickRX;
00104   byte stickRY;
00105   byte triggerR;
00106   byte triggerL;
00107   bool buttonTriggerR;
00108   bool buttonTriggerL;
00109   bool buttonDPadU;
00110   bool buttonDPadD;
00111   bool buttonDPadL;
00112   bool buttonDPadR;
00113   bool buttonX;
00114   bool buttonA;
00115   bool buttonY;
00116   bool buttonB;
00117   bool buttonHome;
00118   bool buttonSelect;
00119   bool buttonStart;
00120   bool buttonZL;
00121   bool buttonZR;
00122   unsigned int buttons;
00123 } tClassicCtrl;
00124 
00125 
00126 ubyte NXTChuckIdentLookup[][] = {
00127   {0x00,0x00,0xA4,0x20,0x00,0x00}, // Nunchuk
00128   {0x00,0x00,0xA4,0x20,0x01,0x01}, // Classic Controller
00129   {0x00,0x00,0xA4,0x20,0x01,0x03}, // GH3 or GHWT Guitar
00130   {0x01,0x00,0xA4,0x20,0x01,0x03}, // Guitar Hero World Tour Drums
00131   {0x03,0x00,0xA4,0x20,0x01,0x03}, // DJ Hero Turntable
00132   {0x00,0x00,0xA4,0x20,0x04,0x02}, // Wii Balance Board
00133   {0x00,0x00,0xA4,0x20,0x04,0x05}, // Activated Wii Motion Plus
00134   {0x00,0x00,0xA4,0x20,0x05,0x05}, // Activated Wii Motion Plus in Nunchuck passthrought mode
00135   {0x00,0x00,0xA4,0x20,0x07,0x05}, // Activated Wii Motion Plus in Classic Controller passthrought mode
00136   {0x00,0x00,0xA6,0x20,0x00,0x05}, // Inactive Wii Motion Plus
00137   {0x00,0x00,0xA6,0x20,0x04,0x05}, // No-longer active Wii Motion Plus
00138   {0x00,0x00,0xA6,0x20,0x05,0x05}, // No-longer nunchuk-passthrough Wii Motion Plus
00139   {0x00,0x00,0xA6,0x20,0x07,0x05}, // No-longer classic-passthrough Wii Motion Plus
00140   {0xFF,0x00,0xA4,0x20,0x00,0x00}  // Seems to the ID of a black nunchuck
00141 };
00142 
00143 ubyte _NXTChuckDataInit1[] = {3, 0xA4, 0xF0, 0x55}; /*!< First of two arrays written to the extension to initialize */
00144 ubyte _NXTChuckDataInit2[] = {3, 0xA4, 0xFB, 0x00}; /*!< Second of two arrays written to the extension to initialize */
00145 
00146 /**
00147  * It's a nunchuck, innit? Initialise the nunchuck sensor.
00148  *
00149  * Please note that this is an internal function and should not called directly.
00150  * @param link the NXTChuck port number
00151  * @return true if no error occured, false if it did
00152  */
00153 bool _NXTChuckInit(tSensors link){
00154   writeDebugStreamLine("initialising");
00155     memcpy(NXTCHUCK_I2CRequest, _NXTChuckDataInit1, sizeof(_NXTChuckDataInit1));
00156     if (!writeI2C(link, NXTCHUCK_I2CRequest))
00157       return false;
00158 
00159     memcpy(NXTCHUCK_I2CRequest, _NXTChuckDataInit2, sizeof(_NXTChuckDataInit2));
00160     return writeI2C(link, NXTCHUCK_I2CRequest);
00161 }
00162 
00163 /**
00164  * Read 6 bytes from the nunchuck and return it.
00165  *
00166  * Please note this is an internal function and should not be used directly.
00167  * @param link the nunchuck port number
00168  * @param _reg the register to read
00169  * @param data the tByteArray to hold the returned data
00170  * @return true if no error occured, false if it did
00171  */
00172 bool __NXTChuckReadRaw(tSensors link, ubyte _reg, tByteArray &data){
00173   if (!NXTCHUCKinitialised[link])
00174   {
00175     if (!_NXTChuckInit(link))
00176       return false;
00177 
00178     NXTCHUCKinitialised[link] = true;
00179   }
00180 
00181   NXTCHUCK_I2CRequest[0] = 2;
00182   NXTCHUCK_I2CRequest[1] = NXTCHUCK_I2C_ADDRESS;
00183   NXTCHUCK_I2CRequest[2] = _reg;
00184 
00185   if (!writeI2C(link, NXTCHUCK_I2CRequest))
00186     return false;
00187 
00188   NXTCHUCK_I2CRequest[0] = 1;
00189   NXTCHUCK_I2CRequest[1] = NXTCHUCK_I2C_ADDRESS;
00190 
00191   return writeI2C(link, NXTCHUCK_I2CRequest, data, 6);
00192 }
00193 
00194 
00195 /**
00196  * Identify the type of nunchuck sensor connected to the NXT.
00197  * @param link the nunchuck port number
00198  * @param nunchuck the tNunchuck that holds the nunchuck related data.
00199  * @return true if no error occured, false if it did
00200  */
00201 bool NXTChuckreadIdent(tSensors link, tNunchuck &nunchuck){
00202   if(__NXTChuckReadRaw(link, 0xFA, NXTCHUCK_I2CReply)){
00203 
00204 #ifdef __NUNHUCK__DEBUG__
00205     for (int i = 0; i < 6; i++)
00206     {
00207       writeDebugStream("0x%02X ", NXTCHUCK_I2CReply[i]);
00208     }
00209 
00210     writeDebugStreamLine(" ");
00211 #endif // __NUNHUCK__DEBUG__
00212 
00213     for(byte i = 0; i < 14; i++){
00214 
00215 #ifdef __NUNHUCK__DEBUG__
00216       writeDebugStream("Comparing: ");
00217       for (int j = 0; j < 6; j++)
00218       {
00219         writeDebugStream("0x%02X ", NXTCHUCK_I2CReply[j]);
00220       }
00221       writeDebugStream("   and   ");
00222       for (int j = 0; j < 6; j++)
00223       {
00224         writeDebugStream("0x%02X ", NXTChuckIdentLookup[i][j]);
00225       }
00226       writeDebugStreamLine(": %d", memcmp(&NXTChuckIdentLookup[i][0], &NXTCHUCK_I2CReply[0], 6));
00227 #endif // __NUNHUCK__DEBUG__
00228 
00229       if (memcmp(&NXTChuckIdentLookup[i][0], &NXTCHUCK_I2CReply[0], 6) == 0)
00230       {
00231         nunchuck.ident = i + 2;
00232         return true;
00233       }
00234     }
00235     nunchuck.ident = NXTCHUCK_DEVICE_UNKNOWN;
00236     return true;
00237   }
00238   return false;                                                    // Communication error
00239 }
00240 
00241 
00242 /**
00243  * Read the data from the nunchuck.
00244  * @param link the nunchuck port number
00245  * @param nunchuck the tNunchuck that holds the nunchuck related data.
00246  * @return true if no error occured, false if it did
00247  */
00248 bool NXTChuckreadSensor(tSensors link, tNunchuck &nunchuck){
00249   if(__NXTChuckReadRaw(link, 0x00, NXTCHUCK_I2CReply))
00250   {
00251     nunchuck.stickX = NXTCHUCK_I2CReply[0];
00252     nunchuck.stickY = NXTCHUCK_I2CReply[1];
00253 
00254     nunchuck.accelX = (NXTCHUCK_I2CReply[2] << 2) | ((NXTCHUCK_I2CReply[5] >> 2) & 0x03);
00255     nunchuck.accelY = (NXTCHUCK_I2CReply[3] << 2) | ((NXTCHUCK_I2CReply[5] >> 4) & 0x03);
00256     nunchuck.accelZ = (NXTCHUCK_I2CReply[4] << 2) | ((NXTCHUCK_I2CReply[5] >> 6) & 0x03);
00257 
00258     nunchuck.buttons = (~NXTCHUCK_I2CReply[5]) & 0x03;
00259     nunchuck.buttonC = (nunchuck.buttons & NXTCHUCK_N_BTN_C) ? true : false;
00260     nunchuck.buttonZ = (nunchuck.buttons & NXTCHUCK_N_BTN_Z) ? true : false;
00261 
00262     return true;                                            // Return success
00263   }
00264   return false;                                                  // Return error
00265 }
00266 
00267 
00268 /**
00269  * Read the data from the classic controller.
00270  * @param link the nunchuck port number
00271  * @param controller the tClassicCtrl that holds the Classic Controller related data.
00272  * @return true if no error occured, false if it did
00273  */
00274 bool NXTChuckReadClassicController(tSensors link, tClassicCtrl &controller){
00275   if(__NXTChuckReadRaw(link, 0x00, NXTCHUCK_I2CReply))
00276   {
00277     controller.stickLX = NXTCHUCK_I2CReply[0] & 0x3F;                                        // Unpack the data into usable values
00278     controller.stickLY = NXTCHUCK_I2CReply[1] & 0x3F;
00279     controller.triggerL = ((NXTCHUCK_I2CReply[2] >> 2) & 0x18) | ((NXTCHUCK_I2CReply[3] >> 5) & 0x07);
00280 
00281     controller.stickRX = ((NXTCHUCK_I2CReply[0] >> 3) & 0x18) | ((NXTCHUCK_I2CReply[1] >> 5) & 0x06) | ((NXTCHUCK_I2CReply[2] >> 7) & 0x01);
00282     controller.stickRY = NXTCHUCK_I2CReply[2] & 0x1F;
00283     controller.triggerR = NXTCHUCK_I2CReply[3] & 0x1F;
00284 
00285     controller.buttons = ~(NXTCHUCK_I2CReply[4] | (NXTCHUCK_I2CReply[5] << 8)) & 0xFFFE;
00286 
00287     controller.buttonTriggerR = (controller.buttons & NXTCHUCK_CC_BTN_RT) ? true : false;
00288     controller.buttonTriggerL = (controller.buttons & NXTCHUCK_CC_BTN_LT) ? true : false;
00289 
00290     controller.buttonDPadU =    (controller.buttons & NXTCHUCK_CC_BTN_DU) ? true : false;
00291     controller.buttonDPadD =    (controller.buttons & NXTCHUCK_CC_BTN_DD) ? true : false;
00292     controller.buttonDPadL =    (controller.buttons & NXTCHUCK_CC_BTN_DL) ? true : false;
00293     controller.buttonDPadR =    (controller.buttons & NXTCHUCK_CC_BTN_DR) ? true : false;
00294 
00295     controller.buttonX =        (controller.buttons & NXTCHUCK_CC_BTN_X)  ? true : false;
00296     controller.buttonA =        (controller.buttons & NXTCHUCK_CC_BTN_A)  ? true : false;
00297     controller.buttonY =        (controller.buttons & NXTCHUCK_CC_BTN_Y)  ? true : false;
00298     controller.buttonB =        (controller.buttons & NXTCHUCK_CC_BTN_B)  ? true : false;
00299 
00300     controller.buttonHome =     (controller.buttons & NXTCHUCK_CC_BTN_H)  ? true : false;
00301     controller.buttonSelect =   (controller.buttons & NXTCHUCK_CC_BTN_RT) ? true : false;
00302     controller.buttonStart =    (controller.buttons & NXTCHUCK_CC_BTN_P)  ? true : false;
00303 
00304     controller.buttonZL =       (controller.buttons & NXTCHUCK_CC_BTN_RT) ? true : false;
00305     controller.buttonZR =       (controller.buttons & NXTCHUCK_CC_BTN_RT) ? true : false;
00306 
00307     return true;
00308   }
00309   return false;
00310 }
00311 
00312 
00313 #endif // __NXTCHUCK_H__
00314 
00315 /*
00316  * $Id: dexterind-nxtchuck.h 133 2013-03-10 15:15:38Z xander $
00317  */
00318 /* @} */
00319 /* @} */