# HG changeset patch
# User Michael Wagner <michael.wagner@gmx.at>
# Date 1474015004 -7200
# Fri Sep 16 10:36:44 2016 +0200
# Node ID d6ee4a5066611703778f4b341b0c8b3d5c51e1b4
# Parent a1b8b53606f6025fc1ad727331837cfc7759f178
[btech] Delayed retry on writing to radio in case of errornous response. Needed mostly on linux. Fixes issue #3993
If radio responds with the infamous '0x05', driver now retries, but delays after each sent byte. Happens mostly on linux, and on several radios of this family (found on a KT-8900R).
Might also affect/fix also #3587 and #3635.
Many Thanks to Pavel Milanes for his support (analysis, explainations of the driver, sharing his knowledge about this and similar bugs, helping me with python-codestyle), and for encouraging me to contribute this patch.
Michael Wagner,
OE4AMW
diff -r a1b8b53606f6 -r d6ee4a506661 chirp/drivers/btech.py
--- a/chirp/drivers/btech.py Sat Sep 10 11:34:01 2016 -0400
+++ b/chirp/drivers/btech.py Fri Sep 16 10:36:44 2016 +0200
@@ -21,6 +21,7 @@
LOG = logging.getLogger(__name__)
+from time import sleep
from chirp import chirp_common, directory, memmap
from chirp import bitwise, errors, util
from chirp.settings import RadioSettingGroup, RadioSetting, \
@@ -236,7 +237,7 @@
# this var controls the verbosity in the debug and by default it's low (False)
# make it True and you will to get a very verbose debug.log
-debug = False
+debug = True
# Power Levels
NORMAL_POWER_LEVELS = [chirp_common.PowerLevel("High", watts=25),
@@ -334,6 +335,9 @@
# magic string for all other models
MSTRING = "\x55\x20\x15\x09\x20\x45\x4d\x02"
+# this variables controls the forced delay and retry on Linux OS mainly. Added by OE4AMW to workaround Issue 3993
+NEEDS_DELAY = False
+RETRY_DELAYED = False
def _clean_buffer(radio):
"""Cleaning the read serial buffer, hard timeout to survive an infinite
@@ -383,6 +387,11 @@
if len(data) < amount:
LOG.warn("Short reading %d bytes from the %d requested." %
(len(data), amount))
+ # This problem can be and expression of the MCU getting stuck
+ # so from now own we must delay the write operations.
+ global NEEDS_DELAY
+ NEEDS_DELAY = True
+ LOG.debug("Delaying future writes.")
except:
raise errors.RadioError("Error reading data from radio")
@@ -396,11 +405,26 @@
try:
for byte in data:
radio.pipe.write(byte)
+ # Some OS (mainly Linux ones) are two fast on the serial and
+ # get the MCU inside the radio stuck in the early stages, this
+ # hits some models more than others.
+ #
+ # To cope with that we introduce a delay on the writes but only if
+ # we detect this problem, this was found by Michael Wagner who
+ # proposed a patch for it, well done.
+ if NEEDS_DELAY:
+ # 10 msec is proved to be safe, is better to be slow and right
+ # than fast and some times wrong. (5 msec is tested ok)
+ sleep(0.010)
# DEBUG
if debug is True:
+ if NEEDS_DELAY:
+ LOG.debug("This write was delayed")
+
LOG.debug("==> (%d) bytes:\n\n%s" %
(len(data), util.hexprint(data)))
+
except:
raise errors.RadioError("Error sending data to radio")
@@ -435,9 +459,21 @@
# header validation
c, a, l = struct.unpack(">BHB", block[1:5])
if a != addr or l != BLOCK_SIZE or c != ord("X"):
- LOG.debug("Invalid header for block 0x%04x" % addr)
+ LOG.error("Invalid header for block 0x%04x" % addr)
LOG.debug("CMD: %s ADDR: %04x SIZE: %02x" % (c, a, l))
- raise errors.RadioError("Invalid header for block 0x%04x:" % addr)
+
+ global RETRY_DELAYED
+ if not RETRY_DELAYED:
+ # first try with header problems, forcing a write delay
+ LOG.warn("Failure occured, trying once again with delay")
+ RETRY_DELAYED = True
+ global NEEDS_DELAY
+ NEEDS_DELAY = True
+ return False
+ else:
+ # second try, now we fail.
+ LOG.debug("This was already a retry")
+ raise errors.RadioError("Invalid header for block 0x%04x:" % addr)
# return the data
return block[5:]
@@ -613,6 +649,16 @@
# read
d = _recv(radio, addr)
+ if d == False:
+ # retry to get that block of data.
+ msg = "Previous block request failed."
+ msg += " Cleaning buffer and trying again."
+ LOG.info(msg)
+ _clean_buffer(radio)
+ d = _recv(radio, addr)
+ global RETRY_DELAYED
+ RETRY_DELAYED = False
+
# aggregate the data
data += d
@@ -821,7 +867,16 @@
def sync_in(self):
"""Download from radio"""
- data = _download(self)
+ try:
+ data = _download(self)
+ except errors.RadioError:
+ msg = "First download-attempt failed."
+ msg += " Retrying the whole procedure with delayed writes."
+ LOG.error(msg)
+ global NEEDS_DELAY
+ NEEDS_DELAY = True
+ data = _download(self)
+
self._mmap = memmap.MemoryMap(data)
self.process_mmap()
@@ -1284,7 +1339,7 @@
if self.MODEL in ("UV-2501", "UV-5001"):
vfomren = RadioSetting("settings2.vfomren", "VFO/MR switching",
RadioSettingValueBoolean(
- _mem.settings2.vfomren))
+ not _mem.settings2.vfomren))
advanced.append(vfomren)
reseten = RadioSetting("settings2.reseten", "RESET",
@@ -1569,6 +1624,8 @@
if element.has_apply_callback():
LOG.debug("Using apply callback")
element.run_apply_callback()
+ elif setting == "vfomren":
+ setattr(obj, setting, not int(element.value))
elif element.value.get_mutable():
LOG.debug("Setting %s = %s" % (setting, element.value))
setattr(obj, setting, element.value)