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 }