Skip to content

Commit

Permalink
Issue #446 USB-error recovery, version 1
Browse files Browse the repository at this point in the history
  • Loading branch information
WouterJD committed Nov 30, 2023
1 parent 8ee2a5a commit 5fd9a62
Showing 1 changed file with 111 additions and 54 deletions.
165 changes: 111 additions & 54 deletions pythoncode/usbTrainer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#-------------------------------------------------------------------------------
# Version info
#-------------------------------------------------------------------------------
__version__ = "2023-04-06"
__version__ = "2023-11-30"
# 2023-10-30 Error recovery on the USB-device improved, because of issue #446
# If reading (including retry) fails multiple times, the USB-device is
# re-initialized.
# 2023-04-06 If UserAndBikeWeight is set below the minimum, a sensible value is set.
# 2022-08-22 Steering only active when -S wired specified.
# 2022-08-10 Steering merged from marcoveeneman and switchable's code
Expand Down Expand Up @@ -380,19 +383,65 @@ def GetTrainer(clv, AntDevice=None):
if clv.Tacx_Genius: return clsTacxAntGeniusTrainer(clv, AntDevice)
if clv.Tacx_Bushido: return clsTacxAntBushidoTrainer(clv, AntDevice)


#-----------------------------------------------------------------------
# Let's see whether there is a USB-headunit connected...
#-----------------------------------------------------------------------
msg, hu, dev, LegacyProtocol = clsTacxTrainer.InitializeUSB(0)

#-----------------------------------------------------------------------
# Done
#-----------------------------------------------------------------------
logfile.Console(msg)
if debug.on(debug.Function):
logfile.Write ("GetTrainer() returns, trainertype=" + hex(hu))

#-----------------------------------------------------------------------
# Return the correct Object
#-----------------------------------------------------------------------
if dev != False:
if LegacyProtocol:
return clsTacxLegacyUsbTrainer(clv, msg, hu, dev)
else:
return clsTacxNewUsbTrainer(clv, msg, hu, dev)
else:
return clsTacxTrainer (clv, msg) # where .OK = False

#---------------------------------------------------------------------------
# I n i t i a l i z e U S B
#---------------------------------------------------------------------------
# Input previousHU, is used to reconnect on error-recovery
#
# Function Find USB-connected headunit and perform initialization
# This function was part of GetTrainer().
# Issue #446 reports disconnect of the USB headunit which does
# not recover.
# InitializeUSB() is used to reconnect when erros occur,
# practice must reveal whether this works.
#
# Output msg, hu, dev, LegacyProtocol
#---------------------------------------------------------------------------
@staticmethod
def InitializeUSB(previousHu):
logfile.Console ("Find and initialise USB head unit")
#-----------------------------------------------------------------------
# So we are going to initialize USB
# This may be either 'Legacy interface' or 'New interface'
#-----------------------------------------------------------------------
msg = "No Tacx trainer found"
hu = None # TrainerType
hu = 0 # TrainerType
dev = False
LegacyProtocol = False

#-----------------------------------------------------------------------
# Find supported trainer (actually we talk to a headunit)
#-----------------------------------------------------------------------
for hu in [hu1902, hu1902_nfw, hu1904, hu1932, hu1942, hue6be_nfw]:
if previousHu == 0:
HuList = [hu1902, hu1902_nfw, hu1904, hu1932, hu1942, hue6be_nfw]
else:
HuList = [previousHu]

for hu in HuList:
try:
if debug.on(debug.Function):
logfile.Write ("GetTrainer - Check for trainer %s" % (hex(hu)))
Expand Down Expand Up @@ -481,22 +530,9 @@ def GetTrainer(clv, AntDevice=None):
dev.write(0x02,data)

#-----------------------------------------------------------------------
# Done
#-----------------------------------------------------------------------
logfile.Console(msg)
if debug.on(debug.Function):
logfile.Write ("GetTrainer() returns, trainertype=" + hex(hu))

#-----------------------------------------------------------------------
# Return the correct Object
# Return results
#-----------------------------------------------------------------------
if dev != False:
if LegacyProtocol:
return clsTacxLegacyUsbTrainer(clv, msg, hu, dev)
else:
return clsTacxNewUsbTrainer(clv, msg, hu, dev)
else:
return clsTacxTrainer (clv, msg) # where .OK = False
return msg, hu, dev, LegacyProtocol

