[chirp_devel] [PATCH] [btech] Delayed retry on writing to radio in case of errornous response. Needed mostly on linux. Fixes issue #3993

Michael Wagner
Mon Sep 19 14:42:53 PDT 2016


# HG changeset patch
# User Michael Wagner <michael.wagner at 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)



More information about the chirp_devel mailing list