2014-04-28 09:54:41 +08:00
|
|
|
package i2c
|
2014-04-26 18:11:51 +08:00
|
|
|
|
|
|
|
import (
|
2023-02-04 20:22:22 +08:00
|
|
|
"fmt"
|
2017-04-03 02:10:12 +08:00
|
|
|
"sync"
|
2014-11-23 11:38:39 +08:00
|
|
|
"time"
|
2014-07-10 09:32:27 +08:00
|
|
|
|
2023-05-20 20:25:21 +08:00
|
|
|
"gobot.io/x/gobot/v2"
|
2014-04-26 18:11:51 +08:00
|
|
|
)
|
|
|
|
|
2017-02-09 23:47:11 +08:00
|
|
|
const (
|
|
|
|
// Joystick event when the Wiichuck joystick is moved
|
|
|
|
Joystick = "joystick"
|
|
|
|
|
|
|
|
// C event when the Wiichuck "C" button is pressed
|
|
|
|
C = "c"
|
|
|
|
|
|
|
|
// Z event when the Wiichuck "C" button is pressed
|
|
|
|
Z = "z"
|
|
|
|
)
|
|
|
|
|
2022-12-10 20:10:23 +08:00
|
|
|
const wiichuckDefaultAddress = 0x52
|
2015-07-04 09:57:29 +08:00
|
|
|
|
2023-02-04 20:22:22 +08:00
|
|
|
// WiichuckDriver contains the attributes for the i2c driver
|
2014-04-28 09:54:41 +08:00
|
|
|
type WiichuckDriver struct {
|
2022-12-10 20:10:23 +08:00
|
|
|
*Driver
|
2017-02-09 18:23:36 +08:00
|
|
|
interval time.Duration
|
|
|
|
pauseTime time.Duration
|
2014-11-23 11:38:39 +08:00
|
|
|
gobot.Eventer
|
2017-04-03 02:10:12 +08:00
|
|
|
mtx sync.Mutex
|
2014-04-26 18:11:51 +08:00
|
|
|
joystick map[string]float64
|
|
|
|
data map[string]float64
|
|
|
|
}
|
|
|
|
|
2016-09-25 20:08:18 +08:00
|
|
|
// NewWiichuckDriver creates a WiichuckDriver with specified i2c interface.
|
2014-10-21 01:42:01 +08:00
|
|
|
//
|
2017-02-09 23:47:11 +08:00
|
|
|
// Params:
|
2023-05-20 20:25:21 +08:00
|
|
|
//
|
|
|
|
// c Connector - the Adaptor to use with this Driver
|
2017-02-09 23:47:11 +08:00
|
|
|
//
|
|
|
|
// Optional params:
|
|
|
|
//
|
2023-05-20 20:25:21 +08:00
|
|
|
// i2c.WithBus(int): bus to use with this driver
|
|
|
|
// i2c.WithAddress(int): address to use with this driver
|
2022-12-10 20:10:23 +08:00
|
|
|
func NewWiichuckDriver(c Connector, options ...func(Config)) *WiichuckDriver {
|
2014-07-08 07:59:19 +08:00
|
|
|
w := &WiichuckDriver{
|
2022-12-10 20:10:23 +08:00
|
|
|
Driver: NewDriver(c, "Wiichuck", wiichuckDefaultAddress),
|
2017-02-06 07:19:42 +08:00
|
|
|
interval: 10 * time.Millisecond,
|
|
|
|
pauseTime: 1 * time.Millisecond,
|
|
|
|
Eventer: gobot.NewEventer(),
|
2014-04-28 09:54:41 +08:00
|
|
|
joystick: map[string]float64{
|
|
|
|
"sy_origin": -1,
|
|
|
|
"sx_origin": -1,
|
|
|
|
},
|
|
|
|
data: map[string]float64{
|
|
|
|
"sx": 0,
|
|
|
|
"sy": 0,
|
|
|
|
"z": 0,
|
|
|
|
"c": 0,
|
|
|
|
},
|
2014-04-26 18:11:51 +08:00
|
|
|
}
|
2022-12-10 20:10:23 +08:00
|
|
|
w.afterStart = w.initialize
|
2014-07-08 07:59:19 +08:00
|
|
|
|
2017-02-09 18:23:36 +08:00
|
|
|
for _, option := range options {
|
|
|
|
option(w)
|
2014-11-29 10:37:03 +08:00
|
|
|
}
|
|
|
|
|
2014-11-30 04:10:23 +08:00
|
|
|
w.AddEvent(Z)
|
|
|
|
w.AddEvent(C)
|
|
|
|
w.AddEvent(Joystick)
|
2016-02-07 10:51:55 +08:00
|
|
|
w.AddEvent(Error)
|
2017-02-09 18:23:36 +08:00
|
|
|
|
2014-07-08 07:59:19 +08:00
|
|
|
return w
|
2014-04-26 18:11:51 +08:00
|
|
|
}
|
2017-02-10 18:08:32 +08:00
|
|
|
|
2017-04-03 02:10:12 +08:00
|
|
|
// Joystick returns the current value for the joystick
|
|
|
|
func (w *WiichuckDriver) Joystick() map[string]float64 {
|
2017-04-12 22:00:22 +08:00
|
|
|
val := make(map[string]float64)
|
2017-04-03 02:10:12 +08:00
|
|
|
w.mtx.Lock()
|
|
|
|
defer w.mtx.Unlock()
|
2017-04-12 22:00:22 +08:00
|
|
|
val["sx_origin"] = w.joystick["sx_origin"]
|
|
|
|
val["sy_origin"] = w.joystick["sy_origin"]
|
2017-04-03 02:10:12 +08:00
|
|
|
return val
|
|
|
|
}
|
|
|
|
|
2014-10-21 01:42:01 +08:00
|
|
|
// update parses value to update buttons and joystick.
|
|
|
|
// If value is encrypted, warning message is printed
|
2023-02-04 20:22:22 +08:00
|
|
|
func (w *WiichuckDriver) update(value []byte) error {
|
2014-04-26 18:11:51 +08:00
|
|
|
if w.isEncrypted(value) {
|
2023-02-04 20:22:22 +08:00
|
|
|
return fmt.Errorf("Encrypted bytes")
|
2014-04-26 18:11:51 +08:00
|
|
|
}
|
2023-02-04 20:22:22 +08:00
|
|
|
|
|
|
|
w.parse(value)
|
|
|
|
w.adjustOrigins()
|
|
|
|
w.updateButtons()
|
|
|
|
w.updateJoystick()
|
|
|
|
return nil
|
2014-04-26 18:11:51 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 01:42:01 +08:00
|
|
|
// setJoystickDefaultValue sets default value if value is -1
|
2014-06-11 06:16:11 +08:00
|
|
|
func (w *WiichuckDriver) setJoystickDefaultValue(joystickAxis string, defaultValue float64) {
|
2017-04-03 02:10:12 +08:00
|
|
|
w.mtx.Lock()
|
|
|
|
defer w.mtx.Unlock()
|
2014-06-11 06:16:11 +08:00
|
|
|
if w.joystick[joystickAxis] == -1 {
|
|
|
|
w.joystick[joystickAxis] = defaultValue
|
2014-04-26 18:11:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-21 01:42:01 +08:00
|
|
|
// calculateJoystickValue returns distance between axis and origin
|
2014-04-28 09:54:41 +08:00
|
|
|
func (w *WiichuckDriver) calculateJoystickValue(axis float64, origin float64) float64 {
|
2023-10-21 02:50:42 +08:00
|
|
|
return axis - origin
|
2014-04-26 18:11:51 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 01:42:01 +08:00
|
|
|
// isEncrypted returns true if value is encrypted
|
2014-06-07 07:58:17 +08:00
|
|
|
func (w *WiichuckDriver) isEncrypted(value []byte) bool {
|
2014-04-26 18:11:51 +08:00
|
|
|
if value[0] == value[1] && value[2] == value[3] && value[4] == value[5] {
|
|
|
|
return true
|
|
|
|
}
|
2014-06-11 06:16:11 +08:00
|
|
|
return false
|
2014-04-26 18:11:51 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 01:42:01 +08:00
|
|
|
// decode removes encoding from `x` byte
|
2014-06-07 07:58:17 +08:00
|
|
|
func (w *WiichuckDriver) decode(x byte) float64 {
|
2014-04-26 18:11:51 +08:00
|
|
|
return float64((x ^ 0x17) + 0x17)
|
|
|
|
}
|
|
|
|
|
2014-10-21 01:42:01 +08:00
|
|
|
// adjustOrigins sets sy_origin and sx_origin with values from data
|
2014-04-28 09:54:41 +08:00
|
|
|
func (w *WiichuckDriver) adjustOrigins() {
|
2014-04-26 18:11:51 +08:00
|
|
|
w.setJoystickDefaultValue("sy_origin", w.data["sy"])
|
|
|
|
w.setJoystickDefaultValue("sx_origin", w.data["sx"])
|
|
|
|
}
|
|
|
|
|
2014-10-21 01:42:01 +08:00
|
|
|
// updateButtons publishes "c" and "x" events if present in data
|
2014-04-28 09:54:41 +08:00
|
|
|
func (w *WiichuckDriver) updateButtons() {
|
2014-04-26 18:11:51 +08:00
|
|
|
if w.data["c"] == 0 {
|
2016-08-30 20:22:09 +08:00
|
|
|
w.Publish(w.Event(C), true)
|
2014-04-26 18:11:51 +08:00
|
|
|
}
|
|
|
|
if w.data["z"] == 0 {
|
2016-08-30 20:22:09 +08:00
|
|
|
w.Publish(w.Event(Z), true)
|
2014-04-26 18:11:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-21 01:42:01 +08:00
|
|
|
// updateJoystick publishes event with current x and y values for joystick
|
2014-04-28 09:54:41 +08:00
|
|
|
func (w *WiichuckDriver) updateJoystick() {
|
2017-04-03 02:10:12 +08:00
|
|
|
joy := w.Joystick()
|
2016-08-30 20:22:09 +08:00
|
|
|
w.Publish(w.Event(Joystick), map[string]float64{
|
2017-04-03 02:10:12 +08:00
|
|
|
"x": w.calculateJoystickValue(w.data["sx"], joy["sx_origin"]),
|
|
|
|
"y": w.calculateJoystickValue(w.data["sy"], joy["sy_origin"]),
|
2014-04-28 09:54:41 +08:00
|
|
|
})
|
2014-04-26 18:11:51 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 01:42:01 +08:00
|
|
|
// parse sets driver values based on parsed value
|
2014-06-07 07:58:17 +08:00
|
|
|
func (w *WiichuckDriver) parse(value []byte) {
|
2014-04-26 18:11:51 +08:00
|
|
|
w.data["sx"] = w.decode(value[0])
|
|
|
|
w.data["sy"] = w.decode(value[1])
|
|
|
|
w.data["z"] = float64(uint8(w.decode(value[5])) & 0x01)
|
|
|
|
w.data["c"] = float64(uint8(w.decode(value[5])) & 0x02)
|
|
|
|
}
|
2022-12-10 20:10:23 +08:00
|
|
|
|
|
|
|
// reads from adaptor using specified interval to update with new value
|
2023-11-16 03:51:52 +08:00
|
|
|
func (w *WiichuckDriver) initialize() error {
|
2022-12-10 20:10:23 +08:00
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
if _, err := w.connection.Write([]byte{0x40, 0x00}); err != nil {
|
|
|
|
w.Publish(w.Event(Error), err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
time.Sleep(w.pauseTime)
|
|
|
|
if _, err := w.connection.Write([]byte{0x00}); err != nil {
|
|
|
|
w.Publish(w.Event(Error), err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
time.Sleep(w.pauseTime)
|
|
|
|
newValue := make([]byte, 6)
|
|
|
|
bytesRead, err := w.connection.Read(newValue)
|
|
|
|
if err != nil {
|
|
|
|
w.Publish(w.Event(Error), err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if bytesRead == 6 {
|
|
|
|
if err = w.update(newValue); err != nil {
|
|
|
|
w.Publish(w.Event(Error), err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
time.Sleep(w.interval)
|
|
|
|
}
|
|
|
|
}()
|
2023-11-16 03:51:52 +08:00
|
|
|
return nil
|
2022-12-10 20:10:23 +08:00
|
|
|
}
|