gobot.io/x/gobot@v1.16.0/platforms/raspi/raspi_adaptor.go (about) 1 package raspi 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "strconv" 8 "strings" 9 10 "sync" 11 12 multierror "github.com/hashicorp/go-multierror" 13 "gobot.io/x/gobot" 14 "gobot.io/x/gobot/drivers/i2c" 15 "gobot.io/x/gobot/drivers/spi" 16 "gobot.io/x/gobot/sysfs" 17 ) 18 19 var readFile = func() ([]byte, error) { 20 return ioutil.ReadFile("/proc/cpuinfo") 21 } 22 23 // Adaptor is the Gobot Adaptor for the Raspberry Pi 24 type Adaptor struct { 25 mutex *sync.Mutex 26 name string 27 revision string 28 digitalPins map[int]*sysfs.DigitalPin 29 pwmPins map[int]*PWMPin 30 i2cDefaultBus int 31 i2cBuses [2]i2c.I2cDevice 32 spiDefaultBus int 33 spiDefaultChip int 34 spiDevices [2]spi.Connection 35 spiDefaultMode int 36 spiDefaultMaxSpeed int64 37 PiBlasterPeriod uint32 38 } 39 40 // NewAdaptor creates a Raspi Adaptor 41 func NewAdaptor() *Adaptor { 42 r := &Adaptor{ 43 mutex: &sync.Mutex{}, 44 name: gobot.DefaultName("RaspberryPi"), 45 digitalPins: make(map[int]*sysfs.DigitalPin), 46 pwmPins: make(map[int]*PWMPin), 47 PiBlasterPeriod: 10000000, 48 } 49 content, _ := readFile() 50 for _, v := range strings.Split(string(content), "\n") { 51 if strings.Contains(v, "Revision") { 52 s := strings.Split(string(v), " ") 53 version, _ := strconv.ParseInt("0x"+s[len(s)-1], 0, 64) 54 r.i2cDefaultBus = 1 55 r.spiDefaultBus = 0 56 r.spiDefaultChip = 0 57 r.spiDefaultMode = 0 58 r.spiDefaultMaxSpeed = 500000 59 if version <= 3 { 60 r.revision = "1" 61 r.i2cDefaultBus = 0 62 } else if version <= 15 { 63 r.revision = "2" 64 } else { 65 r.revision = "3" 66 } 67 } 68 } 69 70 return r 71 } 72 73 // Name returns the Adaptor's name 74 func (r *Adaptor) Name() string { 75 r.mutex.Lock() 76 defer r.mutex.Unlock() 77 78 return r.name 79 } 80 81 // SetName sets the Adaptor's name 82 func (r *Adaptor) SetName(n string) { 83 r.mutex.Lock() 84 defer r.mutex.Unlock() 85 86 r.name = n 87 } 88 89 // Connect starts connection with board and creates 90 // digitalPins and pwmPins adaptor maps 91 func (r *Adaptor) Connect() (err error) { 92 return 93 } 94 95 // Finalize closes connection to board and pins 96 func (r *Adaptor) Finalize() (err error) { 97 r.mutex.Lock() 98 defer r.mutex.Unlock() 99 100 for _, pin := range r.digitalPins { 101 if pin != nil { 102 if perr := pin.Unexport(); err != nil { 103 err = multierror.Append(err, perr) 104 } 105 } 106 } 107 for _, pin := range r.pwmPins { 108 if pin != nil { 109 if perr := pin.Unexport(); err != nil { 110 err = multierror.Append(err, perr) 111 } 112 } 113 } 114 for _, bus := range r.i2cBuses { 115 if bus != nil { 116 if e := bus.Close(); e != nil { 117 err = multierror.Append(err, e) 118 } 119 } 120 } 121 for _, dev := range r.spiDevices { 122 if dev != nil { 123 if e := dev.Close(); e != nil { 124 err = multierror.Append(err, e) 125 } 126 } 127 } 128 return 129 } 130 131 // DigitalPin returns matched digitalPin for specified values 132 func (r *Adaptor) DigitalPin(pin string, dir string) (sysfsPin sysfs.DigitalPinner, err error) { 133 i, err := r.translatePin(pin) 134 135 if err != nil { 136 return 137 } 138 139 currentPin, err := r.getExportedDigitalPin(i, dir) 140 141 if err != nil { 142 return 143 } 144 145 if err = currentPin.Direction(dir); err != nil { 146 return 147 } 148 149 return currentPin, nil 150 } 151 152 func (r *Adaptor) getExportedDigitalPin(translatedPin int, dir string) (sysfsPin sysfs.DigitalPinner, err error) { 153 r.mutex.Lock() 154 defer r.mutex.Unlock() 155 156 if r.digitalPins[translatedPin] == nil { 157 r.digitalPins[translatedPin] = sysfs.NewDigitalPin(translatedPin) 158 if err = r.digitalPins[translatedPin].Export(); err != nil { 159 return 160 } 161 } 162 163 return r.digitalPins[translatedPin], nil 164 } 165 166 // DigitalRead reads digital value from pin 167 func (r *Adaptor) DigitalRead(pin string) (val int, err error) { 168 sysfsPin, err := r.DigitalPin(pin, sysfs.IN) 169 if err != nil { 170 return 171 } 172 return sysfsPin.Read() 173 } 174 175 // DigitalWrite writes digital value to specified pin 176 func (r *Adaptor) DigitalWrite(pin string, val byte) (err error) { 177 sysfsPin, err := r.DigitalPin(pin, sysfs.OUT) 178 if err != nil { 179 return err 180 } 181 return sysfsPin.Write(int(val)) 182 } 183 184 // GetConnection returns an i2c connection to a device on a specified bus. 185 // Valid bus number is [0..1] which corresponds to /dev/i2c-0 through /dev/i2c-1. 186 func (r *Adaptor) GetConnection(address int, bus int) (connection i2c.Connection, err error) { 187 if (bus < 0) || (bus > 1) { 188 return nil, fmt.Errorf("Bus number %d out of range", bus) 189 } 190 191 device, err := r.getI2cBus(bus) 192 193 return i2c.NewConnection(device, address), err 194 } 195 196 func (r *Adaptor) getI2cBus(bus int) (_ i2c.I2cDevice, err error) { 197 r.mutex.Lock() 198 defer r.mutex.Unlock() 199 200 if r.i2cBuses[bus] == nil { 201 r.i2cBuses[bus], err = sysfs.NewI2cDevice(fmt.Sprintf("/dev/i2c-%d", bus)) 202 } 203 204 return r.i2cBuses[bus], err 205 } 206 207 // GetDefaultBus returns the default i2c bus for this platform 208 func (r *Adaptor) GetDefaultBus() int { 209 return r.i2cDefaultBus 210 } 211 212 // GetSpiConnection returns an spi connection to a device on a specified bus. 213 // Valid bus number is [0..1] which corresponds to /dev/spidev0.0 through /dev/spidev0.1. 214 func (r *Adaptor) GetSpiConnection(busNum, chipNum, mode, bits int, maxSpeed int64) (connection spi.Connection, err error) { 215 r.mutex.Lock() 216 defer r.mutex.Unlock() 217 218 if (busNum < 0) || (busNum > 1) { 219 return nil, fmt.Errorf("Bus number %d out of range", busNum) 220 } 221 222 if r.spiDevices[busNum] == nil { 223 r.spiDevices[busNum], err = spi.GetSpiConnection(busNum, chipNum, mode, bits, maxSpeed) 224 } 225 226 return r.spiDevices[busNum], err 227 } 228 229 // GetSpiDefaultBus returns the default spi bus for this platform. 230 func (r *Adaptor) GetSpiDefaultBus() int { 231 return r.spiDefaultBus 232 } 233 234 // GetSpiDefaultChip returns the default spi chip for this platform. 235 func (r *Adaptor) GetSpiDefaultChip() int { 236 return r.spiDefaultChip 237 } 238 239 // GetSpiDefaultMode returns the default spi mode for this platform. 240 func (r *Adaptor) GetSpiDefaultMode() int { 241 return r.spiDefaultMode 242 } 243 244 // GetSpiDefaultBits returns the default spi number of bits for this platform. 245 func (r *Adaptor) GetSpiDefaultBits() int { 246 return 8 247 } 248 249 // GetSpiDefaultMaxSpeed returns the default spi bus for this platform. 250 func (r *Adaptor) GetSpiDefaultMaxSpeed() int64 { 251 return r.spiDefaultMaxSpeed 252 } 253 254 // PWMPin returns a raspi.PWMPin which provides the sysfs.PWMPinner interface 255 func (r *Adaptor) PWMPin(pin string) (raspiPWMPin sysfs.PWMPinner, err error) { 256 i, err := r.translatePin(pin) 257 if err != nil { 258 return 259 } 260 261 r.mutex.Lock() 262 defer r.mutex.Unlock() 263 264 if r.pwmPins[i] == nil { 265 r.pwmPins[i] = NewPWMPin(strconv.Itoa(i)) 266 r.pwmPins[i].SetPeriod(r.PiBlasterPeriod) 267 } 268 269 return r.pwmPins[i], nil 270 } 271 272 // PwmWrite writes a PWM signal to the specified pin 273 func (r *Adaptor) PwmWrite(pin string, val byte) (err error) { 274 sysfsPin, err := r.PWMPin(pin) 275 if err != nil { 276 return err 277 } 278 279 duty := uint32(gobot.FromScale(float64(val), 0, 255) * float64(r.PiBlasterPeriod)) 280 return sysfsPin.SetDutyCycle(duty) 281 } 282 283 // ServoWrite writes a servo signal to the specified pin 284 func (r *Adaptor) ServoWrite(pin string, angle byte) (err error) { 285 sysfsPin, err := r.PWMPin(pin) 286 if err != nil { 287 return err 288 } 289 290 duty := uint32(gobot.FromScale(float64(angle), 0, 180) * float64(r.PiBlasterPeriod)) 291 return sysfsPin.SetDutyCycle(duty) 292 } 293 294 func (r *Adaptor) translatePin(pin string) (i int, err error) { 295 if val, ok := pins[pin][r.revision]; ok { 296 i = val 297 } else if val, ok := pins[pin]["*"]; ok { 298 i = val 299 } else { 300 err = errors.New("Not a valid pin") 301 return 302 } 303 return 304 }