gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/i2c_driver.go (about) 1 package i2c 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "strconv" 7 "sync" 8 9 "gobot.io/x/gobot/v2" 10 ) 11 12 // Config is the interface to set and get I2C device related parameters. 13 type Config interface { 14 // SetBus sets which bus to use 15 SetBus(bus int) 16 17 // GetBusOrDefault gets which bus to use 18 GetBusOrDefault(def int) int 19 20 // SetAddress sets which address to use 21 SetAddress(address int) 22 23 // GetAddressOrDefault gets which address to use 24 GetAddressOrDefault(def int) int 25 } 26 27 // Connector lets adaptors (platforms) provide the interface for Drivers to get access to the I2C buses on platforms 28 // that support I2C. The "I2C" specifier is part of the name to differentiate to SPI at platform level. 29 type Connector interface { 30 // GetI2cConnection creates and returns a connection to device at the specified address 31 // and bus. Bus numbering starts at index 0, the range of valid buses is 32 // platform specific. 33 GetI2cConnection(address int, busNr int) (device Connection, err error) 34 35 // DefaultI2cBus returns the default I2C bus index 36 DefaultI2cBus() int 37 } 38 39 // Driver implements the interface gobot.Driver. 40 type Driver struct { 41 name string 42 defaultAddress int 43 connector Connector 44 connection Connection 45 afterStart func() error 46 beforeHalt func() error 47 Config 48 gobot.Commander 49 mutex *sync.Mutex // mutex often needed to ensure that write-read sequences are not interrupted 50 } 51 52 // NewDriver creates a new generic and basic i2c gobot driver. 53 func NewDriver(c Connector, name string, address int, options ...func(Config)) *Driver { 54 d := &Driver{ 55 name: gobot.DefaultName(name), 56 defaultAddress: address, 57 connector: c, 58 afterStart: func() error { return nil }, 59 beforeHalt: func() error { return nil }, 60 Config: NewConfig(), 61 Commander: gobot.NewCommander(), 62 mutex: &sync.Mutex{}, 63 } 64 65 for _, option := range options { 66 option(d) 67 } 68 69 return d 70 } 71 72 // Name returns the name of the i2c device. 73 func (d *Driver) Name() string { 74 return d.name 75 } 76 77 // SetName sets the name of the i2c device. 78 func (d *Driver) SetName(name string) { 79 d.name = name 80 } 81 82 // Connection returns the connection of the i2c device. 83 func (d *Driver) Connection() gobot.Connection { 84 return d.connector.(gobot.Connection) 85 } 86 87 // Start initializes the i2c device. 88 func (d *Driver) Start() error { 89 d.mutex.Lock() 90 defer d.mutex.Unlock() 91 92 var err error 93 bus := d.GetBusOrDefault(d.connector.DefaultI2cBus()) 94 address := d.GetAddressOrDefault(int(d.defaultAddress)) 95 96 if d.connection, err = d.connector.GetI2cConnection(address, bus); err != nil { 97 return err 98 } 99 100 return d.afterStart() 101 } 102 103 // Halt halts the i2c device. 104 func (d *Driver) Halt() error { 105 d.mutex.Lock() 106 defer d.mutex.Unlock() 107 108 if err := d.beforeHalt(); err != nil { 109 return err 110 } 111 112 // currently there is nothing to do here for the driver 113 return nil 114 } 115 116 // Write implements a simple write mechanism, starting from the given register of an i2c device. 117 func (d *Driver) Write(pin string, val int) error { 118 d.mutex.Lock() 119 defer d.mutex.Unlock() 120 121 register, err := driverParseRegister(pin) 122 if err != nil { 123 return err 124 } 125 126 if val > 0xFFFF { 127 buf := make([]byte, 4) 128 binary.LittleEndian.PutUint32(buf, uint32(val)) 129 return d.connection.WriteBlockData(register, buf) 130 } 131 if val > 0xFF { 132 return d.connection.WriteWordData(register, uint16(val)) 133 } 134 return d.connection.WriteByteData(register, uint8(val)) 135 } 136 137 // Read implements a simple read mechanism from the given register of an i2c device. 138 func (d *Driver) Read(pin string) (int, error) { 139 d.mutex.Lock() 140 defer d.mutex.Unlock() 141 142 register, err := driverParseRegister(pin) 143 if err != nil { 144 return 0, err 145 } 146 147 val, err := d.connection.ReadByteData(register) 148 if err != nil { 149 return 0, err 150 } 151 152 return int(val), nil 153 } 154 155 func driverParseRegister(pin string) (uint8, error) { 156 register, err := strconv.ParseUint(pin, 10, 8) 157 if err != nil { 158 return 0, fmt.Errorf("Could not parse the register from given pin '%s'", pin) 159 } 160 return uint8(register), nil 161 }