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  }