gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/wiichuck_driver.go (about) 1 package i2c 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 8 "gobot.io/x/gobot/v2" 9 ) 10 11 const ( 12 // Joystick event when the Wiichuck joystick is moved 13 Joystick = "joystick" 14 15 // C event when the Wiichuck "C" button is pressed 16 C = "c" 17 18 // Z event when the Wiichuck "C" button is pressed 19 Z = "z" 20 ) 21 22 const wiichuckDefaultAddress = 0x52 23 24 // WiichuckDriver contains the attributes for the i2c driver 25 type WiichuckDriver struct { 26 *Driver 27 interval time.Duration 28 pauseTime time.Duration 29 gobot.Eventer 30 mtx sync.Mutex 31 joystick map[string]float64 32 data map[string]float64 33 } 34 35 // NewWiichuckDriver creates a WiichuckDriver with specified i2c interface. 36 // 37 // Params: 38 // 39 // c Connector - the Adaptor to use with this Driver 40 // 41 // Optional params: 42 // 43 // i2c.WithBus(int): bus to use with this driver 44 // i2c.WithAddress(int): address to use with this driver 45 func NewWiichuckDriver(c Connector, options ...func(Config)) *WiichuckDriver { 46 w := &WiichuckDriver{ 47 Driver: NewDriver(c, "Wiichuck", wiichuckDefaultAddress), 48 interval: 10 * time.Millisecond, 49 pauseTime: 1 * time.Millisecond, 50 Eventer: gobot.NewEventer(), 51 joystick: map[string]float64{ 52 "sy_origin": -1, 53 "sx_origin": -1, 54 }, 55 data: map[string]float64{ 56 "sx": 0, 57 "sy": 0, 58 "z": 0, 59 "c": 0, 60 }, 61 } 62 w.afterStart = w.initialize 63 64 for _, option := range options { 65 option(w) 66 } 67 68 w.AddEvent(Z) 69 w.AddEvent(C) 70 w.AddEvent(Joystick) 71 w.AddEvent(Error) 72 73 return w 74 } 75 76 // Joystick returns the current value for the joystick 77 func (w *WiichuckDriver) Joystick() map[string]float64 { 78 val := make(map[string]float64) 79 w.mtx.Lock() 80 defer w.mtx.Unlock() 81 val["sx_origin"] = w.joystick["sx_origin"] 82 val["sy_origin"] = w.joystick["sy_origin"] 83 return val 84 } 85 86 // update parses value to update buttons and joystick. 87 // If value is encrypted, warning message is printed 88 func (w *WiichuckDriver) update(value []byte) error { 89 if w.isEncrypted(value) { 90 return fmt.Errorf("Encrypted bytes") 91 } 92 93 w.parse(value) 94 w.adjustOrigins() 95 w.updateButtons() 96 w.updateJoystick() 97 return nil 98 } 99 100 // setJoystickDefaultValue sets default value if value is -1 101 func (w *WiichuckDriver) setJoystickDefaultValue(joystickAxis string, defaultValue float64) { 102 w.mtx.Lock() 103 defer w.mtx.Unlock() 104 if w.joystick[joystickAxis] == -1 { 105 w.joystick[joystickAxis] = defaultValue 106 } 107 } 108 109 // calculateJoystickValue returns distance between axis and origin 110 func (w *WiichuckDriver) calculateJoystickValue(axis float64, origin float64) float64 { 111 return float64(axis - origin) 112 } 113 114 // isEncrypted returns true if value is encrypted 115 func (w *WiichuckDriver) isEncrypted(value []byte) bool { 116 if value[0] == value[1] && value[2] == value[3] && value[4] == value[5] { 117 return true 118 } 119 return false 120 } 121 122 // decode removes encoding from `x` byte 123 func (w *WiichuckDriver) decode(x byte) float64 { 124 return float64((x ^ 0x17) + 0x17) 125 } 126 127 // adjustOrigins sets sy_origin and sx_origin with values from data 128 func (w *WiichuckDriver) adjustOrigins() { 129 w.setJoystickDefaultValue("sy_origin", w.data["sy"]) 130 w.setJoystickDefaultValue("sx_origin", w.data["sx"]) 131 } 132 133 // updateButtons publishes "c" and "x" events if present in data 134 func (w *WiichuckDriver) updateButtons() { 135 if w.data["c"] == 0 { 136 w.Publish(w.Event(C), true) 137 } 138 if w.data["z"] == 0 { 139 w.Publish(w.Event(Z), true) 140 } 141 } 142 143 // updateJoystick publishes event with current x and y values for joystick 144 func (w *WiichuckDriver) updateJoystick() { 145 joy := w.Joystick() 146 w.Publish(w.Event(Joystick), map[string]float64{ 147 "x": w.calculateJoystickValue(w.data["sx"], joy["sx_origin"]), 148 "y": w.calculateJoystickValue(w.data["sy"], joy["sy_origin"]), 149 }) 150 } 151 152 // parse sets driver values based on parsed value 153 func (w *WiichuckDriver) parse(value []byte) { 154 w.data["sx"] = w.decode(value[0]) 155 w.data["sy"] = w.decode(value[1]) 156 w.data["z"] = float64(uint8(w.decode(value[5])) & 0x01) 157 w.data["c"] = float64(uint8(w.decode(value[5])) & 0x02) 158 } 159 160 // reads from adaptor using specified interval to update with new value 161 func (w *WiichuckDriver) initialize() (err error) { 162 go func() { 163 for { 164 if _, err := w.connection.Write([]byte{0x40, 0x00}); err != nil { 165 w.Publish(w.Event(Error), err) 166 continue 167 } 168 time.Sleep(w.pauseTime) 169 if _, err := w.connection.Write([]byte{0x00}); err != nil { 170 w.Publish(w.Event(Error), err) 171 continue 172 } 173 time.Sleep(w.pauseTime) 174 newValue := make([]byte, 6) 175 bytesRead, err := w.connection.Read(newValue) 176 if err != nil { 177 w.Publish(w.Event(Error), err) 178 continue 179 } 180 if bytesRead == 6 { 181 if err = w.update(newValue); err != nil { 182 w.Publish(w.Event(Error), err) 183 continue 184 } 185 } 186 time.Sleep(w.interval) 187 } 188 }() 189 return 190 }