gobot.io/x/gobot@v1.16.0/platforms/firmata/client/client_test.go (about) 1 package client 2 3 import ( 4 "bytes" 5 "sync" 6 "testing" 7 "time" 8 9 "gobot.io/x/gobot/gobottest" 10 ) 11 12 type readWriteCloser struct{} 13 14 func (readWriteCloser) Write(p []byte) (int, error) { 15 writeDataMutex.Lock() 16 defer writeDataMutex.Unlock() 17 return testWriteData.Write(p) 18 } 19 20 var clientMutex sync.Mutex 21 var writeDataMutex sync.Mutex 22 var readDataMutex sync.Mutex 23 var testReadData = []byte{} 24 var testWriteData = bytes.Buffer{} 25 26 func SetTestReadData(d []byte) { 27 readDataMutex.Lock() 28 defer readDataMutex.Unlock() 29 testReadData = d 30 return 31 } 32 33 func (readWriteCloser) Read(b []byte) (int, error) { 34 readDataMutex.Lock() 35 defer readDataMutex.Unlock() 36 37 size := len(b) 38 if len(testReadData) < size { 39 size = len(testReadData) 40 } 41 copy(b, []byte(testReadData)[:size]) 42 testReadData = testReadData[size:] 43 44 return size, nil 45 } 46 47 func (readWriteCloser) Close() error { 48 return nil 49 } 50 51 func testProtocolResponse() []byte { 52 // arduino uno r3 protocol response "2.3" 53 return []byte{249, 2, 3} 54 } 55 56 func testFirmwareResponse() []byte { 57 // arduino uno r3 firmware response "StandardFirmata.ino" 58 return []byte{240, 121, 2, 3, 83, 0, 116, 0, 97, 0, 110, 0, 100, 0, 97, 59 0, 114, 0, 100, 0, 70, 0, 105, 0, 114, 0, 109, 0, 97, 0, 116, 0, 97, 0, 46, 60 0, 105, 0, 110, 0, 111, 0, 247} 61 } 62 63 func testCapabilitiesResponse() []byte { 64 // arduino uno r3 capabilities response 65 return []byte{240, 108, 127, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 3, 66 8, 4, 14, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 3, 8, 4, 14, 127, 0, 1, 67 1, 1, 3, 8, 4, 14, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 4, 14, 127, 0, 68 1, 1, 1, 3, 8, 4, 14, 127, 0, 1, 1, 1, 3, 8, 4, 14, 127, 0, 1, 1, 1, 3, 8, 69 4, 14, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 2, 70 10, 127, 0, 1, 1, 1, 2, 10, 127, 0, 1, 1, 1, 2, 10, 127, 0, 1, 1, 1, 2, 10, 71 127, 0, 1, 1, 1, 2, 10, 6, 1, 127, 0, 1, 1, 1, 2, 10, 6, 1, 127, 247} 72 } 73 74 func testAnalogMappingResponse() []byte { 75 // arduino uno r3 analog mapping response 76 return []byte{240, 106, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 77 127, 127, 127, 127, 0, 1, 2, 3, 4, 5, 247} 78 } 79 80 func initTestFirmata() *Client { 81 b := New() 82 b.connection = readWriteCloser{} 83 84 for _, f := range []func() []byte{ 85 testProtocolResponse, 86 testFirmwareResponse, 87 testCapabilitiesResponse, 88 testAnalogMappingResponse, 89 } { 90 SetTestReadData(f()) 91 b.process() 92 } 93 94 return b 95 } 96 97 func TestPins(t *testing.T) { 98 b := initTestFirmata() 99 b.setConnected(true) 100 101 gobottest.Assert(t, len(b.Pins()), 20) 102 gobottest.Assert(t, len(b.analogPins), 6) 103 } 104 105 func TestReportVersion(t *testing.T) { 106 b := initTestFirmata() 107 b.setConnected(true) 108 //test if functions executes 109 gobottest.Assert(t, b.ProtocolVersionQuery(), nil) 110 } 111 112 func TestQueryFirmware(t *testing.T) { 113 b := initTestFirmata() 114 b.setConnected(true) 115 //test if functions executes 116 gobottest.Assert(t, b.FirmwareQuery(), nil) 117 } 118 119 func TestQueryPinState(t *testing.T) { 120 b := initTestFirmata() 121 b.setConnected(true) 122 //test if functions executes 123 gobottest.Assert(t, b.PinStateQuery(1), nil) 124 } 125 126 func TestProcessProtocolVersion(t *testing.T) { 127 sem := make(chan bool) 128 b := initTestFirmata() 129 b.setConnected(true) 130 SetTestReadData([]byte{249, 2, 3}) 131 132 b.Once(b.Event("ProtocolVersion"), func(data interface{}) { 133 gobottest.Assert(t, data, "2.3") 134 sem <- true 135 }) 136 137 b.process() 138 139 select { 140 case <-sem: 141 case <-time.After(100 * time.Millisecond): 142 t.Errorf("ProtocolVersion was not published") 143 } 144 } 145 146 func TestProcessAnalogRead0(t *testing.T) { 147 sem := make(chan bool) 148 b := initTestFirmata() 149 b.setConnected(true) 150 SetTestReadData([]byte{0xE0, 0x23, 0x05}) 151 152 b.Once(b.Event("AnalogRead0"), func(data interface{}) { 153 gobottest.Assert(t, data, 675) 154 sem <- true 155 }) 156 157 b.process() 158 159 select { 160 case <-sem: 161 case <-time.After(100 * time.Millisecond): 162 t.Errorf("AnalogRead0 was not published") 163 } 164 } 165 166 func TestProcessAnalogRead1(t *testing.T) { 167 sem := make(chan bool) 168 b := initTestFirmata() 169 b.setConnected(true) 170 SetTestReadData([]byte{0xE1, 0x23, 0x06}) 171 172 b.Once(b.Event("AnalogRead1"), func(data interface{}) { 173 gobottest.Assert(t, data, 803) 174 sem <- true 175 }) 176 177 b.process() 178 179 select { 180 case <-sem: 181 case <-time.After(100 * time.Millisecond): 182 t.Errorf("AnalogRead1 was not published") 183 } 184 } 185 186 func TestProcessDigitalRead2(t *testing.T) { 187 sem := make(chan bool) 188 b := initTestFirmata() 189 b.setConnected(true) 190 b.pins[2].Mode = Input 191 SetTestReadData([]byte{0x90, 0x04, 0x00}) 192 193 b.Once(b.Event("DigitalRead2"), func(data interface{}) { 194 gobottest.Assert(t, data, 1) 195 sem <- true 196 }) 197 198 b.process() 199 200 select { 201 case <-sem: 202 case <-time.After(100 * time.Millisecond): 203 t.Errorf("DigitalRead2 was not published") 204 } 205 } 206 207 func TestProcessDigitalRead4(t *testing.T) { 208 sem := make(chan bool) 209 b := initTestFirmata() 210 b.setConnected(true) 211 b.pins[4].Mode = Input 212 SetTestReadData([]byte{0x90, 0x16, 0x00}) 213 214 b.Once(b.Event("DigitalRead4"), func(data interface{}) { 215 gobottest.Assert(t, data, 1) 216 sem <- true 217 }) 218 219 b.process() 220 221 select { 222 case <-sem: 223 case <-time.After(100 * time.Millisecond): 224 t.Errorf("DigitalRead4 was not published") 225 } 226 } 227 228 func TestDigitalWrite(t *testing.T) { 229 b := initTestFirmata() 230 b.setConnected(true) 231 gobottest.Assert(t, b.DigitalWrite(13, 0), nil) 232 } 233 234 func TestSetPinMode(t *testing.T) { 235 b := initTestFirmata() 236 b.setConnected(true) 237 gobottest.Assert(t, b.SetPinMode(13, Output), nil) 238 } 239 240 func TestAnalogWrite(t *testing.T) { 241 b := initTestFirmata() 242 b.setConnected(true) 243 gobottest.Assert(t, b.AnalogWrite(0, 128), nil) 244 } 245 246 func TestReportAnalog(t *testing.T) { 247 b := initTestFirmata() 248 b.setConnected(true) 249 gobottest.Assert(t, b.ReportAnalog(0, 1), nil) 250 gobottest.Assert(t, b.ReportAnalog(0, 0), nil) 251 } 252 253 func TestProcessPinState13(t *testing.T) { 254 sem := make(chan bool) 255 b := initTestFirmata() 256 b.setConnected(true) 257 SetTestReadData([]byte{240, 110, 13, 1, 1, 247}) 258 259 b.Once(b.Event("PinState13"), func(data interface{}) { 260 gobottest.Assert(t, data, Pin{[]int{0, 1, 4}, 1, 0, 1, 127}) 261 sem <- true 262 }) 263 264 b.process() 265 266 select { 267 case <-sem: 268 case <-time.After(100 * time.Millisecond): 269 t.Errorf("PinState13 was not published") 270 } 271 } 272 273 func TestI2cConfig(t *testing.T) { 274 b := initTestFirmata() 275 b.setConnected(true) 276 gobottest.Assert(t, b.I2cConfig(100), nil) 277 } 278 279 func TestI2cWrite(t *testing.T) { 280 b := initTestFirmata() 281 b.setConnected(true) 282 gobottest.Assert(t, b.I2cWrite(0x00, []byte{0x01, 0x02}), nil) 283 } 284 285 func TestI2cRead(t *testing.T) { 286 b := initTestFirmata() 287 b.setConnected(true) 288 gobottest.Assert(t, b.I2cRead(0x00, 10), nil) 289 } 290 291 func TestWriteSysex(t *testing.T) { 292 b := initTestFirmata() 293 b.setConnected(true) 294 gobottest.Assert(t, b.WriteSysex([]byte{0x01, 0x02}), nil) 295 } 296 297 func TestProcessI2cReply(t *testing.T) { 298 sem := make(chan bool) 299 b := initTestFirmata() 300 b.setConnected(true) 301 SetTestReadData([]byte{240, 119, 9, 0, 0, 0, 24, 1, 1, 0, 26, 1, 247}) 302 303 b.Once(b.Event("I2cReply"), func(data interface{}) { 304 gobottest.Assert(t, data, I2cReply{ 305 Address: 9, 306 Register: 0, 307 Data: []byte{152, 1, 154}, 308 }) 309 sem <- true 310 }) 311 312 b.process() 313 314 select { 315 case <-sem: 316 case <-time.After(100 * time.Millisecond): 317 t.Errorf("I2cReply was not published") 318 } 319 } 320 321 func TestProcessFirmwareQuery(t *testing.T) { 322 sem := make(chan bool) 323 b := initTestFirmata() 324 b.setConnected(true) 325 SetTestReadData([]byte{240, 121, 2, 3, 83, 0, 116, 0, 97, 0, 110, 0, 100, 0, 97, 326 0, 114, 0, 100, 0, 70, 0, 105, 0, 114, 0, 109, 0, 97, 0, 116, 0, 97, 0, 46, 327 0, 105, 0, 110, 0, 111, 0, 247}) 328 329 b.Once(b.Event("FirmwareQuery"), func(data interface{}) { 330 gobottest.Assert(t, data, "StandardFirmata.ino") 331 sem <- true 332 }) 333 334 b.process() 335 336 select { 337 case <-sem: 338 case <-time.After(100 * time.Millisecond): 339 t.Errorf("FirmwareQuery was not published") 340 } 341 } 342 343 func TestProcessStringData(t *testing.T) { 344 sem := make(chan bool) 345 b := initTestFirmata() 346 b.setConnected(true) 347 SetTestReadData(append([]byte{240, 0x71}, append([]byte("Hello Firmata!"), 247)...)) 348 349 b.Once(b.Event("StringData"), func(data interface{}) { 350 gobottest.Assert(t, data, "Hello Firmata!") 351 sem <- true 352 }) 353 354 b.process() 355 356 select { 357 case <-sem: 358 case <-time.After(100 * time.Millisecond): 359 t.Errorf("StringData was not published") 360 } 361 } 362 363 func TestConnect(t *testing.T) { 364 b := New() 365 366 var responseMutex sync.Mutex 367 responseMutex.Lock() 368 response := testProtocolResponse() 369 responseMutex.Unlock() 370 371 b.Once(b.Event("ProtocolVersion"), func(data interface{}) { 372 responseMutex.Lock() 373 response = testFirmwareResponse() 374 responseMutex.Unlock() 375 }) 376 377 b.Once(b.Event("FirmwareQuery"), func(data interface{}) { 378 responseMutex.Lock() 379 response = testCapabilitiesResponse() 380 responseMutex.Unlock() 381 }) 382 383 b.Once(b.Event("CapabilityQuery"), func(data interface{}) { 384 responseMutex.Lock() 385 response = testAnalogMappingResponse() 386 responseMutex.Unlock() 387 }) 388 389 b.Once(b.Event("AnalogMappingQuery"), func(data interface{}) { 390 responseMutex.Lock() 391 response = testProtocolResponse() 392 responseMutex.Unlock() 393 }) 394 395 go func() { 396 for { 397 responseMutex.Lock() 398 readDataMutex.Lock() 399 testReadData = append(testReadData, response...) 400 readDataMutex.Unlock() 401 responseMutex.Unlock() 402 time.Sleep(100 * time.Millisecond) 403 } 404 }() 405 406 gobottest.Assert(t, b.Connect(readWriteCloser{}), nil) 407 time.Sleep(150 * time.Millisecond) 408 gobottest.Assert(t, b.Disconnect(), nil) 409 } 410 411 func TestServoConfig(t *testing.T) { 412 b := New() 413 b.connection = readWriteCloser{} 414 415 tests := []struct { 416 description string 417 arguments [3]int 418 expected []byte 419 result error 420 }{ 421 { 422 description: "Min values for min & max", 423 arguments: [3]int{9, 0, 0}, 424 expected: []byte{0xF0, 0x70, 9, 0, 0, 0, 0, 0xF7}, 425 }, 426 { 427 description: "Max values for min & max", 428 arguments: [3]int{9, 0x3FFF, 0x3FFF}, 429 expected: []byte{0xF0, 0x70, 9, 0x7F, 0x7F, 0x7F, 0x7F, 0xF7}, 430 }, 431 { 432 description: "Clipped max values for min & max", 433 arguments: [3]int{9, 0xFFFF, 0xFFFF}, 434 expected: []byte{0xF0, 0x70, 9, 0x7F, 0x7F, 0x7F, 0x7F, 0xF7}, 435 }, 436 } 437 438 for _, test := range tests { 439 writeDataMutex.Lock() 440 testWriteData.Reset() 441 writeDataMutex.Unlock() 442 err := b.ServoConfig(test.arguments[0], test.arguments[1], test.arguments[2]) 443 writeDataMutex.Lock() 444 gobottest.Assert(t, testWriteData.Bytes(), test.expected) 445 gobottest.Assert(t, err, test.result) 446 writeDataMutex.Unlock() 447 } 448 } 449 450 func TestProcessSysexData(t *testing.T) { 451 sem := make(chan bool) 452 b := initTestFirmata() 453 b.setConnected(true) 454 SetTestReadData([]byte{240, 17, 1, 2, 3, 247}) 455 456 b.Once("SysexResponse", func(data interface{}) { 457 gobottest.Assert(t, data, []byte{240, 17, 1, 2, 3, 247}) 458 sem <- true 459 }) 460 461 b.process() 462 463 select { 464 case <-sem: 465 case <-time.After(100 * time.Millisecond): 466 t.Errorf("SysexResponse was not published") 467 } 468 }