gobot.io/x/gobot/v2@v2.1.0/platforms/beaglebone/beaglebone_adaptor_test.go (about)

     1  package beaglebone
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  
     9  	"gobot.io/x/gobot/v2"
    10  	"gobot.io/x/gobot/v2/drivers/aio"
    11  	"gobot.io/x/gobot/v2/drivers/gpio"
    12  	"gobot.io/x/gobot/v2/drivers/i2c"
    13  	"gobot.io/x/gobot/v2/drivers/spi"
    14  	"gobot.io/x/gobot/v2/gobottest"
    15  	"gobot.io/x/gobot/v2/system"
    16  )
    17  
    18  // make sure that this Adaptor fulfills all the required interfaces
    19  var _ gobot.Adaptor = (*Adaptor)(nil)
    20  var _ gobot.DigitalPinnerProvider = (*Adaptor)(nil)
    21  var _ gobot.PWMPinnerProvider = (*Adaptor)(nil)
    22  var _ gpio.DigitalReader = (*Adaptor)(nil)
    23  var _ gpio.DigitalWriter = (*Adaptor)(nil)
    24  var _ aio.AnalogReader = (*Adaptor)(nil)
    25  var _ gpio.PwmWriter = (*Adaptor)(nil)
    26  var _ gpio.ServoWriter = (*Adaptor)(nil)
    27  var _ i2c.Connector = (*Adaptor)(nil)
    28  var _ spi.Connector = (*Adaptor)(nil)
    29  
    30  func initTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) {
    31  	a := NewAdaptor()
    32  	fs := a.sys.UseMockFilesystem(mockPaths)
    33  	if err := a.Connect(); err != nil {
    34  		panic(err)
    35  	}
    36  	return a, fs
    37  }
    38  
    39  func TestPWM(t *testing.T) {
    40  	mockPaths := []string{
    41  		"/sys/devices/platform/ocp/ocp:P9_22_pinmux/state",
    42  		"/sys/devices/platform/ocp/ocp:P9_21_pinmux/state",
    43  		"/sys/bus/iio/devices/iio:device0/in_voltage1_raw",
    44  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/export",
    45  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/unexport",
    46  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm0/enable",
    47  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm0/period",
    48  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm0/duty_cycle",
    49  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm0/polarity",
    50  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm1/enable",
    51  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm1/period",
    52  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm1/duty_cycle",
    53  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm1/polarity",
    54  	}
    55  
    56  	a, fs := initTestAdaptorWithMockedFilesystem(mockPaths)
    57  
    58  	gobottest.Assert(t, a.PwmWrite("P9_99", 175), errors.New("'P9_99' is not a valid id for a PWM pin"))
    59  	a.PwmWrite("P9_21", 175)
    60  	gobottest.Assert(
    61  		t,
    62  		fs.Files["/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm1/period"].Contents,
    63  		"500000",
    64  	)
    65  	gobottest.Assert(
    66  		t,
    67  		fs.Files["/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm1/duty_cycle"].Contents,
    68  		"343137",
    69  	)
    70  
    71  	a.ServoWrite("P9_21", 100)
    72  	gobottest.Assert(
    73  		t,
    74  		fs.Files["/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm1/period"].Contents,
    75  		"500000",
    76  	)
    77  	gobottest.Assert(
    78  		t,
    79  		fs.Files["/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/pwm1/duty_cycle"].Contents,
    80  		"66666",
    81  	)
    82  
    83  	gobottest.Assert(t, a.Finalize(), nil)
    84  }
    85  
    86  func TestAnalog(t *testing.T) {
    87  	mockPaths := []string{
    88  		"/sys/bus/iio/devices/iio:device0/in_voltage1_raw",
    89  	}
    90  
    91  	a, fs := initTestAdaptorWithMockedFilesystem(mockPaths)
    92  
    93  	fs.Files["/sys/bus/iio/devices/iio:device0/in_voltage1_raw"].Contents = "567\n"
    94  	i, err := a.AnalogRead("P9_40")
    95  	gobottest.Assert(t, i, 567)
    96  	gobottest.Assert(t, err, nil)
    97  
    98  	_, err = a.AnalogRead("P9_99")
    99  	gobottest.Assert(t, err, errors.New("Not a valid analog pin"))
   100  
   101  	fs.WithReadError = true
   102  	_, err = a.AnalogRead("P9_40")
   103  	gobottest.Assert(t, err, errors.New("read error"))
   104  	fs.WithReadError = false
   105  
   106  	gobottest.Assert(t, a.Finalize(), nil)
   107  }
   108  
   109  func TestDigitalIO(t *testing.T) {
   110  	mockPaths := []string{
   111  		"/sys/devices/platform/ocp/ocp:P8_07_pinmux/state",
   112  		"/sys/devices/platform/ocp/ocp:P9_11_pinmux/state",
   113  		"/sys/devices/platform/ocp/ocp:P9_12_pinmux/state",
   114  		"/sys/class/leds/beaglebone:green:usr1/brightness",
   115  		"/sys/class/gpio/export",
   116  		"/sys/class/gpio/unexport",
   117  		"/sys/class/gpio/gpio60/value",
   118  		"/sys/class/gpio/gpio60/direction",
   119  		"/sys/class/gpio/gpio66/value",
   120  		"/sys/class/gpio/gpio66/direction",
   121  		"/sys/class/gpio/gpio10/value",
   122  		"/sys/class/gpio/gpio10/direction",
   123  		"/sys/class/gpio/gpio30/value",
   124  		"/sys/class/gpio/gpio30/direction",
   125  	}
   126  
   127  	a, fs := initTestAdaptorWithMockedFilesystem(mockPaths)
   128  
   129  	// DigitalIO
   130  	a.DigitalWrite("usr1", 1)
   131  	gobottest.Assert(t,
   132  		fs.Files["/sys/class/leds/beaglebone:green:usr1/brightness"].Contents,
   133  		"1",
   134  	)
   135  
   136  	// no such LED
   137  	err := a.DigitalWrite("usr10101", 1)
   138  	gobottest.Assert(t, err.Error(), " : /sys/class/leds/beaglebone:green:usr10101/brightness: no such file")
   139  
   140  	a.DigitalWrite("P9_12", 1)
   141  	gobottest.Assert(t, fs.Files["/sys/class/gpio/gpio60/value"].Contents, "1")
   142  
   143  	gobottest.Assert(t, a.DigitalWrite("P9_99", 1), errors.New("'P9_99' is not a valid id for a digital pin"))
   144  
   145  	_, err = a.DigitalRead("P9_99")
   146  	gobottest.Assert(t, err, errors.New("'P9_99' is not a valid id for a digital pin"))
   147  
   148  	fs.Files["/sys/class/gpio/gpio66/value"].Contents = "1"
   149  	i, err := a.DigitalRead("P8_07")
   150  	gobottest.Assert(t, i, 1)
   151  	gobottest.Assert(t, err, nil)
   152  
   153  	gobottest.Assert(t, a.Finalize(), nil)
   154  }
   155  
   156  func TestName(t *testing.T) {
   157  	a := NewAdaptor()
   158  	gobottest.Assert(t, strings.HasPrefix(a.Name(), "Beaglebone"), true)
   159  	a.SetName("NewName")
   160  	gobottest.Assert(t, a.Name(), "NewName")
   161  }
   162  
   163  func TestAnalogReadFileError(t *testing.T) {
   164  	mockPaths := []string{
   165  		"/sys/devices/platform/whatever",
   166  	}
   167  
   168  	a, _ := initTestAdaptorWithMockedFilesystem(mockPaths)
   169  
   170  	_, err := a.AnalogRead("P9_40")
   171  	gobottest.Assert(t, strings.Contains(err.Error(), "/sys/bus/iio/devices/iio:device0/in_voltage1_raw: no such file"), true)
   172  }
   173  
   174  func TestDigitalPinDirectionFileError(t *testing.T) {
   175  	mockPaths := []string{
   176  		"/sys/class/gpio/export",
   177  		"/sys/class/gpio/gpio60/value",
   178  		"/sys/devices/platform/ocp/ocp:P9_12_pinmux/state",
   179  	}
   180  
   181  	a, _ := initTestAdaptorWithMockedFilesystem(mockPaths)
   182  
   183  	err := a.DigitalWrite("P9_12", 1)
   184  	gobottest.Assert(t, strings.Contains(err.Error(), "/sys/class/gpio/gpio60/direction: no such file"), true)
   185  
   186  	// no pin added after previous problem, so no pin to unexport in finalize
   187  	err = a.Finalize()
   188  	gobottest.Assert(t, nil, err)
   189  }
   190  
   191  func TestDigitalPinFinalizeFileError(t *testing.T) {
   192  	mockPaths := []string{
   193  		"/sys/class/gpio/export",
   194  		"/sys/class/gpio/gpio60/value",
   195  		"/sys/class/gpio/gpio60/direction",
   196  		"/sys/devices/platform/ocp/ocp:P9_12_pinmux/state",
   197  	}
   198  
   199  	a, _ := initTestAdaptorWithMockedFilesystem(mockPaths)
   200  
   201  	err := a.DigitalWrite("P9_12", 1)
   202  	gobottest.Assert(t, err, nil)
   203  
   204  	err = a.Finalize()
   205  	gobottest.Assert(t, strings.Contains(err.Error(), "/sys/class/gpio/unexport: no such file"), true)
   206  }
   207  
   208  func TestPocketName(t *testing.T) {
   209  	a := NewPocketBeagleAdaptor()
   210  	gobottest.Assert(t, strings.HasPrefix(a.Name(), "PocketBeagle"), true)
   211  }
   212  
   213  func TestSpiDefaultValues(t *testing.T) {
   214  	a := NewAdaptor()
   215  
   216  	gobottest.Assert(t, a.SpiDefaultBusNumber(), 0)
   217  	gobottest.Assert(t, a.SpiDefaultChipNumber(), 0)
   218  	gobottest.Assert(t, a.SpiDefaultMode(), 0)
   219  	gobottest.Assert(t, a.SpiDefaultBitCount(), 8)
   220  	gobottest.Assert(t, a.SpiDefaultMaxSpeed(), int64(500000))
   221  }
   222  
   223  func TestI2cDefaultBus(t *testing.T) {
   224  	a := NewAdaptor()
   225  	gobottest.Assert(t, a.DefaultI2cBus(), 2)
   226  }
   227  
   228  func TestI2cFinalizeWithErrors(t *testing.T) {
   229  	// arrange
   230  	a := NewAdaptor()
   231  	a.sys.UseMockSyscall()
   232  	fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-2"})
   233  	gobottest.Assert(t, a.Connect(), nil)
   234  	con, err := a.GetI2cConnection(0xff, 2)
   235  	gobottest.Assert(t, err, nil)
   236  	_, err = con.Write([]byte{0xbf})
   237  	gobottest.Assert(t, err, nil)
   238  	fs.WithCloseError = true
   239  	// act
   240  	err = a.Finalize()
   241  	// assert
   242  	gobottest.Assert(t, strings.Contains(err.Error(), "close error"), true)
   243  }
   244  
   245  func Test_validateSpiBusNumber(t *testing.T) {
   246  	var tests = map[string]struct {
   247  		busNr   int
   248  		wantErr error
   249  	}{
   250  		"number_negative_error": {
   251  			busNr:   -1,
   252  			wantErr: fmt.Errorf("Bus number -1 out of range"),
   253  		},
   254  		"number_0_ok": {
   255  			busNr: 0,
   256  		},
   257  		"number_1_ok": {
   258  			busNr: 1,
   259  		},
   260  		"number_2_error": {
   261  			busNr:   2,
   262  			wantErr: fmt.Errorf("Bus number 2 out of range"),
   263  		},
   264  	}
   265  	for name, tc := range tests {
   266  		t.Run(name, func(t *testing.T) {
   267  			// arrange
   268  			a := NewAdaptor()
   269  			// act
   270  			err := a.validateSpiBusNumber(tc.busNr)
   271  			// assert
   272  			gobottest.Assert(t, err, tc.wantErr)
   273  		})
   274  	}
   275  }
   276  
   277  func Test_validateI2cBusNumber(t *testing.T) {
   278  	var tests = map[string]struct {
   279  		busNr   int
   280  		wantErr error
   281  	}{
   282  		"number_negative_error": {
   283  			busNr:   -1,
   284  			wantErr: fmt.Errorf("Bus number -1 out of range"),
   285  		},
   286  		"number_0_ok": {
   287  			busNr: 0,
   288  		},
   289  		"number_1_error": {
   290  			busNr:   1,
   291  			wantErr: fmt.Errorf("Bus number 1 out of range"),
   292  		},
   293  		"number_2_ok": {
   294  			busNr: 2,
   295  		},
   296  		"number_3_error": {
   297  			busNr:   3,
   298  			wantErr: fmt.Errorf("Bus number 3 out of range"),
   299  		},
   300  	}
   301  	for name, tc := range tests {
   302  		t.Run(name, func(t *testing.T) {
   303  			// arrange
   304  			a := NewAdaptor()
   305  			// act
   306  			err := a.validateI2cBusNumber(tc.busNr)
   307  			// assert
   308  			gobottest.Assert(t, err, tc.wantErr)
   309  		})
   310  	}
   311  }
   312  
   313  func Test_translateAndMuxPWMPin(t *testing.T) {
   314  	// arrange
   315  	mockPaths := []string{
   316  		"/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip4/",
   317  		"/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchip2/",
   318  		"/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/",
   319  		"/sys/devices/platform/ocp/48300000.epwmss/48300100.ecap/pwm/pwmchip0/",
   320  	}
   321  	a, fs := initTestAdaptorWithMockedFilesystem(mockPaths)
   322  
   323  	var tests = map[string]struct {
   324  		wantDir     string
   325  		wantChannel int
   326  		wantErr     error
   327  	}{
   328  		"P8_13": {
   329  			wantDir:     "/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip4",
   330  			wantChannel: 1,
   331  		},
   332  		"P8_19": {
   333  			wantDir:     "/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip4",
   334  			wantChannel: 0,
   335  		},
   336  		"P9_14": {
   337  			wantDir:     "/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchip2",
   338  			wantChannel: 0,
   339  		},
   340  		"P9_16": {
   341  			wantDir:     "/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchip2",
   342  			wantChannel: 1,
   343  		},
   344  		"P9_21": {
   345  			wantDir:     "/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0",
   346  			wantChannel: 1,
   347  		},
   348  		"P9_22": {
   349  			wantDir:     "/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0",
   350  			wantChannel: 0,
   351  		},
   352  		"P9_42": {
   353  			wantDir:     "/sys/devices/platform/ocp/48300000.epwmss/48300100.ecap/pwm/pwmchip0",
   354  			wantChannel: 0,
   355  		},
   356  		"P9_99": {
   357  			wantDir:     "",
   358  			wantChannel: -1,
   359  			wantErr:     fmt.Errorf("'P9_99' is not a valid id for a PWM pin"),
   360  		},
   361  	}
   362  	for name, tc := range tests {
   363  		t.Run(name, func(t *testing.T) {
   364  			// arrange
   365  			muxPath := fmt.Sprintf("/sys/devices/platform/ocp/ocp:%s_pinmux/state", name)
   366  			fs.Add(muxPath)
   367  			// act
   368  			path, channel, err := a.translateAndMuxPWMPin(name)
   369  			// assert
   370  			gobottest.Assert(t, err, tc.wantErr)
   371  			gobottest.Assert(t, path, tc.wantDir)
   372  			gobottest.Assert(t, channel, tc.wantChannel)
   373  			if tc.wantErr == nil {
   374  				gobottest.Assert(t, fs.Files[muxPath].Contents, "pwm")
   375  			}
   376  		})
   377  	}
   378  }