gobot.io/x/gobot@v1.16.0/platforms/firmata/firmata_adaptor.go (about) 1 package firmata 2 3 import ( 4 "fmt" 5 "io" 6 "strconv" 7 "time" 8 9 "go.bug.st/serial" 10 "gobot.io/x/gobot" 11 "gobot.io/x/gobot/drivers/i2c" 12 "gobot.io/x/gobot/platforms/firmata/client" 13 ) 14 15 type firmataBoard interface { 16 Connect(io.ReadWriteCloser) error 17 Disconnect() error 18 Pins() []client.Pin 19 AnalogWrite(int, int) error 20 SetPinMode(int, int) error 21 ReportAnalog(int, int) error 22 ReportDigital(int, int) error 23 DigitalWrite(int, int) error 24 I2cRead(int, int) error 25 I2cWrite(int, []byte) error 26 I2cConfig(int) error 27 ServoConfig(int, int, int) error 28 WriteSysex(data []byte) error 29 gobot.Eventer 30 } 31 32 type FirmataAdaptor interface { 33 Connect() (err error) 34 Finalize() (err error) 35 Name() string 36 SetName(n string) 37 WriteSysex(data []byte) error 38 gobot.Eventer 39 } 40 41 // Adaptor is the Gobot Adaptor for Firmata based boards 42 type Adaptor struct { 43 name string 44 port string 45 Board firmataBoard 46 conn io.ReadWriteCloser 47 PortOpener func(port string) (io.ReadWriteCloser, error) 48 gobot.Eventer 49 } 50 51 // NewAdaptor returns a new Firmata Adaptor which optionally accepts: 52 // 53 // string: port the Adaptor uses to connect to a serial port with a baude rate of 57600 54 // io.ReadWriteCloser: connection the Adaptor uses to communication with the hardware 55 // 56 // If an io.ReadWriteCloser is not supplied, the Adaptor will open a connection 57 // to a serial port with a baude rate of 57600. If an io.ReadWriteCloser 58 // is supplied, then the Adaptor will use the provided io.ReadWriteCloser and use the 59 // string port as a label to be displayed in the log and api. 60 func NewAdaptor(args ...interface{}) *Adaptor { 61 f := &Adaptor{ 62 name: gobot.DefaultName("Firmata"), 63 port: "", 64 conn: nil, 65 Board: client.New(), 66 PortOpener: func(port string) (io.ReadWriteCloser, error) { 67 return serial.Open(port, &serial.Mode{BaudRate: 57600}) 68 }, 69 Eventer: gobot.NewEventer(), 70 } 71 72 for _, arg := range args { 73 switch arg.(type) { 74 case string: 75 f.port = arg.(string) 76 case io.ReadWriteCloser: 77 f.conn = arg.(io.ReadWriteCloser) 78 } 79 } 80 81 return f 82 } 83 84 // Connect starts a connection to the board. 85 func (f *Adaptor) Connect() (err error) { 86 if f.conn == nil { 87 sp, e := f.PortOpener(f.Port()) 88 if e != nil { 89 return e 90 } 91 f.conn = sp 92 } 93 if err = f.Board.Connect(f.conn); err != nil { 94 return err 95 } 96 97 f.Board.On("SysexResponse", func(data interface{}) { 98 f.Publish("SysexResponse", data) 99 }) 100 101 return 102 } 103 104 // Disconnect closes the io connection to the Board 105 func (f *Adaptor) Disconnect() (err error) { 106 if f.Board != nil { 107 return f.Board.Disconnect() 108 } 109 return nil 110 } 111 112 // Finalize terminates the firmata connection 113 func (f *Adaptor) Finalize() (err error) { 114 err = f.Disconnect() 115 return err 116 } 117 118 // Port returns the Firmata Adaptors port 119 func (f *Adaptor) Port() string { return f.port } 120 121 // Name returns the Firmata Adaptors name 122 func (f *Adaptor) Name() string { return f.name } 123 124 // SetName sets the Firmata Adaptors name 125 func (f *Adaptor) SetName(n string) { f.name = n } 126 127 // ServoConfig sets the pulse width in microseconds for a pin attached to a servo 128 func (f *Adaptor) ServoConfig(pin string, min, max int) error { 129 p, err := strconv.Atoi(pin) 130 if err != nil { 131 return err 132 } 133 134 return f.Board.ServoConfig(p, max, min) 135 } 136 137 // ServoWrite writes the 0-180 degree angle to the specified pin. 138 func (f *Adaptor) ServoWrite(pin string, angle byte) (err error) { 139 p, err := strconv.Atoi(pin) 140 if err != nil { 141 return err 142 } 143 144 if f.Board.Pins()[p].Mode != client.Servo { 145 err = f.Board.SetPinMode(p, client.Servo) 146 if err != nil { 147 return err 148 } 149 } 150 err = f.Board.AnalogWrite(p, int(angle)) 151 return 152 } 153 154 // PwmWrite writes the 0-254 value to the specified pin 155 func (f *Adaptor) PwmWrite(pin string, level byte) (err error) { 156 p, err := strconv.Atoi(pin) 157 if err != nil { 158 return err 159 } 160 161 if f.Board.Pins()[p].Mode != client.Pwm { 162 err = f.Board.SetPinMode(p, client.Pwm) 163 if err != nil { 164 return err 165 } 166 } 167 err = f.Board.AnalogWrite(p, int(level)) 168 return 169 } 170 171 // DigitalWrite writes a value to the pin. Acceptable values are 1 or 0. 172 func (f *Adaptor) DigitalWrite(pin string, level byte) (err error) { 173 p, err := strconv.Atoi(pin) 174 if err != nil { 175 return 176 } 177 178 if f.Board.Pins()[p].Mode != client.Output { 179 err = f.Board.SetPinMode(p, client.Output) 180 if err != nil { 181 return 182 } 183 } 184 185 err = f.Board.DigitalWrite(p, int(level)) 186 return 187 } 188 189 // DigitalRead retrieves digital value from specified pin. 190 // Returns -1 if the response from the board has timed out 191 func (f *Adaptor) DigitalRead(pin string) (val int, err error) { 192 p, err := strconv.Atoi(pin) 193 if err != nil { 194 return 195 } 196 197 if f.Board.Pins()[p].Mode != client.Input { 198 if err = f.Board.SetPinMode(p, client.Input); err != nil { 199 return 200 } 201 if err = f.Board.ReportDigital(p, 1); err != nil { 202 return 203 } 204 <-time.After(10 * time.Millisecond) 205 } 206 207 return f.Board.Pins()[p].Value, nil 208 } 209 210 // AnalogRead retrieves value from analog pin. 211 // Returns -1 if the response from the board has timed out 212 func (f *Adaptor) AnalogRead(pin string) (val int, err error) { 213 p, err := strconv.Atoi(pin) 214 if err != nil { 215 return 216 } 217 218 p = f.digitalPin(p) 219 220 if f.Board.Pins()[p].Mode != client.Analog { 221 if err = f.Board.SetPinMode(p, client.Analog); err != nil { 222 return 223 } 224 225 if err = f.Board.ReportAnalog(p, 1); err != nil { 226 return 227 } 228 <-time.After(10 * time.Millisecond) 229 } 230 231 return f.Board.Pins()[p].Value, nil 232 } 233 234 func (f *Adaptor) WriteSysex(data []byte) error { 235 return f.Board.WriteSysex(data) 236 } 237 238 // digitalPin converts pin number to digital mapping 239 func (f *Adaptor) digitalPin(pin int) int { 240 return pin + 14 241 } 242 243 // GetConnection returns an i2c connection to a device on a specified bus. 244 // Only supports bus number 0 245 func (f *Adaptor) GetConnection(address int, bus int) (connection i2c.Connection, err error) { 246 if bus != 0 { 247 return nil, fmt.Errorf("Invalid bus number %d, only 0 is supported", bus) 248 } 249 err = f.Board.I2cConfig(0) 250 return NewFirmataI2cConnection(f, address), err 251 } 252 253 // GetDefaultBus returns the default i2c bus for this platform 254 func (f *Adaptor) GetDefaultBus() int { 255 return 0 256 }