gobot.io/x/gobot@v1.16.0/platforms/intel-iot/joule/joule_adaptor.go (about)

     1  package joule
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sync"
     7  
     8  	multierror "github.com/hashicorp/go-multierror"
     9  	"gobot.io/x/gobot"
    10  	"gobot.io/x/gobot/drivers/i2c"
    11  	"gobot.io/x/gobot/sysfs"
    12  )
    13  
    14  type sysfsPin struct {
    15  	pin    int
    16  	pwmPin int
    17  }
    18  
    19  // Adaptor represents an Intel Joule
    20  type Adaptor struct {
    21  	name        string
    22  	digitalPins map[int]*sysfs.DigitalPin
    23  	pwmPins     map[int]*sysfs.PWMPin
    24  	i2cBuses    [3]i2c.I2cDevice
    25  	connect     func(e *Adaptor) (err error)
    26  	mutex       *sync.Mutex
    27  }
    28  
    29  // NewAdaptor returns a new Joule Adaptor
    30  func NewAdaptor() *Adaptor {
    31  	return &Adaptor{
    32  		name: gobot.DefaultName("Joule"),
    33  		connect: func(e *Adaptor) (err error) {
    34  			return
    35  		},
    36  		mutex: &sync.Mutex{},
    37  	}
    38  }
    39  
    40  // Name returns the Adaptors name
    41  func (e *Adaptor) Name() string { return e.name }
    42  
    43  // SetName sets the Adaptors name
    44  func (e *Adaptor) SetName(n string) { e.name = n }
    45  
    46  // Connect initializes the Joule for use with the Arduino beakout board
    47  func (e *Adaptor) Connect() (err error) {
    48  	e.mutex.Lock()
    49  	defer e.mutex.Unlock()
    50  
    51  	e.digitalPins = make(map[int]*sysfs.DigitalPin)
    52  	e.pwmPins = make(map[int]*sysfs.PWMPin)
    53  	err = e.connect(e)
    54  	return
    55  }
    56  
    57  // Finalize releases all i2c devices and exported digital and pwm pins.
    58  func (e *Adaptor) Finalize() (err error) {
    59  	e.mutex.Lock()
    60  	defer e.mutex.Unlock()
    61  
    62  	for _, pin := range e.digitalPins {
    63  		if pin != nil {
    64  			if errs := pin.Unexport(); errs != nil {
    65  				err = multierror.Append(err, errs)
    66  			}
    67  		}
    68  	}
    69  	for _, pin := range e.pwmPins {
    70  		if pin != nil {
    71  			if errs := pin.Enable(false); errs != nil {
    72  				err = multierror.Append(err, errs)
    73  			}
    74  			if errs := pin.Unexport(); errs != nil {
    75  				err = multierror.Append(err, errs)
    76  			}
    77  		}
    78  	}
    79  	for _, bus := range e.i2cBuses {
    80  		if bus != nil {
    81  			if errs := bus.Close(); errs != nil {
    82  				err = multierror.Append(err, errs)
    83  			}
    84  		}
    85  	}
    86  	return
    87  }
    88  
    89  // digitalPin returns matched digitalPin for specified values
    90  func (e *Adaptor) DigitalPin(pin string, dir string) (sysfsPin sysfs.DigitalPinner, err error) {
    91  	e.mutex.Lock()
    92  	defer e.mutex.Unlock()
    93  
    94  	i := sysfsPinMap[pin]
    95  	if e.digitalPins[i.pin] == nil {
    96  		e.digitalPins[i.pin] = sysfs.NewDigitalPin(i.pin)
    97  		if err = e.digitalPins[i.pin].Export(); err != nil {
    98  			return
    99  		}
   100  	}
   101  
   102  	if dir == "in" {
   103  		if err = e.digitalPins[i.pin].Direction(sysfs.IN); err != nil {
   104  			return
   105  		}
   106  	} else if dir == "out" {
   107  		if err = e.digitalPins[i.pin].Direction(sysfs.OUT); err != nil {
   108  			return
   109  		}
   110  	}
   111  	return e.digitalPins[i.pin], nil
   112  }
   113  
   114  // DigitalRead reads digital value from pin
   115  func (e *Adaptor) DigitalRead(pin string) (i int, err error) {
   116  	sysfsPin, err := e.DigitalPin(pin, "in")
   117  	if err != nil {
   118  		return
   119  	}
   120  	return sysfsPin.Read()
   121  }
   122  
   123  // DigitalWrite writes a value to the pin. Acceptable values are 1 or 0.
   124  func (e *Adaptor) DigitalWrite(pin string, val byte) (err error) {
   125  	sysfsPin, err := e.DigitalPin(pin, "out")
   126  	if err != nil {
   127  		return
   128  	}
   129  	return sysfsPin.Write(int(val))
   130  }
   131  
   132  // PwmWrite writes the 0-254 value to the specified pin
   133  func (e *Adaptor) PwmWrite(pin string, val byte) (err error) {
   134  	pwmPin, err := e.PWMPin(pin)
   135  	if err != nil {
   136  		return
   137  	}
   138  	period, err := pwmPin.Period()
   139  	if err != nil {
   140  		return err
   141  	}
   142  	duty := gobot.FromScale(float64(val), 0, 255.0)
   143  	return pwmPin.SetDutyCycle(uint32(float64(period) * duty))
   144  }
   145  
   146  // PWMPin returns a sysfs.PWMPin
   147  func (e *Adaptor) PWMPin(pin string) (sysfsPin sysfs.PWMPinner, err error) {
   148  	e.mutex.Lock()
   149  	defer e.mutex.Unlock()
   150  
   151  	sysPin, ok := sysfsPinMap[pin]
   152  	if !ok {
   153  		err = errors.New("Not a valid pin")
   154  		return
   155  	}
   156  	if sysPin.pwmPin != -1 {
   157  		if e.pwmPins[sysPin.pwmPin] == nil {
   158  			e.pwmPins[sysPin.pwmPin] = sysfs.NewPWMPin(sysPin.pwmPin)
   159  			if err = e.pwmPins[sysPin.pwmPin].Export(); err != nil {
   160  				return
   161  			}
   162  			if err = e.pwmPins[sysPin.pwmPin].SetPeriod(10000000); err != nil {
   163  				return
   164  			}
   165  			if err = e.pwmPins[sysPin.pwmPin].Enable(true); err != nil {
   166  				return
   167  			}
   168  		}
   169  
   170  		sysfsPin = e.pwmPins[sysPin.pwmPin]
   171  		return
   172  	}
   173  	err = errors.New("Not a PWM pin")
   174  	return
   175  }
   176  
   177  // GetConnection returns an i2c connection to a device on a specified bus.
   178  // Valid bus number is [0..2] which corresponds to /dev/i2c-0 through /dev/i2c-2.
   179  func (e *Adaptor) GetConnection(address int, bus int) (connection i2c.Connection, err error) {
   180  	if (bus < 0) || (bus > 2) {
   181  		return nil, fmt.Errorf("Bus number %d out of range", bus)
   182  	}
   183  	if e.i2cBuses[bus] == nil {
   184  		e.i2cBuses[bus], err = sysfs.NewI2cDevice(fmt.Sprintf("/dev/i2c-%d", bus))
   185  	}
   186  	return i2c.NewConnection(e.i2cBuses[bus], address), err
   187  }
   188  
   189  // GetDefaultBus returns the default i2c bus for this platform
   190  func (e *Adaptor) GetDefaultBus() int {
   191  	return 0
   192  }