[chirp_devel] #8987 Adding settings to IC-7300 live mode

Rick (AA0RD) DeWitt
Mon Apr 26 07:21:54 PDT 2021


Feature request #8987 adds settings read/write to IC-7300 live mode.
-- 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://intrepid.danplanet.com/pipermail/chirp_devel/attachments/20210426/4fe81796/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/20210426/4fe81796/attachment-0001.jpg 
-------------- next part --------------
# HG changeset patch
# User Rick DeWitt <aa0rd at yahoo.com>
# Date 1619446451 25200
#      Mon Apr 26 07:14:11 2021 -0700
# Node ID 8f5228c4a5d87cce3b151d975af63ae77f3c817d
# Parent  c04f4296f628b927cfb7a732f42062b32f785e00
[icomciv.py] Add settings to IC-7300 live mode. Feature request #8987

diff -r c04f4296f628 -r 8f5228c4a5d8 chirp/drivers/icomciv.py
--- a/chirp/drivers/icomciv.py	Mon Apr 26 07:07:38 2021 -0700
+++ b/chirp/drivers/icomciv.py	Mon Apr 26 07:14:11 2021 -0700
@@ -1,11 +1,12 @@
-# Latest update: March, 2021 RJ DeWitt added IC-7300
+# Latest update: Apr, 2021 Rick DeWitt added IC7300 Settings
 import struct
 import logging
 from chirp.drivers import icf
 from chirp import chirp_common, util, errors, bitwise, directory
 from chirp.memmap import MemoryMap
 from chirp.settings import RadioSetting, RadioSettingGroup, \
-    RadioSettingValueList, RadioSettingValueBoolean
+    RadioSettingValueList, RadioSettingValueBoolean, RadioSettingValueFloat, \
+    RadioSettingValueString, RadioSettingValueInteger, RadioSettings
 
 LOG = logging.getLogger(__name__)
 
@@ -80,6 +81,31 @@
 char name[16];             // 52-60 Name of station
 """
 
+MEM_IC7300_FORMAT = """
+bbcd number[2];            // 1,2
+u8   spl:4,                // 3 split and select memory settings
+     select:4;
+lbcd freq[5];              // 4-8 receive freq
+u8   mode;                 // 9 operating mode
+u8   filter;               // 10 filter 1-3 (undocumented)
+u8   dataMode:4,           // 11 data mode setting (on or off)
+     tmode:4;              // 11 tone type
+u8   duplex;               // Dummy duplex ===
+bbcd rtone[2];             // 12-14 tx tone freq
+u8   pad2;
+bbcd ctone[2];             // 15-17 tone rx squelch setting
+lbcd freq_tx[5];           // 4-8 transmit freq
+u8   mode_tx;              // 9 tx operating mode
+u8   filter_tx;            // 10
+u8   dataMode_tx:4,        // 11 tx data mode setting (on or off)
+     tmode_tx:4;           // 11 tx tone type
+u8   pad3;
+bbcd rtone_tx[2];          // 12-14 repeater tone freq
+u8   pad4;
+bbcd ctone_tx[2];          // 15-17 tone squelch setting
+char name[10];             // 18-27 Callsign
+"""
+
 MEM_IC910_FORMAT = """
 u8   bank;                 // 1 bank number
 bbcd number[2];            // 2,3
