gobot.io/x/gobot/v2@v2.1.0/drivers/spi/spi_connection.go (about) 1 package spi 2 3 import ( 4 "fmt" 5 "sync" 6 7 "gobot.io/x/gobot/v2" 8 ) 9 10 const ( 11 spiDebugByte = false 12 spiDebugBlock = false 13 ) 14 15 // spiConnection is the common implementation of the SPI bus interface. 16 type spiConnection struct { 17 spiSystem gobot.SpiSystemDevicer 18 mutex sync.Mutex 19 } 20 21 // NewConnection uses the given SPI system device and provides it as gobot.SpiOperations 22 // and Implements gobot.BusOperations. 23 func NewConnection(spiSystem gobot.SpiSystemDevicer) *spiConnection { 24 return &spiConnection{spiSystem: spiSystem} 25 } 26 27 // ReadCommandData uses the SPI device TX to send/receive data. Implements gobot.SpiOperations 28 // On write command, the first byte normally contains the address and mode. 29 // On read data, the return value is most likely one byte behind the command. 30 // The length of command and data needs to be the same (except data is nil). 31 func (c *spiConnection) ReadCommandData(command []byte, data []byte) error { 32 c.mutex.Lock() 33 defer c.mutex.Unlock() 34 35 return c.txRxAndCheckReadLength(command, data) 36 } 37 38 // Close connection to underlying SPI device. 39 func (c *spiConnection) Close() error { 40 c.mutex.Lock() 41 defer c.mutex.Unlock() 42 43 return c.spiSystem.Close() 44 } 45 46 // ReadByteData reads a byte from the given register of SPI device. Implements gobot.BusOperations. 47 func (c *spiConnection) ReadByteData(reg uint8) (uint8, error) { 48 c.mutex.Lock() 49 defer c.mutex.Unlock() 50 51 buf := []byte{0x0} 52 if err := c.readAlignedBlockData(reg, buf); err != nil { 53 return 0, err 54 } 55 56 if spiDebugByte { 57 fmt.Printf("ReadByteData: register 0x%02X/0x%02X : 0x%02X %dd\n", reg, reg&0x7F>>1, buf[0], buf[0]) 58 } 59 return buf[0], nil 60 } 61 62 // ReadBlockData fills the given buffer with reads starting from the given register of SPI device. 63 // Implements gobot.BusOperations. 64 func (c *spiConnection) ReadBlockData(reg uint8, data []byte) error { 65 c.mutex.Lock() 66 defer c.mutex.Unlock() 67 68 if err := c.readAlignedBlockData(reg, data); err != nil { 69 return err 70 } 71 72 if spiDebugBlock { 73 fmt.Printf("ReadBlockData: register 0x%02X/0x%02X : %v\n", reg, reg&0x7F>>1, data) 74 } 75 return nil 76 } 77 78 // WriteByte writes the given byte value to the current register of SPI device. Implements gobot.BusOperations. 79 func (c *spiConnection) WriteByte(val byte) error { 80 c.mutex.Lock() 81 defer c.mutex.Unlock() 82 83 return c.writeBytes([]byte{val}) 84 } 85 86 // WriteByteData writes the given byte value to the given register of SPI device. Implements gobot.BusOperations. 87 func (c *spiConnection) WriteByteData(reg byte, data byte) error { 88 c.mutex.Lock() 89 defer c.mutex.Unlock() 90 91 return c.writeBytes([]byte{reg, data}) 92 } 93 94 // WriteBlockData writes the given data starting from the given register of SPI device. Implements gobot.BusOperations. 95 func (c *spiConnection) WriteBlockData(reg byte, data []byte) error { 96 c.mutex.Lock() 97 defer c.mutex.Unlock() 98 99 buf := make([]byte, len(data)+1) 100 copy(buf[1:], data) 101 buf[0] = reg 102 return c.writeBytes(buf) 103 } 104 105 // WriteBytes writes the given data starting from the current register of bus device. Implements gobot.BusOperations. 106 func (c *spiConnection) WriteBytes(data []byte) error { 107 c.mutex.Lock() 108 defer c.mutex.Unlock() 109 110 return c.writeBytes(data) 111 } 112 113 func (c *spiConnection) readAlignedBlockData(reg uint8, data []byte) error { 114 // length of TX needs to equal length of RX 115 // the read value is one cycle behind the write, so for n bytes to read, we need n+1 bytes (to read and write) 116 buflen := len(data) + 1 117 writeBuf := make([]byte, buflen) 118 readBuf := make([]byte, buflen) 119 writeBuf[0] = reg 120 if err := c.txRxAndCheckReadLength(writeBuf, readBuf); err != nil { 121 return err 122 } 123 copy(data, readBuf[1:]) 124 return nil 125 } 126 127 func (c *spiConnection) writeBytes(data []byte) error { 128 return c.txRxAndCheckReadLength(data, nil) 129 } 130 131 func (c *spiConnection) txRxAndCheckReadLength(tx []byte, rx []byte) error { 132 dataLen := len(rx) 133 if err := c.spiSystem.TxRx(tx, rx); err != nil { 134 return err 135 } 136 if len(rx) != dataLen { 137 return fmt.Errorf("Read length (%d) differ to expected (%d)", len(rx), dataLen) 138 } 139 return nil 140 }