[chirp_devel] TS-480 Patch for #8297 and #8877

Rick (AA0RD) DeWitt
Sat Mar 6 10:16:05 PST 2021


Patch fixes Split mode support for TS-480 (#8297) and 67.0 Htz PL 
download (#8877).
I know, I am improperly submitting multiple bug-fixes in a combined 
patch, but I feel they should both be implemented in the next build.
I am so ashamed...😭
-- 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://intrepid.danplanet.com/pipermail/chirp_devel/attachments/20210306/742e6fe1/attachment-0001.html 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Signature-RIck-AA0RD-Image.jpg
Type: image/jpeg
Size: 18469 bytes
Desc: not available
Url : http://intrepid.danplanet.com/pipermail/chirp_devel/attachments/20210306/742e6fe1/attachment-0001.jpg 
-------------- next part --------------
# HG changeset patch
# User Rick DeWitt <aa0rd at yahoo.com>
# Date 1615053925 28800
#      Sat Mar 06 10:05:25 2021 -0800
# Node ID 8f16194724cc7404fc3a0391023d2106650b102c
# Parent  5249ae1ee57bb1e7cd45ddba6bde11a68a507673
[ts480] Bug fixes for issues #8297 and #8877 Kenwood TS-480
#8297 fix for split mode support, #8877 fix for 67Htz PL download

diff -r 5249ae1ee57b -r 8f16194724cc chirp/drivers/ts480.py
--- a/chirp/drivers/ts480.py	Thu Feb 11 15:40:16 2021 -0800
+++ b/chirp/drivers/ts480.py	Sat Mar 06 10:05:25 2021 -0800
@@ -1,5 +1,7 @@
 # Copyright 2019 Rick DeWitt <aa0rd at yahoo.com>
-# Implementing mem as Clone Mode
+# Implementing Kenwood TS-480 as Clone Mode
+# March 2021: Implementing true Split mode support per issue #8297
+# March 6, 2021: PL tone download fix for issue #8877
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
@@ -18,7 +20,6 @@
 import logging
 import re
 import math
-import threading
 from chirp import chirp_common, directory, memmap
 from chirp import bitwise, errors, util
 from chirp.settings import RadioSettingGroup, RadioSetting, \
@@ -38,7 +39,8 @@
   u8   tmode;
   u8   rtone;
   u8   ctone;
-  u8   skip;
+  u8   split:4,
+       skip:4;
   u8   step;
   char name[8];
 } ch_mem[110];   // 100 normal + 10 P-type
@@ -90,15 +92,15 @@
 
 """
 
+MEMSIZE = 0x0b1d       # img file size
 STIMEOUT = 0.6
-LOCK = threading.Lock()
 BAUD = 0    # Initial baud rate
 MEMSEL = 0  # Default Menu A
 BEEPVOL = 5     # Default beep level
 W8S = 0.01      # short wait, secs
 W8L = 0.05      # long wait
 
-TS480_DUPLEX = ["", "-", "+"]
+TS480_DUPLEX = ["", "split"]
 TS480_SKIP = ["", "S"]
 
 # start at 0:LSB
@@ -133,7 +135,6 @@
     #       If rsplen = 0 then do not read after write
 
     start = time.time()
-    #   LOCK.acquire()
     stx = cmd       # preserve cmd for response check
     stx = stx + exts + ";"    # append arguments
     ser.write(stx)
@@ -146,7 +147,6 @@
         result = ser.read(rsplen)
         LOG.debug("RADIO->PC [%s]" % result)
         result = result[:-1]        # remove terminator
-    #   LOCK.release()
     return result.strip()
 
 
@@ -166,10 +166,10 @@
         BAUD = bd
         radio.pipe.write(";")
         radio.pipe.write(";")
-        resp = radio.pipe.read(4)
+        resp = radio.pipe.read(16)
         radio.pipe.write("ID;")
-        resp = radio.pipe.read(6)
-        if resp == radio.ID:           # Good comms
+        resp = radio.pipe.read(16)
+        if resp.find(radio.ID) >= 0:           # Good comms
             resp = command(radio.pipe, "AI0", 0, W8L)
             return
         elif resp in RADIO_IDS.keys():
@@ -248,15 +248,6 @@
     return dx
 
 
-def _sets_val(stx, nv, nb):
-    """ Split string stx into nv nb-bit values in 1 byte """
-    # Right now: hardcoded for nv:3 values of nb:2 bits each
-    v1 = int(stx[0]) << 6
-    v1 = v1 | (int(stx[1]) << 4)
-    v1 = v1 | (int(stx[2]) << 2)
-    return chr(v1)
-
-
 def _sets_asf(stx):
     """ Process AS0 auto-mode setting """
     asm = _make_dat(stx[0:11], 4)   # 11-bit freq
@@ -337,6 +328,8 @@
             setts += _make_dat(result0, 4)   # 11-bit freq
         elif (cmc == "MF0") or (cmc == "MF1"):  # No stored response
             skipme = True
+        elif (cmc == "TY"):     # remove upper 2 digits
+            result0 = result0[2:]
         # Generic single byte processing
         if not skipme:
             setts += chr(int(result0))
@@ -359,7 +352,7 @@
     # UI progress
     status = chirp_common.Status()
     status.cur = 0
-    status.max = radio._upper + 10  # 10 P chans
+    status.max = radio._upper
     status.msg = "Writing Channel Memory"
     radio.status_fn(status)
 
@@ -367,15 +360,19 @@
     BEEPVOL = int(result0[6:12])
     result0 = command(radio.pipe, "EX01200000", 0, W8L)   # Silence beeps
 
-    for chn in range(0, (radio._upper + 11)):   # Loop stops at +20
+    for chn in range(0, (radio._upper + 1)):
         _mem = radio._memobj.ch_mem[chn]
         cmx = "MW0%03i" % chn
-        stm = cmx + radio._make_base_spec(_mem, _mem.rxfreq)
-        result0 = command(radio.pipe, stm, 0, W8L)     # No response
-        if _mem.txfreq > 0:            # Don't write MW1 if empty/deleted
-            cmx = "MW1%03i" % chn
-            stm = cmx + radio._make_base_spec(_mem, _mem.txfreq)
+        if _mem.rxfreq == 0:            # Empty, deleted
+            stm = cmx + "0" * 35
             result0 = command(radio.pipe, stm, 0, W8L)
+        else:
+            stm = cmx + radio._make_base_spec(_mem, _mem.rxfreq)
+            result0 = command(radio.pipe, stm, 0, W8L)     # No response
+            if _mem.split:     # SPLIT mode
+                cmx = "MW1%03i" % chn
+                stm = cmx + radio._make_base_spec(_mem, _mem.txfreq)
+                result0 = command(radio.pipe, stm, 0, W8L)
         status.cur = chn
         radio.status_fn(status)
     return
@@ -454,8 +451,8 @@
 
 
 @directory.register
-class TS480Radio(chirp_common.CloneModeRadio):
-    """Kenwood TS-590"""
+class TS480_CRadio(chirp_common.CloneModeRadio):
+    """ Kenwood TS-480 simulated clone mode """
     VENDOR = "Kenwood"
     MODEL = "TS-480_CloneMode"
     ID = "ID020;"
@@ -491,7 +488,7 @@
     def get_features(self):
         rf = chirp_common.RadioFeatures()
 
-        rf.can_odd_split = False
+        rf.can_odd_split = True
         rf.has_bank = False
         rf.has_ctone = True
         rf.has_dtcs = False
@@ -582,10 +579,11 @@
     def get_memory(self, number):
         """Convert raw channel data (_mem) into UI columns (mem)"""
         mem = chirp_common.Memory()
-        if number > 99 and number < 110:
-            return          # Don't show VFO edges as mem chans
         _mem = self._memobj.ch_mem[number]
         mem.number = number
+        # --- Correct old img file loads with +/- offsets ---
+        if (_mem.txfreq != 0) and (_mem.rxfreq != _mem.txfreq):
+            _mem.split = 1
         mnx = ""
         for char in _mem.name:
             mnx += chr(char)
@@ -598,13 +596,10 @@
         mem.freq = int(_mem.rxfreq)
         mem.duplex = TS480_DUPLEX[0]    # None by default
         mem.offset = 0
-        if _mem.rxfreq < _mem.txfreq:   # + shift
-            mem.duplex = TS480_DUPLEX[2]
-            mem.offset = _mem.txfreq - _mem.rxfreq
-        if _mem.rxfreq > _mem.txfreq:   # - shift
+        if _mem.split:              # NO +/- Offsets, just split
             mem.duplex = TS480_DUPLEX[1]
-            mem.offset = _mem.rxfreq - _mem.txfreq
-        if _mem.txfreq == 0:
+            mem.offset = _mem.txfreq
+        elif _mem.txfreq == 0:
             # leave offset alone, or run_tests will bomb
             mem.duplex = TS480_DUPLEX[0]
         mx = _mem.xmode - 1     # CAT modes start at 1
@@ -635,6 +630,7 @@
         if mem.empty:
             _mem.rxfreq = 0
             _mem.txfreq = 0
+            _mem.split = 0
             _mem.xmode = 0
             _mem.step = 0
             _mem.tmode = 0
@@ -656,10 +652,12 @@
                     _mem.name[ix] = " "    # assignment needs 8 chrs
         _mem.rxfreq = mem.freq
         _mem.txfreq = 0
-        if mem.duplex == "+":
-            _mem.txfreq = mem.freq + mem.offset
-        if mem.duplex == "-":
-            _mem.txfreq = mem.freq - mem.offset
+        _mem.split = 0
+        if mem.duplex == "":
+            _mem.txfreq = _mem.rxfreq
+        elif mem.duplex == "split":
+            _mem.split = 1
+            _mem.txfreq = mem.offset
         ix = TS480_MODES.index(mem.mode)
         _mem.xmode = ix + 1     # stored as CAT values, LSB= 1
         if ix == 7:     # FSK-R
@@ -682,29 +680,27 @@
 
     def _parse_mem_spec(self, spec0, spec1):
         """ Extract ascii memory paramters; build data string """
-        # spec0 is simplex result, spec1 is split
+        # spec0 is Rx freq string, spec1 is Tx
         # pad string so indexes match Kenwood docs
         spec0 = "x" + spec0  # match CAT document 1-based description
         ix = len(spec0)
         # _pxx variables are STRINGS
-        _p1 = spec0[3]       # P1    Split Specification
+        _p1 = spec0[3]       # P1    Tx/Rx Specification
         _p3 = spec0[5:7]     # P3    Memory Channel
-        _p4 = spec0[7:18]    # P4    Frequency
+        _p4 = spec0[7:18]    # P4    Rx Frequency
         _p5 = spec0[18]      # P5    Mode
         _p6 = spec0[19]      # P6    Chan Lockout (Skip)
         _p7 = spec0[20]      # P7    Tone Mode
         _p8 = spec0[21:23]   # P8    Tone Frequency Index
-        if _p8 == "00":
-            _p8 = "08"
         _p9 = spec0[23:25]   # P9    CTCSS Frequency Index
-        if _p9 == "00":
-            _p9 = "08"
         _p14 = spec0[39:41]  # P14   Step Size
         _p16 = spec0[41:50]  # P16   Max 8-Char Name if assigned
 
         spec1 = "x" + spec1
-        _p4s = int(spec1[7:18])  # P4: Offset freq
-
+        _p4s = spec1[7:18]   # P4s: Tx freq
+        _split = 0
+        if _p4 != _p4s:
+            _split = 16     # upper byte bit 0 set
         datm = ""   # Fill in MEM_FORMAT sequence
         datm += _make_dat(_p4, 4)   # rxreq: u32, 4 bytes/chars
         datm += _make_dat(_p4s, 4)  # tx freq
@@ -712,7 +708,7 @@
         datm += chr(int(_p7))       # Tmode: 0-3
         datm += chr(int(_p8))       # rtone: 00-41
         datm += chr(int(_p9))       # ctone: 00-41
-        datm += chr(int(_p6))       # skip: 0/1
+        datm += chr(int(_p6) + _split)       # split 0/1 & skip: 0/1
         datm += chr(int(_p14))      # step: 0-9
         v1 = len(_p16)
         for ix in range(8):
@@ -723,6 +719,7 @@
         return datm
 
     def _make_base_spec(self, mem, freq):
+        """ Generate memory channel parameter string """
         spec = "%011i%1i%1i%1i%02i%02i00000000000000%02i0%s" \
             % (freq, mem.xmode, mem.skip, mem.tmode, mem.rtone,
                 mem.ctone, mem.step, mem.name)
@@ -823,7 +820,8 @@
 
         options = ["TS-480HX (200W)", "TS-480SAT (100W + AT)",
                    "Japanese 50W type", "Japanese 20W type"]
-        rx = RadioSettingValueString(14, 22, options[_sets.ty])
+        nx = _sets.ty & 7      # Can have 'reserved' upper 2 digits
+        rx = RadioSettingValueString(14, 22, options[nx])
         rset = RadioSetting("settings.ty", "FirmwareVersion", rx)
         rset.set_apply_callback(_my_readonly, _sets, "ty")
         basic.append(rset)
@@ -857,7 +855,7 @@
         if vx < 5:
             vx = 5
         options = [200, 100, 50, 20]    # subject to firmware
-        rx = RadioSettingValueInteger(5, options[_sets.ty], vx, nx)
+        rx = RadioSettingValueInteger(5, options[_sets.ty & 7], vx, nx)
         sx = "TX Output power (Watts)"
         rset = RadioSetting("settings.pc", sx, rx)
         basic.append(rset)
@@ -1142,3 +1140,12 @@
                     LOG.debug(element.get_name())
                     raise
         return
+
+    @classmethod
+    def match_model(cls, fdata, fyle):
+        """ Included to prevent 'File > New' error """
+        # Test the file data size
+        if len(fdata) == MEMSIZE:
+            return True
+        else:
+            return False
diff -r 5249ae1ee57b -r 8f16194724cc tests/images/Kenwood_TS-480_CloneMode.img
Binary file tests/images/Kenwood_TS-480_CloneMode.img has changed
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Kenwood_TS-480_CloneMode.img
Type: application/octet-stream
Size: 3052 bytes
Desc: not available
Url : http://intrepid.danplanet.com/pipermail/chirp_devel/attachments/20210306/742e6fe1/attachment-0001.img 


More information about the chirp_devel mailing list