#---------------------------------------------------------------------------
# Functions from external to provide data
Expand Down Expand Up @@ -2358,6 +2394,7 @@ def DisplayStateTable(self, FortiusAntState):
# c l s T a c x U s b T r a i n e r
#-------------------------------------------------------------------------------
class clsTacxUsbTrainer(clsTacxTrainer):
USB_ReadErrorCount = 0
#---------------------------------------------------------------------------
# Convert WheelSpeed --> Speed in km/hr
# SpeedScale must be defined in sub-class
Expand Down Expand Up @@ -2466,46 +2503,66 @@ def USB_Read(self):
# At least 40 bytes must be returned, retry 4 times
#---------------------------------------------------------------------------
def USB_Read_retry4x40(self, expectedHeader = USB_ControlResponse):
retry = 4
TryToReinitialize = False

while True: # Recover through InitializeUSB()
retry = 4
while True: # Retry reading through USB_Read()
data = self.USB_Read()

#-------------------------------------------------------------------
# Retry if no correct buffer received
#-------------------------------------------------------------------
if retry and (len(data) < 40 or self.Header != expectedHeader):
if debug.on(debug.Any):
logfile.Write ( \
'Retry because short buffer (len=%s) or incorrect header received (expected: %s received: %s)' % \
(len(data), hex(expectedHeader), hex(self.Header)))
time.sleep(0.1) # 2020-09-29 short delay @RogerPleijers
retry -= 1
else:
break

while True:
data = self.USB_Read()
#-----------------------------------------------------------------------
# Inform when there's something unexpected
#-----------------------------------------------------------------------
if len(data) < 40:
self.tacxEvent = False
self.USB_ReadErrorCount += 1
# 2020-09-29 the buffer is ignored when too short (was processed before)
logfile.Console('Tacx head unit returns insufficient data, len=%s' % len(data))
if self.clv.PedalStrokeAnalysis:
logfile.Console('To resolve, try to run without Pedal Stroke Analysis.')
else:
logfile.Console('To resolve, check all (signal AND power) cabling for loose contacts.')
# 2021-04-29 On Raspberry Pi Zero W this also occurs when the
# system is too busy.
# When the system is less busy (FortiusAnt only active
# process) then the message disappears automatically.
# A longer timeout does not help (tried: 100ms).

elif self.Header != expectedHeader:
self.tacxEvent = False
self.USB_ReadErrorCount += 1
logfile.Console('Tacx head unit returns incorrect header %s (expected: %s)' % \
(hex(expectedHeader), hex(self.Header)))

#-------------------------------------------------------------------
# Retry if no correct buffer received
#-------------------------------------------------------------------
if retry and (len(data) < 40 or self.Header != expectedHeader):
if debug.on(debug.Any):
logfile.Write ( \
'Retry because short buffer (len=%s) or incorrect header received (expected: %s received: %s)' % \
(len(data), hex(expectedHeader), hex(self.Header)))
time.sleep(0.1) # 2020-09-29 short delay @RogerPleijers
retry -= 1
#-----------------------------------------------------------------------
# If errors occurred multiple times, try to reconnect the USB device...
# There is no timeout here, because it's in a loop itself.
#
# This path has been tested by unplugging the USB-cable which produces
# a heap of errors. After connection, FortiusAnt proceeds nicely.
# Issue #446 (presumably hw-error) to be tested and confirmed.
#-----------------------------------------------------------------------
if self.USB_ReadErrorCount > 4:
self.USB_ReadErrorCount = 0
logfile.Console('Try to reconnect to Tacx head unit')
msg, hu, self.UsbDevice, LegacyProtocol = clsTacxTrainer.InitializeUSB(self.Headunit)
logfile.Console (msg)
# Note that, if dev == False, msg shows what has gone wrong
else:
break

#-----------------------------------------------------------------------
# Inform when there's something unexpected
#-----------------------------------------------------------------------
if len(data) < 40:
self.tacxEvent = False
# 2020-09-29 the buffer is ignored when too short (was processed before)
logfile.Console('Tacx head unit returns insufficient data, len=%s' % len(data))
if self.clv.PedalStrokeAnalysis:
logfile.Console('To resolve, try to run without Pedal Stroke Analysis.')
else:
logfile.Console('To resolve, check all (signal AND power) cabling for loose contacts.')
# 2021-04-29 On Raspberry Pi Zero W this also occurs when the
# system is too busy.
# When the system is less busy (FortiusAnt only active
# process) then the message disappears automatically.
# A longer timeout does not help (tried: 100ms).

elif self.Header != expectedHeader:
self.tacxEvent = False
logfile.Console('Tacx head unit returns incorrect header %s (expected: %s)' % \
(hex(expectedHeader), hex(self.Header)))

return data

#---------------------------------------------------------------------------
Expand Down

0 comments on commit 5fd9a62

Please sign in to comment.