add i2c implementation

pull/20/head
imle 5 years ago
parent 12356d3840
commit 050bc7a20a

@ -8,6 +8,7 @@ import (
"sync" "sync"
"periph.io/x/conn/v3/gpio" "periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/i2c"
"periph.io/x/conn/v3/onewire" "periph.io/x/conn/v3/onewire"
"periph.io/x/conn/v3/pin" "periph.io/x/conn/v3/pin"
) )
@ -38,16 +39,18 @@ type ClientI interface {
SetSamplingInterval(uint16) error SetSamplingInterval(uint16) error
SetDigitalPinValue(p uint8, value gpio.Level) error SetDigitalPinValue(p uint8, value gpio.Level) error
SendAnalogMappingQuery() (chan AnalogMappingResponse, error) SendAnalogMappingQuery() (chan AnalogMappingResponse, error)
SetI2CMessageChannel(address uint8, ch chan I2CPacket)
WriteI2CData(address uint8, restart bool, data []uint8) error
ReadI2CData(address uint8, restart bool, len uint16) error
ReadI2CRegister(address uint8, restart bool, register uint8, len uint16) error
SendI2CConfig(delayMicroseconds uint8) error
AnalogPinToDigitalPin(p uint8) (uint8, error) AnalogPinToDigitalPin(p uint8) (uint8, error)
SetAnalogIOMessageListener(p uint8, ch chan uint16) (release func(), err error) SetAnalogIOMessageListener(p uint8, ch chan uint16) (release func(), err error)
SetDigitalIOMessageListener(p uint8, ch chan gpio.Level) (release func(), err error) SetDigitalIOMessageListener(p uint8, ch chan gpio.Level) (release func(), err error)
SendAnalogIOMessage(uint8, uint16) error SendAnalogIOMessage(uint8, uint16) error
OpenI2CBus() (i2c.Bus, error)
SetI2CAddressListener(addr uint8, ch chan I2CPacket) (release func(), err error)
WriteI2CData(address uint8, restart bool, data []uint8) error
ReadI2CData(address uint8, restart bool, len uint16) error
ReadI2CRegister(address uint8, restart bool, register uint8, len uint16) error
SendI2CConfig(delayMicroseconds uint8) error
OpenOneWireBus(p uint8) (bus onewire.BusCloser, err error) OpenOneWireBus(p uint8) (bus onewire.BusCloser, err error)
SetOneWireListener(uint8, chan []byte) (release func(), err error) SetOneWireListener(uint8, chan []byte) (release func(), err error)
@ -61,7 +64,9 @@ type Client struct {
board io.ReadWriteCloser board io.ReadWriteCloser
responseChannels map[SysExCmd][]chan []byte responseChannels map[SysExCmd][]chan []byte
sysExListenerChannels map[SysExCmd]chan []byte sysExListenerChannels map[SysExCmd]chan []byte
i2cListeners map[uint8]chan I2CPacket
i2cListeners map[uint8]chan I2CPacket
i2cMU sync.Mutex
onewireListeners map[uint8]chan []byte onewireListeners map[uint8]chan []byte
onewireMU sync.Mutex onewireMU sync.Mutex
@ -587,13 +592,25 @@ func (c *Client) SendI2CConfig(delayMicroseconds uint8) error {
return nil return nil
} }
func (c *Client) releaseI2CAddressListener(addr uint8) {
c.i2cMU.Lock()
defer c.i2cMU.Unlock()
delete(c.i2cListeners, addr)
}
// This function only supports 7-bit I2C addresses // This function only supports 7-bit I2C addresses
func (c *Client) SetI2CMessageChannel(address uint8, ch chan I2CPacket) { func (c *Client) SetI2CAddressListener(addr uint8, ch chan I2CPacket) (release func(), err error) {
if c.i2cListeners[address] != nil { c.i2cMU.Lock()
close(c.i2cListeners[address]) defer c.i2cMU.Unlock()
if c.i2cListeners[addr] != nil {
return nil, ErrI2CAddressListenerNotReleased
} }
c.i2cListeners[address] = ch c.i2cListeners[addr] = ch
return func() { c.releaseI2CAddressListener(addr) }, nil
} }
func (c *Client) releaseAnalogIOMessageListener(p uint8) { func (c *Client) releaseAnalogIOMessageListener(p uint8) {
@ -695,3 +712,7 @@ func (c *Client) GetPinName(p uint8) string {
func (c *Client) GetPinFunctions(p uint8) []pin.Func { func (c *Client) GetPinFunctions(p uint8) []pin.Func {
return c.cr.SupportedPinModes[int(p)] return c.cr.SupportedPinModes[int(p)]
} }
func (c *Client) OpenI2CBus() (i2c.Bus, error) {
return newI2CBus(c)
}

@ -21,4 +21,5 @@ var (
ErrAnalogIOMessagePinOutOfRange = errors.New("analog io message pin number cannot exceed 0xF") ErrAnalogIOMessagePinOutOfRange = errors.New("analog io message pin number cannot exceed 0xF")
ErrDigitalIOMessagePinOutOfRange = errors.New("digital io message port number cannot exceed 0xF") ErrDigitalIOMessagePinOutOfRange = errors.New("digital io message port number cannot exceed 0xF")
ErrPinListenerNotReleased = errors.New("pin listener is already set for pin") ErrPinListenerNotReleased = errors.New("pin listener is already set for pin")
ErrI2CAddressListenerNotReleased = errors.New("address listener is already set")
) )

@ -1,33 +1,86 @@
package firmata package firmata
import ( import (
"periph.io/x/conn/v3/gpio" "errors"
"fmt"
"math"
"sync"
"periph.io/x/conn/v3/physic" "periph.io/x/conn/v3/physic"
) )
var (
Err10BitAddressingNotSupported = errors.New("10-bit addressing not supported")
)
type I2CBus struct { type I2CBus struct {
c ClientI
mu sync.Mutex
} }
func (i *I2CBus) SCL() gpio.PinIO { func newI2CBus(c ClientI) (*I2CBus, error) {
panic("implement me") b := &I2CBus{
} c: c,
}
func (i *I2CBus) SDA() gpio.PinIO { err := c.SendI2CConfig(0)
panic("implement me") if err != nil {
return nil, err
}
return b, nil
} }
func (i *I2CBus) Close() error { func (b *I2CBus) Close() error {
panic("implement me") panic("implement me")
} }
func (i *I2CBus) String() string { func (b *I2CBus) String() string {
panic("implement me") panic("implement me")
} }
func (i *I2CBus) Tx(addr uint16, w, r []byte) error { func (b *I2CBus) Tx(addr uint16, w, r []byte) error {
panic("implement me") if addr >= 0b11111111 {
return fmt.Errorf("%w: 0x%04X", Err10BitAddressingNotSupported, addr)
}
if len(r) > math.MaxUint16 {
return fmt.Errorf("%w: cannot reach more than %d bytes", ErrValueOutOfRange, math.MaxUint16)
}
b.mu.Lock()
defer b.mu.Unlock()
ch := make(chan I2CPacket)
defer close(ch)
address := uint8(addr)
release, err := b.c.SetI2CAddressListener(address, ch)
if err != nil {
return err
}
defer release()
if len(w) > 0 {
if err := b.c.WriteI2CData(address, false, w); err != nil {
return err
}
}
if len(r) > 0 {
if err := b.c.ReadI2CData(address, false, uint16(len(r))); err != nil {
return err
}
pck := <-ch
copy(r, pck.Data)
}
return nil
} }
func (i *I2CBus) SetSpeed(f physic.Frequency) error { func (b *I2CBus) SetSpeed(f physic.Frequency) error {
panic("implement me") return fmt.Errorf("%w: firmata does not support setting bus frequency", ErrUnsupportedFeature)
} }

Loading…
Cancel
Save