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 }