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  }