1////////////////////////////////////////////////////////////////////////////////
2// //
3// This software is supplied under the terms of a license agreement or //
4// nondisclosure agreement with Mitov Software and may not be copied //
5// or disclosed except in accordance with the terms of that agreement. //
6// Copyright(c) 2002-2016 Mitov Software. All Rights Reserved. //
7// //
8////////////////////////////////////////////////////////////////////////////////
9
10#ifndef _MITOV_WII_CONTROLLER_h
11#define _MITOV_WII_CONTROLLER_h
12
13#include <Mitov.h>
14
15// http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck
16
17namespace Mitov
18{
19//---------------------------------------------------------------------------
20 class WiiNunchuck : public Mitov::EnabledComponent, public Mitov::ClockingSupport
21 {
22 typedef Mitov::EnabledComponent inherited;
23
24 private:
25 const byte WII_NUNCHUK_I2C_ADDRESS = 0x52;
26
27 public:
28 OpenWire::TypedSourcePin<float> AngleOutputPins[ 3 ];
29 OpenWire::TypedSourcePin<float> StickOutputPins[ 2 ];
30 OpenWire::TypedSourcePin<bool> ButtonOutputPins[ 2 ];
31
32 public:
33 uint32_t ReadDelay = 100;
34
35 protected:
36 bool FStarted = false;
37 unsigned long FLastTime = 0;
38 int FClockedCount = 0;
39
40 protected:
41 void DoClockReceive( void *_Data ) override
42 {
43 ++ FClockedCount;
44 StartRead();
45 }
46
47 void ReadData( bool AChangeOnly )
48 {
49 if( ! Enabled )
50 return;
51
52 ReadController( AChangeOnly );
53 }
54
55 void StartRead()
56 {
57 Wire.beginTransmission(WII_NUNCHUK_I2C_ADDRESS);
58 Wire.write(0x00);
59 Wire.endTransmission();
60
61 delayMicroseconds( 10 );
62
63 Wire.beginTransmission(WII_NUNCHUK_I2C_ADDRESS);
64 Wire.write(0x00);
65 Wire.endTransmission();
66 FLastTime = micros();
67 }
68
69 void ReadController( bool AChangeOnly )
70 {
71 uint8_t AData[6];
72 Wire.requestFrom(WII_NUNCHUK_I2C_ADDRESS, (byte)6);
73
74 for( int i = 0; i < 6; ++i )
75 AData[ i ] = Wire.read();
76
77 float AStickX = (float)AData[0] / 255;
78 float AStickY = (float)AData[1] / 255;
79 StickOutputPins[ 0 ].SetValue( AStickX, AChangeOnly );
80 StickOutputPins[ 1 ].SetValue( AStickY, AChangeOnly );
81
82 float AAngleX = ((float)(((uint16_t)AData[2] ) << 2) + ((AData[5] >> 2) & 0x03)) / 1023;
83 float AAngleY = ((float)(((uint16_t)AData[3] ) << 2) + ((AData[5] >> 4) & 0x03)) / 1023;
84 float AAngleZ = ((float)(((uint16_t)AData[4] ) << 2) + ((AData[5] >> 6) & 0x03)) / 1023;
85
86 AngleOutputPins[ 0 ].SetValue( AAngleX, AChangeOnly );
87 AngleOutputPins[ 1 ].SetValue( AAngleY, AChangeOnly );
88 AngleOutputPins[ 2 ].SetValue( AAngleZ, AChangeOnly );
89
90 bool AButtonValue = !( AData[5] & 0b10 );
91 ButtonOutputPins[ 0 ].SetValue( AButtonValue, AChangeOnly );
92
93 AButtonValue = !( AData[5] & 1 );
94 ButtonOutputPins[ 1 ].SetValue( AButtonValue, AChangeOnly );
95
96 if( ( ! ClockInputPin.IsConnected() ) || FClockedCount )
97 StartRead();
98 }
99
100 protected:
101 virtual void SystemLoopBegin( unsigned long currentMicros ) override
102 {
103 if( ! FClockedCount )
104 if( ! ClockInputPin.IsConnected() )
105 ++ FClockedCount;
106
107 if( FClockedCount )
108 if( currentMicros - FLastTime > ReadDelay )
109 {
110 -- FClockedCount;
111 ReadData( FStarted );
112 FStarted = true;
113 }
114
115 inherited::SystemLoopBegin( currentMicros );
116 }
117
118 virtual void SystemStart() override
119 {
120 // Init the controller
121 Wire.beginTransmission(WII_NUNCHUK_I2C_ADDRESS);
122 Wire.write(0xF0);
123 Wire.write(0x55);
124 Wire.endTransmission();
125
126 Wire.beginTransmission(WII_NUNCHUK_I2C_ADDRESS);
127 Wire.write(0xFB);
128 Wire.write(0x00);
129 Wire.endTransmission();
130
131 StartRead();
132 inherited::SystemStart();
133 }
134
135 };
136//---------------------------------------------------------------------------
137}
138
139#endif