-
Notifications
You must be signed in to change notification settings - Fork 11
/
adafruit_nunchuk.py
135 lines (109 loc) · 4.4 KB
/
adafruit_nunchuk.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# SPDX-FileCopyrightText: 2019 Carter Nelson for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_nunchuk`
================================================================================
CircuitPython library for Nintendo Nunchuk controller
* Author(s): Carter Nelson
Implementation Notes
--------------------
**Hardware:**
* `Wii Remote Nunchuk <https://en.wikipedia.org/wiki/Wii_Remote#Nunchuk>`_
* `Wiichuck <https://www.adafruit.com/product/342>`_
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
"""
import time
from collections import namedtuple
from adafruit_bus_device.i2c_device import I2CDevice
try:
import typing # pylint: disable=unused-import
from busio import I2C
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Nunchuk.git"
_I2C_INIT_DELAY = 0.1
class Nunchuk:
"""Class which provides interface to Nintendo Nunchuk controller.
:param ~I2C i2c: The `busio.I2C` object to use.
:param int address: (Optional) The I2C address of the device. Default is 0x52.
:param float i2c_read_delay: (Optional) The time in seconds to pause between the
I2C write and read. This needs to be at least 200us. A
conservative default of 2000us is used since some hosts may
not be able to achieve such timing.
"""
_Values = namedtuple("Values", ("joystick", "buttons", "acceleration"))
_Joystick = namedtuple("Joystick", ("x", "y"))
_Buttons = namedtuple("Buttons", ("C", "Z"))
_Acceleration = namedtuple("Acceleration", ("x", "y", "z"))
def __init__(
self, i2c: I2C, address: int = 0x52, i2c_read_delay: float = 0.002
) -> None:
self.buffer = bytearray(8)
# -| HACK |---------------------------------------------------
# fixes quirk with RP2040 + 3rd party controllers
while not i2c.try_lock():
pass
_ = i2c.scan()
i2c.unlock()
# ------------------------------------------------------------
self.i2c_device = I2CDevice(i2c, address)
self._i2c_read_delay = i2c_read_delay
time.sleep(_I2C_INIT_DELAY)
with self.i2c_device as i2c_dev:
# turn off encrypted data
# http://wiibrew.org/wiki/Wiimote/Extension_Controllers
i2c_dev.write(b"\xF0\x55")
time.sleep(_I2C_INIT_DELAY)
i2c_dev.write(b"\xFB\x00")
@property
def values(self) -> _Values:
"""The current state of all values."""
self._read_data()
return self._Values(
self._joystick(do_read=False),
self._buttons(do_read=False),
self._acceleration(do_read=False),
)
@property
def joystick(self) -> _Joystick:
"""The current joystick position."""
return self._joystick()
@property
def buttons(self) -> _Buttons: # pylint: disable=invalid-name
"""The current pressed state of buttons C and Z."""
return self._buttons()
@property
def acceleration(self) -> _Acceleration:
"""The current accelerometer reading."""
return self._acceleration()
def _joystick(self, do_read: bool = True) -> _Joystick:
if do_read:
self._read_data()
return self._Joystick(self.buffer[0], self.buffer[1]) # x, y
def _buttons(self, do_read: bool = True) -> _Buttons:
if do_read:
self._read_data()
return self._Buttons(
not bool(self.buffer[5] & 0x02), not bool(self.buffer[5] & 0x01) # C # Z
)
def _acceleration(self, do_read: bool = True) -> _Acceleration:
if do_read:
self._read_data()
return self._Acceleration(
((self.buffer[5] & 0xC0) >> 6) | (self.buffer[2] << 2), # ax
((self.buffer[5] & 0x30) >> 4) | (self.buffer[3] << 2), # ay
((self.buffer[5] & 0x0C) >> 2) | (self.buffer[4] << 2), # az
)
def _read_data(self) -> bytearray:
return self._read_register(b"\x00")
def _read_register(self, address) -> bytearray:
with self.i2c_device as i2c:
i2c.write(address)
time.sleep(self._i2c_read_delay) # at least 200us
i2c.readinto(self.buffer)
return self.buffer