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  }