gobot.io/x/gobot/v2@v2.1.0/platforms/rockpi/rockpi_adaptor.go (about) 1 package rockpi 2 3 import ( 4 "errors" 5 "fmt" 6 "sync" 7 8 multierror "github.com/hashicorp/go-multierror" 9 "gobot.io/x/gobot/v2" 10 "gobot.io/x/gobot/v2/platforms/adaptors" 11 "gobot.io/x/gobot/v2/system" 12 ) 13 14 const ( 15 procDeviceTreeModel = "/proc/device-tree/model" 16 17 defaultI2cBusNumber = 7 18 19 defaultSpiBusNumber = 1 20 defaultSpiChipNumber = 0 21 defaultSpiMode = 0 22 defaultSpiBitsNumber = 8 23 defaultSpiMaxSpeed = 500000 24 ) 25 26 // Adaptor is the Gobot Adaptor for Radxa's Rock Pi. 27 type Adaptor struct { 28 name string 29 mutex sync.Mutex 30 sys *system.Accesser 31 revision string 32 *adaptors.DigitalPinsAdaptor 33 *adaptors.I2cBusAdaptor 34 *adaptors.SpiBusAdaptor 35 spiDefaultMaxSpeed int64 36 } 37 38 // NewAdaptor creates a RockPi Adaptor 39 // Do not forget to enable the required overlays in /boot/hw_initfc.conf! 40 // See https://wiki.radxa.com/Rockpi4/dev/libmraa 41 // 42 // Optional parameters: 43 // 44 // adaptors.WithGpiodAccess(): use character device gpiod driver instead of the default sysfs (does NOT work on RockPi4C+!) 45 // adaptors.WithSpiGpioAccess(sclk, nss, mosi, miso): use GPIO's instead of /dev/spidev#.# 46 // adaptors.WithGpiosActiveLow(pin's): invert the pin behavior 47 func NewAdaptor(opts ...func(adaptors.Optioner)) *Adaptor { 48 sys := system.NewAccesser() 49 c := &Adaptor{ 50 name: gobot.DefaultName("RockPi"), 51 sys: sys, 52 } 53 c.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, c.getPinTranslatorFunction(), opts...) 54 c.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, c.validateI2cBusNumber, defaultI2cBusNumber) 55 c.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, c.validateSpiBusNumber, defaultSpiBusNumber, defaultSpiChipNumber, 56 defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed) 57 return c 58 } 59 60 // Name returns the Adaptor's name 61 func (c *Adaptor) Name() string { 62 c.mutex.Lock() 63 defer c.mutex.Unlock() 64 65 return c.name 66 } 67 68 // SetName sets the Adaptor's name 69 func (c *Adaptor) SetName(n string) { 70 c.mutex.Lock() 71 defer c.mutex.Unlock() 72 73 c.name = n 74 } 75 76 // Connect create new connection to board and pins. 77 func (c *Adaptor) Connect() error { 78 c.mutex.Lock() 79 defer c.mutex.Unlock() 80 81 if err := c.SpiBusAdaptor.Connect(); err != nil { 82 return err 83 } 84 85 if err := c.I2cBusAdaptor.Connect(); err != nil { 86 return err 87 } 88 89 return c.DigitalPinsAdaptor.Connect() 90 } 91 92 // Finalize closes connection to board and pins 93 func (c *Adaptor) Finalize() error { 94 c.mutex.Lock() 95 defer c.mutex.Unlock() 96 97 err := c.DigitalPinsAdaptor.Finalize() 98 99 if e := c.I2cBusAdaptor.Finalize(); e != nil { 100 err = multierror.Append(err, e) 101 } 102 103 if e := c.SpiBusAdaptor.Finalize(); e != nil { 104 err = multierror.Append(err, e) 105 } 106 return err 107 } 108 109 // The RockPi4 has 2 SPI buses: 1, 2. See https://wiki.radxa.com/Rock4/hardware/gpio 110 // This could change in the future with other revisions! 111 func (c *Adaptor) validateSpiBusNumber(busNr int) error { 112 if busNr != 1 && busNr != 2 { 113 return fmt.Errorf("SPI Bus number %d invalid: only 1, 2 supported by current Rockchip.", busNr) 114 } 115 return nil 116 } 117 118 // The RockPi4 has 3 I2C buses: 2, 6, 7. See https://wiki.radxa.com/Rock4/hardware/gpio 119 // This could change in the future with other revisions! 120 func (c *Adaptor) validateI2cBusNumber(busNr int) error { 121 if busNr != 2 && busNr != 6 && busNr != 7 { 122 return fmt.Errorf("I2C Bus number %d invalid: only 2, 6, 7 supported by current Rockchip.", busNr) 123 } 124 return nil 125 } 126 127 func (c *Adaptor) getPinTranslatorFunction() func(string) (string, int, error) { 128 return func(pin string) (chip string, line int, err error) { 129 if val, ok := pins[pin][c.readRevision()]; ok { 130 line = val 131 } else if val, ok := pins[pin]["*"]; ok { 132 line = val 133 } else { 134 err = errors.New("Not a valid pin") 135 return 136 } 137 return "", line, nil 138 } 139 } 140 141 func (c *Adaptor) readRevision() string { 142 if c.revision == "" { 143 content, err := c.sys.ReadFile(procDeviceTreeModel) 144 if err != nil { 145 return c.revision 146 } 147 model := string(content) 148 switch model { 149 case "Radxa ROCK 4": 150 c.revision = "4" 151 case "Radxa ROCK 4C+": 152 c.revision = "4C+" 153 default: 154 c.revision = "4" 155 } 156 } 157 158 return c.revision 159 }