hybridgroup.gobot/platforms/i2c/wiichuck_driver.go

161 lines
4.4 KiB
Go
Raw Normal View History

2014-04-28 09:54:41 +08:00
package i2c
import (
2014-11-20 08:56:48 +08:00
"errors"
"time"
2014-07-10 09:32:27 +08:00
"github.com/hybridgroup/gobot"
)
var _ gobot.Driver = (*WiichuckDriver)(nil)
2014-04-28 09:54:41 +08:00
type WiichuckDriver struct {
name string
connection gobot.Connection
interval time.Duration
gobot.Eventer
joystick map[string]float64
data map[string]float64
}
// NewWiichuckDriver creates a WiichuckDriver with specified i2c interface and name.
//
// It adds the following events:
// "z"- Get's triggered every interval amount of time if the z button is pressed
// "c" - Get's triggered every interval amount of time if the c button is pressed
// "joystick" - Get's triggered every "interval" amount of time if a joystick event occured, you can access values x, y
2014-05-23 12:33:05 +08:00
func NewWiichuckDriver(a I2cInterface, name string) *WiichuckDriver {
2014-07-08 07:59:19 +08:00
w := &WiichuckDriver{
name: name,
connection: a.(gobot.Connection),
interval: 10 * 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-07-08 07:59:19 +08:00
w.AddEvent("z")
w.AddEvent("c")
w.AddEvent("joystick")
return w
}
func (w *WiichuckDriver) Name() string { return w.name }
func (w *WiichuckDriver) Connection() gobot.Connection { return w.connection }
// adaptor returns i2c interface adaptor
func (w *WiichuckDriver) adaptor() I2cInterface {
return w.Connection().(I2cInterface)
}
// Start initilizes i2c and reads from adaptor
// using specified interval to update with new value
func (w *WiichuckDriver) Start() (errs []error) {
if err := w.adaptor().I2cStart(0x52); err != nil {
return []error{err}
2014-11-20 08:56:48 +08:00
}
gobot.Every(w.interval, func() {
2014-11-20 08:56:48 +08:00
if err := w.adaptor().I2cWrite([]byte{0x40, 0x00}); err != nil {
gobot.Publish(w.Event("error"), err)
return
}
if err := w.adaptor().I2cWrite([]byte{0x00}); err != nil {
2014-11-20 08:56:48 +08:00
gobot.Publish(w.Event("error"), err)
return
}
newValue, err := w.adaptor().I2cRead(6)
if err != nil {
gobot.Publish(w.Event("error"), err)
return
}
2014-06-11 06:16:11 +08:00
if len(newValue) == 6 {
2014-11-20 08:56:48 +08:00
if err = w.update(newValue); err != nil {
gobot.Publish(w.Event("error"), err)
return
}
}
})
return
}
2014-09-12 04:38:08 +08:00
// Halt returns true if driver is halted successfully
func (w *WiichuckDriver) Halt() (errs []error) { return }
// update parses value to update buttons and joystick.
// If value is encrypted, warning message is printed
2014-11-20 08:56:48 +08:00
func (w *WiichuckDriver) update(value []byte) (err error) {
if w.isEncrypted(value) {
2014-11-20 08:56:48 +08:00
return errors.New("Encrypted bytes from wii device!")
} else {
w.parse(value)
w.adjustOrigins()
w.updateButtons()
w.updateJoystick()
}
2014-11-20 08:56:48 +08:00
return
}
// setJoystickDefaultValue sets default value if value is -1
2014-06-11 06:16:11 +08:00
func (w *WiichuckDriver) setJoystickDefaultValue(joystickAxis string, defaultValue float64) {
if w.joystick[joystickAxis] == -1 {
w.joystick[joystickAxis] = defaultValue
}
}
// calculateJoystickValue returns distance between axis and origin
2014-04-28 09:54:41 +08:00
func (w *WiichuckDriver) calculateJoystickValue(axis float64, origin float64) float64 {
return float64(axis - origin)
}
// isEncrypted returns true if value is encrypted
func (w *WiichuckDriver) isEncrypted(value []byte) bool {
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
}
// decode removes encoding from `x` byte
func (w *WiichuckDriver) decode(x byte) float64 {
return float64((x ^ 0x17) + 0x17)
}
// adjustOrigins sets sy_origin and sx_origin with values from data
2014-04-28 09:54:41 +08:00
func (w *WiichuckDriver) adjustOrigins() {
w.setJoystickDefaultValue("sy_origin", w.data["sy"])
w.setJoystickDefaultValue("sx_origin", w.data["sx"])
}
// updateButtons publishes "c" and "x" events if present in data
2014-04-28 09:54:41 +08:00
func (w *WiichuckDriver) updateButtons() {
if w.data["c"] == 0 {
2014-07-08 07:59:19 +08:00
gobot.Publish(w.Event("c"), true)
}
if w.data["z"] == 0 {
2014-07-08 07:59:19 +08:00
gobot.Publish(w.Event("z"), true)
}
}
// updateJoystick publishes event with current x and y values for joystick
2014-04-28 09:54:41 +08:00
func (w *WiichuckDriver) updateJoystick() {
2014-07-08 07:59:19 +08:00
gobot.Publish(w.Event("joystick"), map[string]float64{
"x": w.calculateJoystickValue(w.data["sx"], w.joystick["sx_origin"]),
"y": w.calculateJoystickValue(w.data["sy"], w.joystick["sy_origin"]),
2014-04-28 09:54:41 +08:00
})
}
// parse sets driver values based on parsed value
func (w *WiichuckDriver) parse(value []byte) {
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)
}