gobot.io/x/gobot/v2@v2.1.0/platforms/firmata/firmata_i2c.go (about) 1 package firmata 2 3 import ( 4 "fmt" 5 "sync" 6 7 "gobot.io/x/gobot/v2/platforms/firmata/client" 8 ) 9 10 // firmataI2cConnection implements the interface gobot.I2cOperations 11 type firmataI2cConnection struct { 12 address int 13 adaptor *Adaptor 14 mtx sync.Mutex 15 } 16 17 // NewFirmataI2cConnection creates an I2C connection to an I2C device at 18 // the specified address 19 func NewFirmataI2cConnection(adaptor *Adaptor, address int) (connection *firmataI2cConnection) { 20 return &firmataI2cConnection{adaptor: adaptor, address: address} 21 } 22 23 // Read tries to read a full buffer from the i2c device. 24 // Returns an empty array if the response from the board has timed out. 25 func (c *firmataI2cConnection) Read(b []byte) (read int, err error) { 26 c.mtx.Lock() 27 defer c.mtx.Unlock() 28 29 return c.readInternal(b) 30 } 31 32 // Write writes the buffer content in data to the i2c device. 33 func (c *firmataI2cConnection) Write(data []byte) (written int, err error) { 34 c.mtx.Lock() 35 defer c.mtx.Unlock() 36 37 return c.writeInternal(data) 38 } 39 40 // Close do nothing than return nil. 41 func (c *firmataI2cConnection) Close() error { 42 return nil 43 } 44 45 // ReadByte reads one byte from the i2c device. 46 func (c *firmataI2cConnection) ReadByte() (byte, error) { 47 c.mtx.Lock() 48 defer c.mtx.Unlock() 49 50 buf := []byte{0} 51 if err := c.readAndCheckCount(buf); err != nil { 52 return 0, err 53 } 54 return buf[0], nil 55 } 56 57 // ReadByteData reads one byte of the given register address from the i2c device. 58 // TODO: implement the specification, because some devices will not work with this 59 // 60 // current: "S Addr Wr [A] Comm [A] P S Addr Rd [A] [Data] NA P" 61 // required: "S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P" 62 func (c *firmataI2cConnection) ReadByteData(reg uint8) (uint8, error) { 63 c.mtx.Lock() 64 defer c.mtx.Unlock() 65 66 if err := c.writeAndCheckCount([]byte{reg}); err != nil { 67 return 0, err 68 } 69 70 buf := []byte{0} 71 if err := c.readAndCheckCount(buf); err != nil { 72 return 0, err 73 } 74 return buf[0], nil 75 } 76 77 // ReadWordData reads two bytes of the given register address from the i2c device. 78 // TODO: implement the specification, because some devices will not work with this 79 // 80 // current: "S Addr Wr [A] Comm [A] P S Addr Rd [A] [DataLow] A [DataHigh] NA P" 81 // required: "S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P" 82 func (c *firmataI2cConnection) ReadWordData(reg uint8) (uint16, error) { 83 c.mtx.Lock() 84 defer c.mtx.Unlock() 85 86 if err := c.writeAndCheckCount([]byte{reg}); err != nil { 87 return uint16(0), err 88 } 89 90 buf := []byte{0, 0} 91 if err := c.readAndCheckCount(buf); err != nil { 92 return uint16(0), err 93 } 94 low, high := buf[0], buf[1] 95 return (uint16(high) << 8) | uint16(low), nil 96 } 97 98 // ReadBlockData reads a block of maximum 32 bytes from the given register address of the i2c device. 99 // TODO: implement the specification, because some devices will not work with this 100 // 101 // current: "S Addr Wr [A] Comm [A] P S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P" 102 // required: "S Addr Wr [A] Comm [A] S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P" 103 func (c *firmataI2cConnection) ReadBlockData(reg uint8, data []byte) error { 104 c.mtx.Lock() 105 defer c.mtx.Unlock() 106 107 if err := c.writeAndCheckCount([]byte{reg}); err != nil { 108 return err 109 } 110 111 if len(data) > 32 { 112 data = data[:32] 113 } 114 return c.readAndCheckCount(data) 115 } 116 117 // WriteByte writes one byte to the i2c device. 118 func (c *firmataI2cConnection) WriteByte(val byte) error { 119 c.mtx.Lock() 120 defer c.mtx.Unlock() 121 122 buf := []byte{val} 123 return c.writeAndCheckCount(buf) 124 } 125 126 // WriteByteData writes one byte to the given register address of the i2c device. 127 func (c *firmataI2cConnection) WriteByteData(reg uint8, val byte) error { 128 c.mtx.Lock() 129 defer c.mtx.Unlock() 130 131 buf := []byte{reg, val} 132 return c.writeAndCheckCount(buf) 133 } 134 135 // WriteWordData writes two bytes to the given register address of the i2c device. 136 func (c *firmataI2cConnection) WriteWordData(reg uint8, val uint16) error { 137 c.mtx.Lock() 138 defer c.mtx.Unlock() 139 140 low := uint8(val & 0xff) 141 high := uint8((val >> 8) & 0xff) 142 buf := []byte{reg, low, high} 143 return c.writeAndCheckCount(buf) 144 } 145 146 // WriteBlockData writes a block of maximum 32 bytes to the given register address of the i2c device. 147 func (c *firmataI2cConnection) WriteBlockData(reg uint8, data []byte) error { 148 c.mtx.Lock() 149 defer c.mtx.Unlock() 150 151 if len(data) > 32 { 152 data = data[:32] 153 } 154 155 buf := make([]byte, len(data)+1) 156 copy(buf[1:], data) 157 buf[0] = reg 158 return c.writeAndCheckCount(buf) 159 } 160 161 // WriteBytes writes a block of maximum 32 bytes to the current register address of the i2c device. 162 func (c *firmataI2cConnection) WriteBytes(buf []byte) error { 163 c.mtx.Lock() 164 defer c.mtx.Unlock() 165 166 if len(buf) > 32 { 167 buf = buf[:32] 168 } 169 170 return c.writeAndCheckCount(buf) 171 } 172 173 func (c *firmataI2cConnection) readAndCheckCount(buf []byte) error { 174 countRead, err := c.readInternal(buf) 175 if err != nil { 176 return err 177 } 178 expectedCount := len(buf) 179 if countRead != expectedCount { 180 return fmt.Errorf("Firmata i2c read %d bytes, expected %d bytes", countRead, expectedCount) 181 } 182 return nil 183 } 184 185 func (c *firmataI2cConnection) writeAndCheckCount(buf []byte) error { 186 countWritten, err := c.writeInternal(buf) 187 if err != nil { 188 return err 189 } 190 expectedCount := len(buf) 191 if countWritten != expectedCount { 192 return fmt.Errorf("Firmata i2c write %d bytes, expected %d bytes", countWritten, expectedCount) 193 } 194 return nil 195 } 196 197 func (c *firmataI2cConnection) readInternal(b []byte) (read int, err error) { 198 ret := make(chan []byte) 199 200 if err = c.adaptor.Board.I2cRead(c.address, len(b)); err != nil { 201 return 202 } 203 204 c.adaptor.Board.Once(c.adaptor.Board.Event("I2cReply"), func(data interface{}) { 205 ret <- data.(client.I2cReply).Data 206 }) 207 208 result := <-ret 209 copy(b, result) 210 211 read = len(result) 212 213 return 214 } 215 216 func (c *firmataI2cConnection) writeInternal(data []byte) (written int, err error) { 217 var chunk []byte 218 for len(data) >= 16 { 219 chunk, data = data[:16], data[16:] 220 err = c.adaptor.Board.I2cWrite(c.address, chunk) 221 if err != nil { 222 return 223 } 224 written += len(chunk) 225 } 226 if len(data) > 0 { 227 err = c.adaptor.Board.I2cWrite(c.address, data[:]) 228 written += len(data) 229 } 230 return 231 }