|
1 | 1 | #-------------------------------------------------------------------------------
|
2 | 2 | # Version info
|
3 | 3 | #-------------------------------------------------------------------------------
|
4 |
| -__version__ = "2023-04-06" |
| 4 | +__version__ = "2023-12-01" |
| 5 | +# 2023-12-01 Improvement so that reconnect DOES NOT occur when succesful reads |
| 6 | +# follow on unsuccesful reads. |
| 7 | +# 2023-10-30 Error recovery on the USB-device improved, because of issue #446 |
| 8 | +# If reading (including retry) fails multiple times, the USB-device is |
| 9 | +# re-initialized. |
5 | 10 | # 2023-04-06 If UserAndBikeWeight is set below the minimum, a sensible value is set.
|
6 | 11 | # 2022-08-22 Steering only active when -S wired specified.
|
7 | 12 | # 2022-08-10 Steering merged from marcoveeneman and switchable's code
|
@@ -380,19 +385,65 @@ def GetTrainer(clv, AntDevice=None):
|
380 | 385 | if clv.Tacx_Genius: return clsTacxAntGeniusTrainer(clv, AntDevice)
|
381 | 386 | if clv.Tacx_Bushido: return clsTacxAntBushidoTrainer(clv, AntDevice)
|
382 | 387 |
|
| 388 | + |
| 389 | + #----------------------------------------------------------------------- |
| 390 | + # Let's see whether there is a USB-headunit connected... |
| 391 | + #----------------------------------------------------------------------- |
| 392 | + msg, hu, dev, LegacyProtocol = clsTacxTrainer.InitializeUSB(0) |
| 393 | + |
| 394 | + #----------------------------------------------------------------------- |
| 395 | + # Done |
| 396 | + #----------------------------------------------------------------------- |
| 397 | + logfile.Console(msg) |
| 398 | + if debug.on(debug.Function): |
| 399 | + logfile.Write ("GetTrainer() returns, trainertype=" + hex(hu)) |
| 400 | + |
| 401 | + #----------------------------------------------------------------------- |
| 402 | + # Return the correct Object |
| 403 | + #----------------------------------------------------------------------- |
| 404 | + if dev != False: |
| 405 | + if LegacyProtocol: |
| 406 | + return clsTacxLegacyUsbTrainer(clv, msg, hu, dev) |
| 407 | + else: |
| 408 | + return clsTacxNewUsbTrainer(clv, msg, hu, dev) |
| 409 | + else: |
| 410 | + return clsTacxTrainer (clv, msg) # where .OK = False |
| 411 | + |
| 412 | + #--------------------------------------------------------------------------- |
| 413 | + # I n i t i a l i z e U S B |
| 414 | + #--------------------------------------------------------------------------- |
| 415 | + # Input previousHU, is used to reconnect on error-recovery |
| 416 | + # |
| 417 | + # Function Find USB-connected headunit and perform initialization |
| 418 | + # This function was part of GetTrainer(). |
| 419 | + # Issue #446 reports disconnect of the USB headunit which does |
| 420 | + # not recover. |
| 421 | + # InitializeUSB() is used to reconnect when erros occur, |
| 422 | + # practice must reveal whether this works. |
| 423 | + # |
| 424 | + # Output msg, hu, dev, LegacyProtocol |
| 425 | + #--------------------------------------------------------------------------- |
| 426 | + @staticmethod |
| 427 | + def InitializeUSB(previousHu): |
| 428 | + logfile.Console ("Find and initialise USB head unit") |
383 | 429 | #-----------------------------------------------------------------------
|
384 | 430 | # So we are going to initialize USB
|
385 | 431 | # This may be either 'Legacy interface' or 'New interface'
|
386 | 432 | #-----------------------------------------------------------------------
|
387 | 433 | msg = "No Tacx trainer found"
|
388 |
| - hu = None # TrainerType |
| 434 | + hu = 0 # TrainerType |
389 | 435 | dev = False
|
390 | 436 | LegacyProtocol = False
|
391 | 437 |
|
392 | 438 | #-----------------------------------------------------------------------
|
393 | 439 | # Find supported trainer (actually we talk to a headunit)
|
394 | 440 | #-----------------------------------------------------------------------
|
395 |
| - for hu in [hu1902, hu1902_nfw, hu1904, hu1932, hu1942, hue6be_nfw]: |
| 441 | + if previousHu == 0: |
| 442 | + HuList = [hu1902, hu1902_nfw, hu1904, hu1932, hu1942, hue6be_nfw] |
| 443 | + else: |
| 444 | + HuList = [previousHu] |
| 445 | + |
| 446 | + for hu in HuList: |
396 | 447 | try:
|
397 | 448 | if debug.on(debug.Function):
|
398 | 449 | logfile.Write ("GetTrainer - Check for trainer %s" % (hex(hu)))
|
@@ -481,22 +532,9 @@ def GetTrainer(clv, AntDevice=None):
|
481 | 532 | dev.write(0x02,data)
|
482 | 533 |
|
483 | 534 | #-----------------------------------------------------------------------
|
484 |
| - # Done |
| 535 | + # Return results |
485 | 536 | #-----------------------------------------------------------------------
|
486 |
| - logfile.Console(msg) |
487 |
| - if debug.on(debug.Function): |
488 |
| - logfile.Write ("GetTrainer() returns, trainertype=" + hex(hu)) |
489 |
| - |
490 |
| - #----------------------------------------------------------------------- |
491 |
| - # Return the correct Object |
492 |
| - #----------------------------------------------------------------------- |
493 |
| - if dev != False: |
494 |
| - if LegacyProtocol: |
495 |
| - return clsTacxLegacyUsbTrainer(clv, msg, hu, dev) |
496 |
| - else: |
497 |
| - return clsTacxNewUsbTrainer(clv, msg, hu, dev) |
498 |
| - else: |
499 |
| - return clsTacxTrainer (clv, msg) # where .OK = False |
| 537 | + return msg, hu, dev, LegacyProtocol |
500 | 538 |
|
501 | 539 | #---------------------------------------------------------------------------
|
502 | 540 | # Functions from external to provide data
|
@@ -2358,6 +2396,7 @@ def DisplayStateTable(self, FortiusAntState):
|
2358 | 2396 | # c l s T a c x U s b T r a i n e r
|
2359 | 2397 | #-------------------------------------------------------------------------------
|
2360 | 2398 | class clsTacxUsbTrainer(clsTacxTrainer):
|
| 2399 | + USB_ReadErrorCount = 0 |
2361 | 2400 | #---------------------------------------------------------------------------
|
2362 | 2401 | # Convert WheelSpeed --> Speed in km/hr
|
2363 | 2402 | # SpeedScale must be defined in sub-class
|
@@ -2464,48 +2503,91 @@ def USB_Read(self):
|
2464 | 2503 | #
|
2465 | 2504 | # function Same plus:
|
2466 | 2505 | # At least 40 bytes must be returned, retry 4 times
|
| 2506 | + # |
| 2507 | + # If multiple USB_Read_retry4x40() fail, the USB device is |
| 2508 | + # reattached. |
| 2509 | + # |
| 2510 | + # One might argue this error-recovery should also happen in |
| 2511 | + # USB_write(). USB_Write does not fail unless the USB cable is |
| 2512 | + # actually disconnected. Since both functions are in the main loop |
| 2513 | + # reconnecting here works fine. |
2467 | 2514 | #---------------------------------------------------------------------------
|
2468 | 2515 | def USB_Read_retry4x40(self, expectedHeader = USB_ControlResponse):
|
2469 |
| - retry = 4 |
| 2516 | + #----------------------------------------------------------------------- |
| 2517 | + # If multiple reads fail, we try to reconnect. |
| 2518 | + # This is not necessary when succesfull reads occur in the meantime. |
| 2519 | + # This is quite arbitrary, practice must reveal that no unneccessary |
| 2520 | + # reconnects occur. |
| 2521 | + # |
| 2522 | + # A reconnect occurs: |
| 2523 | + # fail - fail - fail - fail USB_ReadErrorCount = 4 |
| 2524 | + # fail - fail - ok - fail - fail - fail USB_ReadErrorCount = 4 |
| 2525 | + # A reconnect DOES NOT occur: |
| 2526 | + # fail - ok - fail - ok - fail - ok - fail USB_ReadErrorCount = 1 |
| 2527 | + #----------------------------------------------------------------------- |
| 2528 | + self.USB_ReadErrorCount = max(self.USB_ReadErrorCount - 1, 0) |
2470 | 2529 |
|
2471 |
| - while True: |
2472 |
| - data = self.USB_Read() |
| 2530 | + #----------------------------------------------------------------------- |
| 2531 | + # Let's go |
| 2532 | + #----------------------------------------------------------------------- |
| 2533 | + while True: # Recover through InitializeUSB() |
| 2534 | + retry = 4 |
| 2535 | + while True: # Retry reading through USB_Read() |
| 2536 | + data = self.USB_Read() |
| 2537 | + |
| 2538 | + #--------------------------------------------------------------- |
| 2539 | + # Retry if no correct buffer received |
| 2540 | + #--------------------------------------------------------------- |
| 2541 | + if retry and (len(data) < 40 or self.Header != expectedHeader): |
| 2542 | + if debug.on(debug.Any): |
| 2543 | + logfile.Write ( \ |
| 2544 | + 'Retry because short buffer (len=%s) or incorrect header received (expected: %s received: %s)' % \ |
| 2545 | + (len(data), hex(expectedHeader), hex(self.Header))) |
| 2546 | + time.sleep(0.1) # 2020-09-29 short delay @RogerPleijers |
| 2547 | + retry -= 1 |
| 2548 | + else: |
| 2549 | + break |
2473 | 2550 |
|
2474 | 2551 | #-------------------------------------------------------------------
|
2475 |
| - # Retry if no correct buffer received |
| 2552 | + # Inform when there's something unexpected |
2476 | 2553 | #-------------------------------------------------------------------
|
2477 |
| - if retry and (len(data) < 40 or self.Header != expectedHeader): |
2478 |
| - if debug.on(debug.Any): |
2479 |
| - logfile.Write ( \ |
2480 |
| -'Retry because short buffer (len=%s) or incorrect header received (expected: %s received: %s)' % \ |
2481 |
| - (len(data), hex(expectedHeader), hex(self.Header))) |
2482 |
| - time.sleep(0.1) # 2020-09-29 short delay @RogerPleijers |
2483 |
| - retry -= 1 |
2484 |
| - else: |
2485 |
| - break |
| 2554 | + if len(data) < 40: |
| 2555 | + self.tacxEvent = False |
| 2556 | + self.USB_ReadErrorCount += 1 |
| 2557 | + # 2020-09-29 the buffer is ignored when too short (was processed before) |
| 2558 | + logfile.Console('Tacx head unit returns insufficient data, len=%s' % len(data)) |
| 2559 | + if self.clv.PedalStrokeAnalysis: |
| 2560 | + logfile.Console('To resolve, try to run without Pedal Stroke Analysis.') |
| 2561 | + else: |
| 2562 | + logfile.Console('To resolve, check all (signal AND power) cabling for loose contacts.') |
| 2563 | + # 2021-04-29 On Raspberry Pi Zero W this also occurs when the |
| 2564 | + # system is too busy. |
| 2565 | + # When the system is less busy (FortiusAnt only active |
| 2566 | + # process) then the message disappears automatically. |
| 2567 | + # A longer timeout does not help (tried: 100ms). |
| 2568 | + |
| 2569 | + elif self.Header != expectedHeader: |
| 2570 | + self.tacxEvent = False |
| 2571 | + self.USB_ReadErrorCount += 1 |
| 2572 | + logfile.Console('Tacx head unit returns incorrect header %s (expected: %s)' % \ |
| 2573 | + (hex(expectedHeader), hex(self.Header))) |
2486 | 2574 |
|
2487 |
| - #----------------------------------------------------------------------- |
2488 |
| - # Inform when there's something unexpected |
2489 |
| - #----------------------------------------------------------------------- |
2490 |
| - if len(data) < 40: |
2491 |
| - self.tacxEvent = False |
2492 |
| - # 2020-09-29 the buffer is ignored when too short (was processed before) |
2493 |
| - logfile.Console('Tacx head unit returns insufficient data, len=%s' % len(data)) |
2494 |
| - if self.clv.PedalStrokeAnalysis: |
2495 |
| - logfile.Console('To resolve, try to run without Pedal Stroke Analysis.') |
| 2575 | + #------------------------------------------------------------------- |
| 2576 | + # If errors occurred multiple times, try to reconnect the USB device... |
| 2577 | + # There is no timeout here, because it's in a loop itself. |
| 2578 | + # |
| 2579 | + # This path has been tested by unplugging the USB-cable which produces |
| 2580 | + # a heap of errors. After connection, FortiusAnt proceeds nicely. |
| 2581 | + # Issue #446 (presumably hw-error) to be tested and confirmed. |
| 2582 | + #------------------------------------------------------------------- |
| 2583 | + if self.USB_ReadErrorCount > 4: |
| 2584 | + self.USB_ReadErrorCount = 0 |
| 2585 | + logfile.Console('Try to reconnect to Tacx head unit') |
| 2586 | + msg, hu, self.UsbDevice, LegacyProtocol = clsTacxTrainer.InitializeUSB(self.Headunit) |
| 2587 | + logfile.Console (msg) |
| 2588 | + # Note that, if dev == False, msg shows what has gone wrong |
2496 | 2589 | else:
|
2497 |
| - logfile.Console('To resolve, check all (signal AND power) cabling for loose contacts.') |
2498 |
| - # 2021-04-29 On Raspberry Pi Zero W this also occurs when the |
2499 |
| - # system is too busy. |
2500 |
| - # When the system is less busy (FortiusAnt only active |
2501 |
| - # process) then the message disappears automatically. |
2502 |
| - # A longer timeout does not help (tried: 100ms). |
2503 |
| - |
2504 |
| - elif self.Header != expectedHeader: |
2505 |
| - self.tacxEvent = False |
2506 |
| - logfile.Console('Tacx head unit returns incorrect header %s (expected: %s)' % \ |
2507 |
| - (hex(expectedHeader), hex(self.Header))) |
2508 |
| - |
| 2590 | + break |
2509 | 2591 | return data
|
2510 | 2592 |
|
2511 | 2593 | #---------------------------------------------------------------------------
|
|
0 commit comments