[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