gobot.io/x/gobot@v1.16.0/drivers/i2c/grovepi_driver.go (about) 1 package i2c 2 3 import ( 4 "strconv" 5 "strings" 6 "sync" 7 "time" 8 9 "gobot.io/x/gobot" 10 ) 11 12 const grovePiAddress = 0x04 13 14 // Commands format 15 const ( 16 CommandReadDigital = 1 17 CommandWriteDigital = 2 18 CommandReadAnalog = 3 19 CommandWriteAnalog = 4 20 CommandPinMode = 5 21 CommandReadUltrasonic = 7 22 CommandReadDHT = 40 23 ) 24 25 // GrovePiDriver is a driver for the GrovePi+ for I²C bus interface. 26 // https://www.dexterindustries.com/grovepi/ 27 // 28 // To use this driver with the GrovePi, it must be running the 1.3.0+ firmware. 29 // https://forum.dexterindustries.com/t/pre-release-of-grovepis-firmware-v1-3-0-open-to-testers/5119 30 // 31 type GrovePiDriver struct { 32 name string 33 digitalPins map[int]string 34 analogPins map[int]string 35 mutex *sync.Mutex 36 connector Connector 37 connection Connection 38 Config 39 } 40 41 // NewGrovePiDriver creates a new driver with specified i2c interface 42 // Params: 43 // conn Connector - the Adaptor to use with this Driver 44 // 45 // Optional params: 46 // i2c.WithBus(int): bus to use with this driver 47 // i2c.WithAddress(int): address to use with this driver 48 // 49 func NewGrovePiDriver(a Connector, options ...func(Config)) *GrovePiDriver { 50 d := &GrovePiDriver{ 51 name: gobot.DefaultName("GrovePi"), 52 digitalPins: make(map[int]string), 53 analogPins: make(map[int]string), 54 mutex: &sync.Mutex{}, 55 connector: a, 56 Config: NewConfig(), 57 } 58 59 for _, option := range options { 60 option(d) 61 } 62 63 // TODO: add commands for API 64 return d 65 } 66 67 // Name returns the Name for the Driver 68 func (d *GrovePiDriver) Name() string { return d.name } 69 70 // SetName sets the Name for the Driver 71 func (d *GrovePiDriver) SetName(n string) { d.name = n } 72 73 // Connection returns the connection for the Driver 74 func (d *GrovePiDriver) Connection() gobot.Connection { return d.connector.(gobot.Connection) } 75 76 // Start initialized the GrovePi 77 func (d *GrovePiDriver) Start() (err error) { 78 bus := d.GetBusOrDefault(d.connector.GetDefaultBus()) 79 address := d.GetAddressOrDefault(grovePiAddress) 80 81 d.connection, err = d.connector.GetConnection(address, bus) 82 if err != nil { 83 return err 84 } 85 86 return 87 } 88 89 // Halt returns true if devices is halted successfully 90 func (d *GrovePiDriver) Halt() (err error) { return } 91 92 // Connect is here to implement the Adaptor interface. 93 func (d *GrovePiDriver) Connect() (err error) { 94 return 95 } 96 97 // Finalize is here to implement the Adaptor interface. 98 func (d *GrovePiDriver) Finalize() (err error) { 99 return 100 } 101 102 // AnalogRead returns value from analog pin implementing the AnalogReader interface. 103 func (d *GrovePiDriver) AnalogRead(pin string) (value int, err error) { 104 pin = getPin(pin) 105 106 var pinNum int 107 pinNum, err = strconv.Atoi(pin) 108 if err != nil { 109 return 110 } 111 112 value, err = d.readAnalog(byte(pinNum)) 113 114 return 115 } 116 117 // DigitalRead performs a read on a digital pin. 118 func (d *GrovePiDriver) DigitalRead(pin string) (val int, err error) { 119 pin = getPin(pin) 120 121 var pinNum int 122 pinNum, err = strconv.Atoi(pin) 123 if err != nil { 124 return 125 } 126 127 if dir, ok := d.digitalPins[pinNum]; !ok || dir != "input" { 128 d.PinMode(byte(pinNum), "input") 129 d.digitalPins[pinNum] = "input" 130 } 131 132 val, err = d.readDigital(byte(pinNum)) 133 134 return 135 } 136 137 // UltrasonicRead performs a read on an ultrasonic pin. 138 func (d *GrovePiDriver) UltrasonicRead(pin string, duration int) (val int, err error) { 139 pin = getPin(pin) 140 141 var pinNum int 142 pinNum, err = strconv.Atoi(pin) 143 if err != nil { 144 return 145 } 146 147 if dir, ok := d.digitalPins[pinNum]; !ok || dir != "input" { 148 d.PinMode(byte(pinNum), "input") 149 d.digitalPins[pinNum] = "input" 150 } 151 152 val, err = d.readUltrasonic(byte(pinNum), duration) 153 154 return 155 } 156 157 // DigitalWrite writes a value to a specific digital pin implementing the DigitalWriter interface. 158 func (d *GrovePiDriver) DigitalWrite(pin string, val byte) (err error) { 159 pin = getPin(pin) 160 161 var pinNum int 162 pinNum, err = strconv.Atoi(pin) 163 if err != nil { 164 return 165 } 166 167 if dir, ok := d.digitalPins[pinNum]; !ok || dir != "output" { 168 d.PinMode(byte(pinNum), "output") 169 d.digitalPins[pinNum] = "output" 170 } 171 172 err = d.writeDigital(byte(pinNum), val) 173 174 return 175 } 176 177 // WriteAnalog writes PWM aka analog to the GrovePi. Not yet working. 178 func (d *GrovePiDriver) WriteAnalog(pin byte, val byte) error { 179 buf := []byte{CommandWriteAnalog, pin, val, 0} 180 _, err := d.connection.Write(buf) 181 182 time.Sleep(2 * time.Millisecond) 183 184 data := make([]byte, 1) 185 _, err = d.connection.Read(data) 186 187 return err 188 } 189 190 // PinMode sets the pin mode to input or output. 191 func (d *GrovePiDriver) PinMode(pin byte, mode string) error { 192 var b []byte 193 if mode == "output" { 194 b = []byte{CommandPinMode, pin, 1, 0} 195 } else { 196 b = []byte{CommandPinMode, pin, 0, 0} 197 } 198 _, err := d.connection.Write(b) 199 200 time.Sleep(2 * time.Millisecond) 201 202 _, err = d.connection.ReadByte() 203 204 return err 205 } 206 207 func getPin(pin string) string { 208 if len(pin) > 1 { 209 if strings.ToUpper(pin[0:1]) == "A" || strings.ToUpper(pin[0:1]) == "D" { 210 return pin[1:len(pin)] 211 } 212 } 213 214 return pin 215 } 216 217 // readAnalog reads analog value from the GrovePi. 218 func (d *GrovePiDriver) readAnalog(pin byte) (int, error) { 219 d.mutex.Lock() 220 defer d.mutex.Unlock() 221 222 b := []byte{CommandReadAnalog, pin, 0, 0} 223 _, err := d.connection.Write(b) 224 if err != nil { 225 return 0, err 226 } 227 228 time.Sleep(2 * time.Millisecond) 229 230 data := make([]byte, 3) 231 _, err = d.connection.Read(data) 232 if err != nil || data[0] != CommandReadAnalog { 233 return -1, err 234 } 235 236 v1 := int(data[1]) 237 v2 := int(data[2]) 238 return ((v1 * 256) + v2), nil 239 } 240 241 // readUltrasonic reads ultrasonic from the GrovePi. 242 func (d *GrovePiDriver) readUltrasonic(pin byte, duration int) (val int, err error) { 243 d.mutex.Lock() 244 defer d.mutex.Unlock() 245 246 buf := []byte{CommandReadUltrasonic, pin, 0, 0} 247 _, err = d.connection.Write(buf) 248 if err != nil { 249 return 250 } 251 252 time.Sleep(time.Duration(duration) * time.Millisecond) 253 254 data := make([]byte, 3) 255 _, err = d.connection.Read(data) 256 if err != nil || data[0] != CommandReadUltrasonic { 257 return 0, err 258 } 259 260 return int(data[1]) * 255 + int(data[2]), err 261 } 262 263 // readDigital reads digitally from the GrovePi. 264 func (d *GrovePiDriver) readDigital(pin byte) (val int, err error) { 265 d.mutex.Lock() 266 defer d.mutex.Unlock() 267 268 buf := []byte{CommandReadDigital, pin, 0, 0} 269 _, err = d.connection.Write(buf) 270 if err != nil { 271 return 272 } 273 274 time.Sleep(2 * time.Millisecond) 275 276 data := make([]byte, 2) 277 _, err = d.connection.Read(data) 278 if err != nil || data[0] != CommandReadDigital { 279 return 0, err 280 } 281 282 return int(data[1]), err 283 } 284 285 // writeDigital writes digitally to the GrovePi. 286 func (d *GrovePiDriver) writeDigital(pin byte, val byte) error { 287 d.mutex.Lock() 288 defer d.mutex.Unlock() 289 290 buf := []byte{CommandWriteDigital, pin, val, 0} 291 _, err := d.connection.Write(buf) 292 293 time.Sleep(2 * time.Millisecond) 294 295 _, err = d.connection.ReadByte() 296 297 return err 298 }