gobot.io/x/gobot@v1.16.0/platforms/upboard/up2/adaptor.go (about) 1 package up2 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "strconv" 8 "sync" 9 10 multierror "github.com/hashicorp/go-multierror" 11 "gobot.io/x/gobot" 12 "gobot.io/x/gobot/drivers/i2c" 13 "gobot.io/x/gobot/drivers/spi" 14 "gobot.io/x/gobot/sysfs" 15 ) 16 17 const ( 18 // LEDRed is the built-in red LED. 19 LEDRed = "red" 20 21 // LEDBlue is the built-in blue LED. 22 LEDBlue = "blue" 23 24 // LEDGreen is the built-in green LED. 25 LEDGreen = "green" 26 27 // LEDYellow is the built-in yellow LED. 28 LEDYellow = "yellow" 29 ) 30 31 type sysfsPin struct { 32 pin int 33 pwmPin int 34 } 35 36 // Adaptor represents a Gobot Adaptor for the Upboard UP2 37 type Adaptor struct { 38 name string 39 pinmap map[string]sysfsPin 40 ledPath string 41 digitalPins map[int]*sysfs.DigitalPin 42 pwmPins map[int]*sysfs.PWMPin 43 i2cBuses [6]i2c.I2cDevice 44 mutex *sync.Mutex 45 spiDefaultBus int 46 spiDefaultChip int 47 spiBuses [2]spi.Connection 48 spiDefaultMode int 49 spiDefaultMaxSpeed int64 50 } 51 52 // NewAdaptor creates a UP2 Adaptor 53 func NewAdaptor() *Adaptor { 54 c := &Adaptor{ 55 name: gobot.DefaultName("UP2"), 56 mutex: &sync.Mutex{}, 57 ledPath: "/sys/class/leds/upboard:%s:/brightness", 58 } 59 60 c.setPins() 61 return c 62 } 63 64 // Name returns the name of the Adaptor 65 func (c *Adaptor) Name() string { return c.name } 66 67 // SetName sets the name of the Adaptor 68 func (c *Adaptor) SetName(n string) { c.name = n } 69 70 // Connect initializes the board 71 func (c *Adaptor) Connect() (err error) { 72 return nil 73 } 74 75 // Finalize closes connection to board and pins 76 func (c *Adaptor) Finalize() (err error) { 77 c.mutex.Lock() 78 defer c.mutex.Unlock() 79 80 for _, pin := range c.digitalPins { 81 if pin != nil { 82 if e := pin.Unexport(); e != nil { 83 err = multierror.Append(err, e) 84 } 85 } 86 } 87 for _, pin := range c.pwmPins { 88 if pin != nil { 89 if errs := pin.Enable(false); errs != nil { 90 err = multierror.Append(err, errs) 91 } 92 if errs := pin.Unexport(); errs != nil { 93 err = multierror.Append(err, errs) 94 } 95 } 96 } 97 for _, bus := range c.i2cBuses { 98 if bus != nil { 99 if e := bus.Close(); e != nil { 100 err = multierror.Append(err, e) 101 } 102 } 103 } 104 for _, bus := range c.spiBuses { 105 if bus != nil { 106 if e := bus.Close(); e != nil { 107 err = multierror.Append(err, e) 108 } 109 } 110 } 111 112 return 113 } 114 115 // DigitalRead reads digital value from the specified pin. 116 func (c *Adaptor) DigitalRead(pin string) (val int, err error) { 117 sysfsPin, err := c.DigitalPin(pin, sysfs.IN) 118 if err != nil { 119 return 120 } 121 return sysfsPin.Read() 122 } 123 124 // DigitalWrite writes digital value to the specified pin. 125 func (c *Adaptor) DigitalWrite(pin string, val byte) (err error) { 126 // is it one of the built-in LEDs? 127 if pin == LEDRed || pin == LEDBlue || pin == LEDGreen || pin == LEDYellow { 128 pinPath := fmt.Sprintf(c.ledPath, pin) 129 fi, e := sysfs.OpenFile(pinPath, os.O_WRONLY|os.O_APPEND, 0666) 130 defer fi.Close() 131 if e != nil { 132 return e 133 } 134 _, err = fi.WriteString(strconv.Itoa(int(val))) 135 return err 136 } 137 // one of the normal GPIO pins, then 138 sysfsPin, err := c.DigitalPin(pin, sysfs.OUT) 139 if err != nil { 140 return err 141 } 142 return sysfsPin.Write(int(val)) 143 } 144 145 // PwmWrite writes a PWM signal to the specified pin 146 func (c *Adaptor) PwmWrite(pin string, val byte) (err error) { 147 pwmPin, err := c.PWMPin(pin) 148 if err != nil { 149 return 150 } 151 period, err := pwmPin.Period() 152 if err != nil { 153 return err 154 } 155 duty := gobot.FromScale(float64(val), 0, 255.0) 156 return pwmPin.SetDutyCycle(uint32(float64(period) * duty)) 157 } 158 159 // TODO: take into account the actual period setting, not just assume default 160 const pwmPeriod = 10000000 161 162 // ServoWrite writes a servo signal to the specified pin 163 func (c *Adaptor) ServoWrite(pin string, angle byte) (err error) { 164 pwmPin, err := c.PWMPin(pin) 165 if err != nil { 166 return 167 } 168 169 // 0.5 ms => -90 170 // 1.5 ms => 0 171 // 2.0 ms => 90 172 const minDuty = 100 * 0.0005 * pwmPeriod 173 const maxDuty = 100 * 0.0020 * pwmPeriod 174 duty := uint32(gobot.ToScale(gobot.FromScale(float64(angle), 0, 180), minDuty, maxDuty)) 175 return pwmPin.SetDutyCycle(duty) 176 } 177 178 // DigitalPin returns matched digitalPin for specified values 179 func (c *Adaptor) DigitalPin(pin string, dir string) (sysfsPin sysfs.DigitalPinner, err error) { 180 c.mutex.Lock() 181 defer c.mutex.Unlock() 182 183 i, err := c.translatePin(pin) 184 185 if err != nil { 186 return 187 } 188 189 if c.digitalPins[i] == nil { 190 c.digitalPins[i] = sysfs.NewDigitalPin(i) 191 if err = c.digitalPins[i].Export(); err != nil { 192 return 193 } 194 } 195 196 if err = c.digitalPins[i].Direction(dir); err != nil { 197 return 198 } 199 200 return c.digitalPins[i], nil 201 } 202 203 // PWMPin returns matched pwmPin for specified pin number 204 func (c *Adaptor) PWMPin(pin string) (sysfsPin sysfs.PWMPinner, err error) { 205 c.mutex.Lock() 206 defer c.mutex.Unlock() 207 208 i, err := c.translatePwmPin(pin) 209 if err != nil { 210 return nil, err 211 } 212 if i == -1 { 213 return nil, errors.New("Not a PWM pin") 214 } 215 216 if c.pwmPins[i] == nil { 217 newPin := sysfs.NewPWMPin(i) 218 if err = newPin.Export(); err != nil { 219 return 220 } 221 // Make sure pwm is disabled when setting polarity 222 if err = newPin.Enable(false); err != nil { 223 return 224 } 225 if err = newPin.InvertPolarity(false); err != nil { 226 return 227 } 228 if err = newPin.Enable(true); err != nil { 229 return 230 } 231 if err = newPin.SetPeriod(10000000); err != nil { 232 return 233 } 234 c.pwmPins[i] = newPin 235 } 236 237 sysfsPin = c.pwmPins[i] 238 return 239 } 240 241 // GetConnection returns a connection to a device on a specified bus. 242 // Valid bus number is [5..6] which corresponds to /dev/i2c-5 through /dev/i2c-6. 243 func (c *Adaptor) GetConnection(address int, bus int) (connection i2c.Connection, err error) { 244 c.mutex.Lock() 245 defer c.mutex.Unlock() 246 247 if (bus < 5) || (bus > 6) { 248 return nil, fmt.Errorf("Bus number %d out of range", bus) 249 } 250 if c.i2cBuses[bus] == nil { 251 c.i2cBuses[bus], err = sysfs.NewI2cDevice(fmt.Sprintf("/dev/i2c-%d", bus)) 252 } 253 return i2c.NewConnection(c.i2cBuses[bus], address), err 254 } 255 256 // GetDefaultBus returns the default i2c bus for this platform 257 func (c *Adaptor) GetDefaultBus() int { 258 return 5 259 } 260 261 // GetSpiConnection returns an spi connection to a device on a specified bus. 262 // Valid bus number is [0..1] which corresponds to /dev/spidev0.0 through /dev/spidev0.1. 263 func (c *Adaptor) GetSpiConnection(busNum, chipNum, mode, bits int, maxSpeed int64) (connection spi.Connection, err error) { 264 c.mutex.Lock() 265 defer c.mutex.Unlock() 266 267 if (busNum < 0) || (busNum > 1) { 268 return nil, fmt.Errorf("Bus number %d out of range", busNum) 269 } 270 271 if c.spiBuses[busNum] == nil { 272 c.spiBuses[busNum], err = spi.GetSpiConnection(busNum, chipNum, mode, bits, maxSpeed) 273 } 274 275 return c.spiBuses[busNum], err 276 } 277 278 // GetSpiDefaultBus returns the default spi bus for this platform. 279 func (c *Adaptor) GetSpiDefaultBus() int { 280 return c.spiDefaultBus 281 } 282 283 // GetSpiDefaultChip returns the default spi chip for this platform. 284 func (c *Adaptor) GetSpiDefaultChip() int { 285 return c.spiDefaultChip 286 } 287 288 // GetSpiDefaultMode returns the default spi mode for this platform. 289 func (c *Adaptor) GetSpiDefaultMode() int { 290 return c.spiDefaultMode 291 } 292 293 // GetSpiDefaultBits returns the default spi number of bits for this platform. 294 func (c *Adaptor) GetSpiDefaultBits() int { 295 return 8 296 } 297 298 // GetSpiDefaultMaxSpeed returns the default spi max speed for this platform. 299 func (c *Adaptor) GetSpiDefaultMaxSpeed() int64 { 300 return c.spiDefaultMaxSpeed 301 } 302 303 func (c *Adaptor) setPins() { 304 c.digitalPins = make(map[int]*sysfs.DigitalPin) 305 c.pwmPins = make(map[int]*sysfs.PWMPin) 306 c.pinmap = fixedPins 307 308 c.spiDefaultBus = 0 309 c.spiDefaultMode = 0 310 c.spiDefaultMaxSpeed = 500000 311 } 312 313 func (c *Adaptor) translatePin(pin string) (i int, err error) { 314 if val, ok := c.pinmap[pin]; ok { 315 i = val.pin 316 } else { 317 err = errors.New("Not a valid pin") 318 } 319 return 320 } 321 322 func (c *Adaptor) translatePwmPin(pin string) (i int, err error) { 323 if val, ok := c.pinmap[pin]; ok { 324 i = val.pwmPin 325 } else { 326 err = errors.New("Not a valid pin") 327 } 328 return 329 }