Library for communicating with a Wii classic controller using the I2C bus.

Dependents:   WiiClassicControllerTest

Note that you will also need the CommonTypes library to use this.

Get it here:http://mbed.org/users/RichardE/code/CommonTypes/

Committer:
RichardE
Date:
Sun Jun 30 16:37:49 2013 +0000
Revision:
3:ecae3d286a99
Parent:
2:52c4a0b3a509
Child:
4:79d04d737f02
Calibration now works.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
RichardE 2:52c4a0b3a509 1 /*
RichardE 2:52c4a0b3a509 2 * SOURCE FILE : WiiClassicControllerWithCalibration.cpp
RichardE 2:52c4a0b3a509 3 *
RichardE 2:52c4a0b3a509 4 * Definition of class WiiClassicControllerWithCalibration.
RichardE 2:52c4a0b3a509 5 *
RichardE 2:52c4a0b3a509 6 */
RichardE 2:52c4a0b3a509 7
RichardE 2:52c4a0b3a509 8 #include "WiiClassicControllerWithCalibration.h"
RichardE 2:52c4a0b3a509 9
RichardE 2:52c4a0b3a509 10 /** Constructor
RichardE 2:52c4a0b3a509 11 * @param sda pin to use for SDA.
RichardE 2:52c4a0b3a509 12 * @param scl pin to use for SCL.
RichardE 2:52c4a0b3a509 13 */
RichardE 2:52c4a0b3a509 14 WiiClassicControllerWithCalibration::WiiClassicControllerWithCalibration( PinName sda, PinName scl ) :
RichardE 3:ecae3d286a99 15 WiiClassicController( sda, scl ),
RichardE 3:ecae3d286a99 16 calibrating( false )
RichardE 2:52c4a0b3a509 17 {
RichardE 2:52c4a0b3a509 18 // Set default scaling factors.
RichardE 2:52c4a0b3a509 19 // Left joystick is 6 bit reading. Raw reading of 0 gives -1. Raw reading of 63 gives +1.
RichardE 2:52c4a0b3a509 20 SetScaling( LeftJoyX, (float)( 2.0 / 63.0 ), -1 );
RichardE 2:52c4a0b3a509 21 SetScaling( LeftJoyY, (float)( 2.0 / 63.0 ), -1 );
RichardE 2:52c4a0b3a509 22 // Right joystick is 5 bit reading. Raw reading of 0 gives -1. Raw reading of 31 gives +1.
RichardE 2:52c4a0b3a509 23 SetScaling( RightJoyX, (float)( 2.0 / 31.0 ), -1 );
RichardE 2:52c4a0b3a509 24 SetScaling( RightJoyY, (float)( 2.0 / 31.0 ), -1 );
RichardE 2:52c4a0b3a509 25 // Left trigger is 5 bit reading. Raw reading of 0 gives 0. Raw reading of 31 gives +1.
RichardE 2:52c4a0b3a509 26 SetScaling( LeftTrigger, (float)( 1.0 / 31.0 ), 0 );
RichardE 2:52c4a0b3a509 27 // Right trigger is 5 bit reading. Raw reading of 0 gives 0. Raw reading of 31 gives +1.
RichardE 2:52c4a0b3a509 28 SetScaling( RightTrigger, (float)( 1.0 / 31.0 ), 0 );
RichardE 2:52c4a0b3a509 29 }
RichardE 2:52c4a0b3a509 30
RichardE 2:52c4a0b3a509 31 /** Destructor
RichardE 2:52c4a0b3a509 32 */
RichardE 2:52c4a0b3a509 33 WiiClassicControllerWithCalibration::~WiiClassicControllerWithCalibration() {
RichardE 2:52c4a0b3a509 34 }
RichardE 2:52c4a0b3a509 35
RichardE 2:52c4a0b3a509 36 /** Set scaling for a particular analogue input.
RichardE 3:ecae3d286a99 37 * @param input channel to read.
RichardE 2:52c4a0b3a509 38 * @param m scale (multiplier) for this analogue input.
RichardE 2:52c4a0b3a509 39 * @param c offset for this analogue input.
RichardE 2:52c4a0b3a509 40 */
RichardE 2:52c4a0b3a509 41 void WiiClassicControllerWithCalibration::SetScaling( AnaIn input, float m, float c ) {
RichardE 2:52c4a0b3a509 42 if( ( (int)input >= 0 ) && ( (int)input < (int)AnaInCount ) ) {
RichardE 2:52c4a0b3a509 43 AnaInRec *ptr = records + (int)input;
RichardE 2:52c4a0b3a509 44 ptr->Scale = m;
RichardE 2:52c4a0b3a509 45 ptr->Offset = c;
RichardE 2:52c4a0b3a509 46 }
RichardE 2:52c4a0b3a509 47 }
RichardE 2:52c4a0b3a509 48
RichardE 3:ecae3d286a99 49 /** Get scaling for a particular analogue input.
RichardE 3:ecae3d286a99 50 * @param input channel to read.
RichardE 3:ecae3d286a99 51 * @param m scale (multiplier) for this analogue input return here.
RichardE 3:ecae3d286a99 52 * @param c offset for this analogue input returned here.
RichardE 3:ecae3d286a99 53 */
RichardE 3:ecae3d286a99 54 void WiiClassicControllerWithCalibration::GetScaling( AnaIn input, float *m, float *c ) const {
RichardE 3:ecae3d286a99 55 if( ( (int)input >= 0 ) && ( (int)input < (int)AnaInCount ) ) {
RichardE 3:ecae3d286a99 56 const AnaInRec *ptr = records + (int)input;
RichardE 3:ecae3d286a99 57 *m = ptr->Scale;
RichardE 3:ecae3d286a99 58 *c = ptr->Offset;
RichardE 3:ecae3d286a99 59 }
RichardE 3:ecae3d286a99 60 }
RichardE 3:ecae3d286a99 61
RichardE 3:ecae3d286a99 62 /** Read from the controller.
RichardE 3:ecae3d286a99 63 * This override will also update calibration information
RichardE 3:ecae3d286a99 64 * when calibration is in progress.
RichardE 3:ecae3d286a99 65 * @returns true on success, false on failure.
RichardE 3:ecae3d286a99 66 */
RichardE 3:ecae3d286a99 67 bool WiiClassicControllerWithCalibration::Read( void ) {
RichardE 3:ecae3d286a99 68 // Call base class method to do the actual reading.
RichardE 3:ecae3d286a99 69 if( WiiClassicController::Read() ) {
RichardE 3:ecae3d286a99 70 // That worked so update calibration information if
RichardE 3:ecae3d286a99 71 // calibration is in progress.
RichardE 3:ecae3d286a99 72 if( calibrating ) {
RichardE 3:ecae3d286a99 73 UpdateCalibration();
RichardE 3:ecae3d286a99 74 }
RichardE 3:ecae3d286a99 75 return true;
RichardE 3:ecae3d286a99 76 }
RichardE 3:ecae3d286a99 77 else {
RichardE 3:ecae3d286a99 78 return false;
RichardE 3:ecae3d286a99 79 }
RichardE 3:ecae3d286a99 80 }
RichardE 3:ecae3d286a99 81
RichardE 2:52c4a0b3a509 82 /** Get calibrated left joystick X reading.
RichardE 2:52c4a0b3a509 83 * @returns a reading between -1 and +1.
RichardE 2:52c4a0b3a509 84 */
RichardE 2:52c4a0b3a509 85 float WiiClassicControllerWithCalibration::GetCalLJoyX( void ) const {
RichardE 3:ecae3d286a99 86 return GetScaled( LeftJoyX, GetLJoyX(), -1, 1 );
RichardE 2:52c4a0b3a509 87 }
RichardE 2:52c4a0b3a509 88
RichardE 2:52c4a0b3a509 89 /** Get calibrated left joystick Y reading.
RichardE 2:52c4a0b3a509 90 * @returns a reading between -1 and +1.
RichardE 2:52c4a0b3a509 91 */
RichardE 2:52c4a0b3a509 92 float WiiClassicControllerWithCalibration::GetCalLJoyY( void ) const {
RichardE 3:ecae3d286a99 93 return GetScaled( LeftJoyY, GetLJoyY(), -1, 1 );
RichardE 2:52c4a0b3a509 94 }
RichardE 2:52c4a0b3a509 95
RichardE 2:52c4a0b3a509 96 /** Get calibrated right joystick X reading.
RichardE 2:52c4a0b3a509 97 * @returns a reading between -1 and +1.
RichardE 2:52c4a0b3a509 98 */
RichardE 2:52c4a0b3a509 99 float WiiClassicControllerWithCalibration::GetCalRJoyX( void ) const {
RichardE 3:ecae3d286a99 100 return GetScaled( RightJoyX, GetRJoyX(), -1, 1 );
RichardE 2:52c4a0b3a509 101 }
RichardE 2:52c4a0b3a509 102
RichardE 2:52c4a0b3a509 103 /** Get calibrated right joystick Y reading.
RichardE 2:52c4a0b3a509 104 * @returns a reading between -1 and +1.
RichardE 2:52c4a0b3a509 105 */
RichardE 2:52c4a0b3a509 106 float WiiClassicControllerWithCalibration::GetCalRJoyY( void ) const {
RichardE 3:ecae3d286a99 107 return GetScaled( RightJoyY, GetRJoyY(), -1, 1 );
RichardE 2:52c4a0b3a509 108 }
RichardE 2:52c4a0b3a509 109
RichardE 2:52c4a0b3a509 110 /** Get calibrated left trigger reading.
RichardE 2:52c4a0b3a509 111 * @returns a reading between 0 and +1.
RichardE 2:52c4a0b3a509 112 */
RichardE 2:52c4a0b3a509 113 float WiiClassicControllerWithCalibration::GetCalLeftTrigger( void ) const {
RichardE 3:ecae3d286a99 114 return GetScaled( LeftTrigger, GetLeftTrigger(), 0, 1 );
RichardE 2:52c4a0b3a509 115 }
RichardE 2:52c4a0b3a509 116
RichardE 2:52c4a0b3a509 117 /** Get calibrated right trigger reading.
RichardE 2:52c4a0b3a509 118 * @returns a reading between 0 and +1.
RichardE 2:52c4a0b3a509 119 */
RichardE 2:52c4a0b3a509 120 float WiiClassicControllerWithCalibration::GetCalRightTrigger( void ) const {
RichardE 3:ecae3d286a99 121 return GetScaled( RightTrigger, GetRightTrigger(), 0, 1 );
RichardE 2:52c4a0b3a509 122 }
RichardE 2:52c4a0b3a509 123
RichardE 2:52c4a0b3a509 124 /** Get scaled reading.
RichardE 2:52c4a0b3a509 125 * @param input analogue input to scale.
RichardE 2:52c4a0b3a509 126 * @param raw raw readings in counts.
RichardE 3:ecae3d286a99 127 * @param min minimum permitted value.
RichardE 3:ecae3d286a99 128 * @param max maximum permited value.
RichardE 2:52c4a0b3a509 129 * @returns scaled reading.
RichardE 2:52c4a0b3a509 130 */
RichardE 3:ecae3d286a99 131 float WiiClassicControllerWithCalibration::GetScaled( AnaIn input, UInt8 raw, float min, float max ) const {
RichardE 2:52c4a0b3a509 132 if( ( (int)input >= 0 ) && ( (int)input < (int)AnaInCount ) ) {
RichardE 2:52c4a0b3a509 133 const AnaInRec *ptr = records + (int)input;
RichardE 3:ecae3d286a99 134 float y = (float)raw * ptr->Scale + ptr->Offset;
RichardE 3:ecae3d286a99 135 if( y < min ) {
RichardE 3:ecae3d286a99 136 y = min;
RichardE 3:ecae3d286a99 137 }
RichardE 3:ecae3d286a99 138 else if( y > max ) {
RichardE 3:ecae3d286a99 139 y = max;
RichardE 3:ecae3d286a99 140 }
RichardE 3:ecae3d286a99 141 return y;
RichardE 2:52c4a0b3a509 142 }
RichardE 2:52c4a0b3a509 143 else {
RichardE 2:52c4a0b3a509 144 return (float)0;
RichardE 2:52c4a0b3a509 145 }
RichardE 2:52c4a0b3a509 146 }
RichardE 3:ecae3d286a99 147
RichardE 3:ecae3d286a99 148 /** Start calibrating.
RichardE 3:ecae3d286a99 149 * Every call to Read method updates calibration until StopCalibrating is called.
RichardE 3:ecae3d286a99 150 */
RichardE 3:ecae3d286a99 151 void WiiClassicControllerWithCalibration::StartCalibrating( void ) {
RichardE 3:ecae3d286a99 152 if( ! calibrating ) {
RichardE 3:ecae3d286a99 153 // Initialise all records so that the minimum count is very large,
RichardE 3:ecae3d286a99 154 // the maximum count is very small and the zero count is whatever
RichardE 3:ecae3d286a99 155 // the joystick is reading right now.
RichardE 3:ecae3d286a99 156 AnaInRec *rec;
RichardE 3:ecae3d286a99 157 for( int i = 0; i < (int)AnaInCount; ++i ) {
RichardE 3:ecae3d286a99 158 rec = records + i;
RichardE 3:ecae3d286a99 159 rec->MinCount = 255;
RichardE 3:ecae3d286a99 160 rec->MaxCount = 0;
RichardE 3:ecae3d286a99 161 rec->ZeroCount = GetAnaIn( (AnaIn)i );
RichardE 3:ecae3d286a99 162 }
RichardE 3:ecae3d286a99 163 calibrating = true;
RichardE 3:ecae3d286a99 164 }
RichardE 3:ecae3d286a99 165 }
RichardE 3:ecae3d286a99 166
RichardE 3:ecae3d286a99 167 /** Get the raw counts for one of the analogue inputs.
RichardE 3:ecae3d286a99 168 * @param input analogue input to read.
RichardE 3:ecae3d286a99 169 * @returns raw counts for input.
RichardE 3:ecae3d286a99 170 */
RichardE 3:ecae3d286a99 171 UInt8 WiiClassicControllerWithCalibration::GetAnaIn( AnaIn input ) const {
RichardE 3:ecae3d286a99 172 switch( input ) {
RichardE 3:ecae3d286a99 173 case LeftJoyX :
RichardE 3:ecae3d286a99 174 return GetLJoyX();
RichardE 3:ecae3d286a99 175 case LeftJoyY :
RichardE 3:ecae3d286a99 176 return GetLJoyY();
RichardE 3:ecae3d286a99 177 case RightJoyX :
RichardE 3:ecae3d286a99 178 return GetRJoyX();
RichardE 3:ecae3d286a99 179 case RightJoyY :
RichardE 3:ecae3d286a99 180 return GetRJoyY();
RichardE 3:ecae3d286a99 181 case LeftTrigger :
RichardE 3:ecae3d286a99 182 return GetLeftTrigger();
RichardE 3:ecae3d286a99 183 case RightTrigger :
RichardE 3:ecae3d286a99 184 return GetRightTrigger();
RichardE 3:ecae3d286a99 185 default :
RichardE 3:ecae3d286a99 186 return 0;
RichardE 3:ecae3d286a99 187 }
RichardE 3:ecae3d286a99 188 }
RichardE 3:ecae3d286a99 189
RichardE 3:ecae3d286a99 190 /** Stop calibrating.
RichardE 3:ecae3d286a99 191 */
RichardE 3:ecae3d286a99 192 void WiiClassicControllerWithCalibration::StopCalibrating( void ) {
RichardE 3:ecae3d286a99 193 if( calibrating ) {
RichardE 3:ecae3d286a99 194 AnaInRec *rec;
RichardE 3:ecae3d286a99 195 for( int i = 0; i < (int)AnaInCount; ++i ) {
RichardE 3:ecae3d286a99 196 rec = records + i;
RichardE 3:ecae3d286a99 197 switch( (AnaIn)i ) {
RichardE 3:ecae3d286a99 198 case LeftJoyX :
RichardE 3:ecae3d286a99 199 case LeftJoyY :
RichardE 3:ecae3d286a99 200 case RightJoyX :
RichardE 3:ecae3d286a99 201 case RightJoyY :
RichardE 3:ecae3d286a99 202 rec->CalculateScaleAndOffsetBiPolar( -1, 1 );
RichardE 3:ecae3d286a99 203 break;
RichardE 3:ecae3d286a99 204 case LeftTrigger :
RichardE 3:ecae3d286a99 205 case RightTrigger :
RichardE 3:ecae3d286a99 206 rec->CalculateScaleAndOffsetUniPolar( 1 );
RichardE 3:ecae3d286a99 207 break;
RichardE 3:ecae3d286a99 208 }
RichardE 3:ecae3d286a99 209 }
RichardE 3:ecae3d286a99 210 calibrating = false;
RichardE 3:ecae3d286a99 211 }
RichardE 3:ecae3d286a99 212 }
RichardE 3:ecae3d286a99 213
RichardE 3:ecae3d286a99 214
RichardE 3:ecae3d286a99 215 /** Update calibration information.
RichardE 3:ecae3d286a99 216 */
RichardE 3:ecae3d286a99 217 void WiiClassicControllerWithCalibration::UpdateCalibration( void ) {
RichardE 3:ecae3d286a99 218 AnaInRec *rec;
RichardE 3:ecae3d286a99 219 UInt8 count;
RichardE 3:ecae3d286a99 220 for( int i = 0; i < (int)AnaInCount; ++i ) {
RichardE 3:ecae3d286a99 221 count = GetAnaIn( (AnaIn)i );
RichardE 3:ecae3d286a99 222 rec = records + i;
RichardE 3:ecae3d286a99 223 if( count < rec->MinCount ) {
RichardE 3:ecae3d286a99 224 rec->MinCount = count;
RichardE 3:ecae3d286a99 225 }
RichardE 3:ecae3d286a99 226 if( count > rec->MaxCount ) {
RichardE 3:ecae3d286a99 227 rec->MaxCount = count;
RichardE 3:ecae3d286a99 228 }
RichardE 3:ecae3d286a99 229 }
RichardE 3:ecae3d286a99 230 }
RichardE 3:ecae3d286a99 231
RichardE 3:ecae3d286a99 232 /** Calculate scale and offset for a bipolar reading.
RichardE 3:ecae3d286a99 233 * @param minValue minimum value to read.
RichardE 3:ecae3d286a99 234 * @param maxValue maximum value to read.
RichardE 3:ecae3d286a99 235 */
RichardE 3:ecae3d286a99 236 void WiiClassicControllerWithCalibration::AnaInRec::CalculateScaleAndOffsetBiPolar( float minValue, float maxValue ) {
RichardE 3:ecae3d286a99 237 UInt8 a;
RichardE 3:ecae3d286a99 238 float b;
RichardE 3:ecae3d286a99 239 if( ( ZeroCount - MinCount ) < ( MaxCount - ZeroCount ) ) {
RichardE 3:ecae3d286a99 240 a = MinCount;
RichardE 3:ecae3d286a99 241 b = minValue;
RichardE 3:ecae3d286a99 242 }
RichardE 3:ecae3d286a99 243 else {
RichardE 3:ecae3d286a99 244 a = MaxCount;
RichardE 3:ecae3d286a99 245 b = maxValue;
RichardE 3:ecae3d286a99 246 }
RichardE 3:ecae3d286a99 247 // Prevent a division by zero, but still a nonsense result.
RichardE 3:ecae3d286a99 248 if( a == ZeroCount ) {
RichardE 3:ecae3d286a99 249 a++;
RichardE 3:ecae3d286a99 250 }
RichardE 3:ecae3d286a99 251 Scale = ( b - (float)0 ) / (float)( a - ZeroCount );
RichardE 3:ecae3d286a99 252 Offset = -Scale * (float)ZeroCount;
RichardE 3:ecae3d286a99 253 }
RichardE 3:ecae3d286a99 254
RichardE 3:ecae3d286a99 255 /** Calculate scale and offset for a unipolar reading.
RichardE 3:ecae3d286a99 256 * Minimum value is assumed to be zero.
RichardE 3:ecae3d286a99 257 * @param maxValue maximum value to read.
RichardE 3:ecae3d286a99 258 */
RichardE 3:ecae3d286a99 259 void WiiClassicControllerWithCalibration::AnaInRec::CalculateScaleAndOffsetUniPolar( float maxValue ) {
RichardE 3:ecae3d286a99 260 UInt8 a = MaxCount;
RichardE 3:ecae3d286a99 261 float b = maxValue;
RichardE 3:ecae3d286a99 262 // Prevent a division by zero, but still a nonsense result.
RichardE 3:ecae3d286a99 263 if( a == MinCount ) {
RichardE 3:ecae3d286a99 264 a++;
RichardE 3:ecae3d286a99 265 }
RichardE 3:ecae3d286a99 266 Scale = ( b - (float)0 ) / (float)( a - MinCount );
RichardE 3:ecae3d286a99 267 Offset = -Scale * (float)MinCount;
RichardE 3:ecae3d286a99 268 }
RichardE 3:ecae3d286a99 269