@@ -114,31 +140,6 @@
 char name[9];
 """
 
-MEM_IC7300_FORMAT = """
-bbcd number[2];            // 1,2
-u8   spl:4,                // 3 split and select memory settings
-     select:4;
-lbcd freq[5];              // 4-8 receive freq
-u8   mode;                 // 9 operating mode
-u8   filter;               // 10 filter 1-3 (undocumented)
-u8   dataMode:4,           // 11 data mode setting (on or off)
-     tmode:4;              // 11 tone type
-char pad1;
-bbcd rtone[2];             // 12-14 tx tone freq
-char pad2;
-bbcd ctone[2];             // 15-17 tone rx squelch setting
-lbcd freq_tx[5];           // 4-8 transmit freq
-u8   mode_tx;              // 9 tx operating mode
-u8   filter_tx;            // 10
-u8   dataMode_tx:4,        // 11 tx data mode setting (on or off)
-     tmode_tx:4;           // 11 tx tone type
-char pad3;
-bbcd rtone_tx[2];          // 12-14 repeater tone freq
-char pad4;
-bbcd ctone_tx[2];          // 15-17 tone squelch setting
-char name[10];             // 18-27 Callsign
-"""
-
 SPLIT = ["", "spl"]
 
 
@@ -260,6 +261,14 @@
     FORMAT = MEM_IC7100_FORMAT
 
 
+class IC7300MemFrame(MemFrame):
+    FORMAT = MEM_IC7300_FORMAT
+
+    def get_obj(self):
+        self._data = MemoryMap(str(self._data))
+        return bitwise.parse(self.FORMAT, self._data)
+
+
 class IC910MemFrame(BankMemFrame):
     FORMAT = MEM_IC910_FORMAT
 
@@ -270,14 +279,6 @@
         return bitwise.parse(mem_duptone_format, self._data)
 
 
-class IC7300MemFrame(MemFrame):
-    FORMAT = MEM_IC7300_FORMAT
-
-    def get_obj(self):
-        self._data = MemoryMap(str(self._data))
-        return bitwise.parse(self.FORMAT, self._data)
-
-
 class SpecialChannel(object):
     """Info for special (named) channels"""
 
@@ -561,7 +562,8 @@
             mem.duplex = self._rf.valid_duplexes[memobj.duplex]
 
         if self._rf.can_odd_split and memobj.spl:
-            mem.duplex = "split"
+            if hasattr(memobj, "duplex"):
+                mem.duplex = "split"
             mem.offset = int(memobj.freq_tx)
             mem.immutable = []
         elif hasattr(memobj, "duplexOffset"):
@@ -802,6 +804,173 @@
 
 
 @directory.register
+class Icom7300Radio(IcomCIVRadio):
+    """Icom IC-7300"""
+    MODEL = "IC-7300"
+    _model = "\x94"
+    _template = 100              # Use P1 as blank template
+
+    _SPECIAL_CHANNELS = {
+        "P1": 100,
+        "P2": 101,
+    }
+    _SPECIAL_CHANNELS_REV = dict(zip(_SPECIAL_CHANNELS.values(),
+                                     _SPECIAL_CHANNELS.keys()))
+
+    def _is_special(self, number):
+        return number > 99 or isinstance(number, str)
+
+    def _get_special_info(self, number):
+        info = SpecialChannel()
+        if isinstance(number, str):
+            info.name = "ScanEdge" + number
+            info.channel = self._SPECIAL_CHANNELS[number]
+            info.location = info.channel
+        else:
+            info.location = number
+            info.name = "ScanEdge" + self._SPECIAL_CHANNELS_REV[number]
+            info.channel = info.location
+        return info
+
+    def _initialize(self):
+        self._classes["mem"] = IC7300MemFrame
+        self._rf.has_name = True
+        self._rf.has_settings = True
+        self._rf.has_dtcs = False
+        self._rf.has_dtcs_polarity = False
+        self._rf.has_bank = False
+        self._rf.has_tuning_step = False
+        self._rf.has_nostep_tuning = True
+        self._rf.can_odd_split = True
+        self._rf.memory_bounds = (1, 99)
+        self._rf.valid_modes = [
+            "LSB", "USB", "AM", "CW", "RTTY", "FM", "CWR", "RTTYR",
+            "Data+LSB", "Data+USB", "Data+AM", "N/A", "N/A", "Data+FM"
+        ]
+        self._rf.valid_tmodes = ["", "Tone", "TSQL"]
+        # 7300 uses "split", not duplex: memobj.spl
+        self._rf.valid_duplexes = ["", "split"]  # prevent using memobj.duplex
+        self._rf.valid_bands = [(1800000, 70500000)]
+        self._rf.valid_skips = []
+        self._rf.valid_name_length = 10
+        self._rf.valid_characters = chirp_common.CHARSET_ASCII
+        self._rf.valid_special_chans = sorted(self._SPECIAL_CHANNELS.keys())
+
+    def get_settings(self):
+        bas = RadioSettingGroup("basic", "BASIC")
+        grps = RadioSettings(bas)
+
+        global scrsav
+        scrsav = ["Off", "15 Mins", "30 Mins", "60 Mins"]
+        global bas_list     # Used by set_settings
+        # name, display string, subcmd, len, type, v1, v2
+        # type: 1=bool, 2=int, 3=int %, 4=list, 5=string, 6= Offset freq
+        bas_list = [("PON", "Show RF Power at power on", "\x92", 1, 1, 0, 0),
+                    ("SHMSG", "Show MyCall message at power on", "\x90", 1,
+                     1, 0, 0),
+                    ("MSG", "MyCall Power-on message", "\x91", 10, 5, 0, 0),
+                    ("BPON", "Confirmation Beep", "\x23", 1, 1, 0, 0),
+                    ("BPV", "Beep Volume %", "\x21", 2, 3, 0, 255),
+                    ("SCRN", "Screensaver Timeout", "\x89", 1, 4, scrsav, 0),
+                    ("6MO", "6m FM Offset (MHz)", "\x32", 3, 6, -9.999, 9.999),
+                    ("HFO", "HF FM Offset (MHz)", "\x31", 3, 6,  -9.999,
+                     9.999), ]
+
+        f = Frame()
+        f.set_command(0x1A, 5)
+
+        global bas_elements     # Used by set_settings
+        bas_elements = []
+        dpx = 2     # resp index to 1st data byte
+        for name, disp, sbc, lnx, typ, v1, v2 in bas_list:
+            bas_elements.append(name)
+            f.set_data("\x00" + sbc)
+            LOG.debug("Get '%s' --" % name)
+            f.send(0x94, 0xE0, self.pipe)
+            f.read(self.pipe)
+            resp = f.get_data()[dpx:]
+            if typ == 1:        # Boolean
+                vlu = ord(resp)
+                rs = RadioSetting(name, disp,
+                                  RadioSettingValueBoolean(vlu))
+            elif typ == 2 or typ == 3:       # Integer
+                if typ == 2:        # 1 byte
+                    vlu = int("%02x" % ord(resp))
+                else:      # 2 bytes, 0-255 as 0-100 %, encodes 138 as 01 38
+                    vlu = int("%02x" % ord(resp[0])) * 100
+                    vlu += int("%02x" % ord(resp[1]))
+                    vlu = round(vlu / 2.55)
+                rs = RadioSetting(name, disp,
+                                  RadioSettingValueInteger(v1, v2, vlu))
+            elif typ == 4:      # List
+                vlu = int("%02x" % ord(resp))
+                rs = RadioSetting(name, disp,
+                                  RadioSettingValueList(v1, v1[vlu]))
+            elif typ == 5:      # String
+                stx = resp
+                rs = RadioSetting(name, disp,
+                                  RadioSettingValueString(0, lnx, stx))
+            elif typ == 6:      # Offset Freq
+                vlu = int("%02x" % ord(resp[0])) * 1000.0
+                vlu += int("%02x" % ord(resp[1])) * 100000.0
+                vlu += int("%02x" % ord(resp[2])) * 10000000.0
+                vlu = vlu / 10000000.0
+                if ord(resp[3]) == 1:
+                    vlu = -vlu
+                rs = RadioSetting(name, disp,
+                                  RadioSettingValueFloat(v1, v2, vlu))
+            else:
+                continue
+            bas.append(rs)
+        return grps
+
+    def set_settings(self, settings):
+        for element in settings:
+            elname = element.get_name()
+            if not isinstance(element, RadioSetting):
+                self.set_settings(element)
+                continue
+            if not element.changed():
+                continue
+            if (elname in bas_elements):
+                ndx = bas_elements.index(elname)
+                sbc = bas_list[ndx][2]
+                typ = bas_list[ndx][4]
+                f = Frame()
+                f.set_command(0x1A, 5)
+                if typ == 1:        # Boolean
+                    vlu = int(element.value)
+                    stx = chr(vlu)
+                elif typ == 3:      # 2-byte integer %
+                    vlu = int(element.value)
+                    vsx = "%04d" % (vlu * 2.55)
+                    stx = chr(int(vsx[1:2], 16)) + chr(int(vsx[2:4], 16))
+                elif typ == 4:      # list index
+                    vlu = scrsav.index(str(element.value))
+                    stx = chr(int(vlu), 16)
+                elif typ == 5:      # string
+                    vlu = str(element.value)
+                    stx = vlu
+                elif typ == 6:      # freq + offset. 3 bytes + sign 0/1
+                    vlu = abs(float(str(element.value)))    # Ex: 9.876543
+                    vlu = int(vlu * 1000.0)       # 9876 (no <=100 hz digit)
+                    vsx = str(vlu) + "0"       # '98760', Fixed 100 hz digit
+                    b1 = int(vsx[3:5], 16)     # evaluate as hex
+                    b2 = int(vsx[1:3], 16)
+                    b3 = int(vsx[0], 16)
+                    stx = chr(b1) + chr(b2) + chr(b3)          # 60 87 09
+                    if float(str(element.value)) >= 0:
+                        stx += chr(0)
+                    else:
+                        stx += chr(1)
+                stx = chr(0) + sbc + stx
+                f.set_data(stx)
+                f.send(0x94, 0xE0, self.pipe)
+            else:
+                LOG.error("Unknown element %s" % elname)
+
+
+ at directory.register
 class Icom746Radio(IcomCIVRadio):
     """Icom IC-746"""
     MODEL = "746"
@@ -934,60 +1103,6 @@
         # Use Chirp locations starting with 1
         self._adjust_bank_loc_start = True
 
-
- at directory.register
-class Icom7300Radio(IcomCIVRadio):      # Added March, 2021 by Rick DeWitt
-    """Icom IC-7300"""
-    MODEL = "IC-7300"
-    _model = "\x94"
-    _template = 100              # Use P1 as blank template
-
-    _SPECIAL_CHANNELS = {
-        "P1": 100,
-        "P2": 101,
-    }
-    _SPECIAL_CHANNELS_REV = dict(zip(_SPECIAL_CHANNELS.values(),
-                                     _SPECIAL_CHANNELS.keys()))
-
-    def _is_special(self, number):
-        return number > 99 or isinstance(number, str)
-
-    def _get_special_info(self, number):
-        info = SpecialChannel()
-        if isinstance(number, str):
-            info.name = number
-            info.channel = self._SPECIAL_CHANNELS[number]
-            info.location = info.channel
-        else:
-            info.location = number
-            info.name = self._SPECIAL_CHANNELS_REV[number]
-            info.channel = info.location
-        return info
-
-    def _initialize(self):
-        self._classes["mem"] = IC7300MemFrame
-        self._rf.has_name = True
-        self._rf.has_dtcs = False
-        self._rf.has_dtcs_polarity = False
-        self._rf.has_bank = False
-        self._rf.has_tuning_step = False
-        self._rf.has_nostep_tuning = True
-        self._rf.can_odd_split = True
-        self._rf.memory_bounds = (1, 99)
-        self._rf.valid_modes = [
-            "LSB", "USB", "AM", "CW", "RTTY", "FM", "CWR", "RTTYR",
-            "Data+LSB", "Data+USB", "Data+AM", "N/A", "N/A", "Data+FM"
-        ]
-        self._rf.valid_tmodes = ["", "Tone", "TSQL"]
-        # self._rf.valid_duplexes = ["", "-", "+", "split"]
-        self._rf.valid_duplexes = []     # To prevent using memobj.duplex
-        self._rf.valid_bands = [(1800000, 70500000)]
-        self._rf.valid_skips = []
-        self._rf.valid_name_length = 10
-        self._rf.valid_characters = chirp_common.CHARSET_ASCII
-        self._rf.valid_special_chans = sorted(self._SPECIAL_CHANNELS.keys())
-
-
 CIV_MODELS = {
     (0x76, 0xE0): Icom7200Radio,
     (0x88, 0xE0): Icom7100Radio,


More information about the chirp_devel mailing list