[chirp_devel] New IC-7300 Driver
Rick (AA0RD) DeWitt
Tue Sep 15 14:03:18 PDT 2020
New IC-7300 driver, Issue #4013.
--
Rick DeWitt
AA0RD
Sequim, Washington, USA 98382
(360) 681-3494
-------------- next part --------------
# HG changeset patch
# User Rick DeWitt <aa0rd at yahoo.com>
# Date 1600203299 25200
# Tue Sep 15 13:54:59 2020 -0700
# Node ID 077d24409132b77412b4f353f48acf9c07a4f1f4
# Parent 2d7b5508d8950df775754f0587b7c7856e1c2302
[ic7300] New driver for Icom IC-7300. Issue #4013
diff -r 2d7b5508d895 -r 077d24409132 chirp/drivers/ic7300.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chirp/drivers/ic7300.py Tue Sep 15 13:54:59 2020 -0700
@@ -0,0 +1,779 @@
+# Copyright 2020 Rick DeWitt <aa0rd at yahoo.com>
+# Icom IC-7300 Vers 1.0: Channel memory and some important settings
+# Using CI-V data requests to generate a memory block
+# Vers 1.0 uses py3 bytes()
+# 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
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import time
+import struct
+import logging
+import re
+import math
+from chirp import chirp_common, directory, memmap
+from chirp import bitwise, errors, util
+from chirp.settings import RadioSettingGroup, RadioSetting, \
+ RadioSettingValueBoolean, RadioSettingValueList, \
+ RadioSettingValueString, RadioSettingValueInteger, \
+ RadioSettingValueFloat, RadioSettings, InvalidValueError
+from textwrap import dedent
+
+LOG = logging.getLogger(__name__)
+
+HAS_FUTURE = True
+try: # PY3 compliance
+ from builtins import bytes
+except ImportError:
+ HAS_FUTURE = False
+ LOG.warning('python-future package is not '
+ 'available; %s requires it' % __name__)
+
+
+MEM_FORMAT = """
+#seekto 0x0000;
+struct { // 32 bytes per chan
+ u8 split:4, // My CI-V format, not an image
+ selmem:4;
+ ul32 rxfreq;
+ ul32 txfreq;
+ u8 tmode;
+ u8 fltr;
+ u8 data:4,
+ tone:4;
+ u8 rcts;
+ u8 tsql;
+ char name[10];
+ u8 chpad[8];
+} ch_mem[99];
+
+struct {
+ u8 rfpwr;
+ u8 beepv;
+ ul16 hf_ofst;
+ ul16 m6_ofst;
+ u8 scrnsav;
+ char msg[10];
+ u8 uprflgs:3,
+ rfpwron:1,
+ cfmbeep:1,
+ opnmsg:1,
+ hfsign:1,
+ m6sign:1;
+} settings;
+
+"""
+# === Globals ====
+TMODES = ["", "Tone", "TSQL"]
+DUPLEX = ["", "-", "+"]
+MODES = ["LSB", "USB", "AM", "CW", "RTTY", "FM", "CWR", "RTTYR",
+ "Data+LSB", "Data+USB"]
+TONES = list(chirp_common.TONES)
+FILTER = ["FIL1", "FIL2", "FIL3"]
+STIMEOUT = 0.6
+BAUD = 115200
+BAUDRATES = [115200, 57600, 38400, 19200, 9600, 4800, 2400]
+
+
+def _setbaud(radio):
+ """ Determine fastest valid baud rate """
+ global BAUD
+ radio.pipe.timeout = 0.1
+ for BAUD in BAUDRATES: # Attempt to read CI-V Transceiver status
+ radio.pipe.baudrate = BAUD
+ radio.pipe.write("\xFE\xFE\x94\xE0\x1A\x05\x00\x71\xFD")
+ resp = radio.pipe.read(55)
+ if len(resp) > 17:
+ if resp[17] == "\x01":
+ break # exit For loop
+ if BAUD < 4800:
+ msg = "Unable to coomunicate with radio! Cable? Power?"
+ raise errors.RadioError(msg)
+ LOG.debug("Baud Rate is %d" % BAUD)
+ radio.pipe.timeout = STIMEOUT
+ return
+
+
+def dbg_dump(stz, kn=32, cptn="DBG", ax=False, lgx=1, ndx=False):
+ """ Debugging tool to print up to kn hex values of string stz """
+ # ax: flag to append ascii, lgx: Log code (bits) 1=Warning, 2=Debug
+ sx = ""
+ kx = len(stz)
+ if kx > kn:
+ kx = kn
+ for ix in range(kx):
+ sx += "%02x " % ord(stz[ix])
+ if ax: # append as ascii
+ sx += " ["
+ for ix in range(kx):
+ if ord(stz[ix]) > 31 and ord(stz[ix]) < 127:
+ sx += "%s" % stz[ix]
+ else:
+ sx += "."
+ sx += "]"
+ if lgx & 1:
+ LOG.warning("%s: %s" % (cptn, sx))
+ if ndx: # write an index line below
+ ixl = "%s: " % cptn
+ for ix in range(kx):
+ ixl += "%02i " % ix
+ LOG.warning("%s" % ixl)
+ if lgx & 2:
+ LOG.debug("%s: %s" % (cptn, sx))
+ return
+
+
+def _rhcd_decode(stx, nbyt, lgw=False):
+ """ Decode decimal value from reverse-hex stx backwards starting
+ at nbyt index. 4 for freq, 3 for offset.
+ Returns 4-byte UL32 string. Ignore upper 0's if format is less"""
+ vstr = ""
+ for ix in range(nbyt-1, -1, -1):
+ vstr += "%02x" % ord(stx[ix])
+ vx = int(vstr)
+ if lgw:
+ LOG.warning("vstr: %s, vs: %04x" % (vstr, vx))
+ vstr = chr(vx & 255)
+ vx = vx >> 8
+ vstr += chr(vx & 255)
+ vx = vx >> 8
+ vstr += chr(vx & 255)
+ vx = vx >> 8
+ vstr += chr(vx & 255)
+ return vstr
+
+
+def _fhdc_decode(stx, nbyt, lgw=False):
+ """ Decode decimal value from hex string stx, not reversed.
+ nbyt is length """
+ vstr = ""
+ for ix in range(0, nbyt): # Decode hcd rcts
+ vstr += "%02x" % ord(stx[ix])
+ vx = int(vstr)
+ if lgw: # print values
+ LOG.warning("fhdc vstr: %s, vx: %i" % (vstr, vx))
+ return vx
+
+
+def _encode_chn(chnum):
+ """ Channel pair must be encoded as hex coded decimal """
+ c1 = 0
+ if chnum < 10:
+ c2 = chnum
+ elif chnum > 9 and chnum < 20:
+ c2 = chnum + 6
+ elif chnum > 19 and chnum < 30:
+ c2 = chnum + 12
+ elif chnum > 29 and chnum < 40:
+ c2 = chnum + 18
+ elif chnum > 39 and chnum < 50:
+ c2 = chnum + 24
+ elif chnum > 49 and chnum < 60:
+ c2 = chnum + 30
+ elif chnum > 59 and chnum < 70:
+ c2 = chnum + 36
+ elif chnum > 69 and chnum < 80:
+ c2 = chnum + 42
+ elif chnum > 79 and chnum < 90:
+ c2 = chnum + 48
+ elif chnum > 89 and chnum < 100:
+ c2 = chnum + 54
+ elif chnum > 99:
+ c1 = 1
+ c2 = chnum - 100
+ chstr = chr(c1) + chr(c2)
+ return chstr
+
+
+def _read_mem(radio):
+ """Generate the memory map. """
+ radio.pipe.baudrate = BAUD
+ # Flush the input buffer
+ radio.pipe.timeout = 0.005
+ junk = radio.pipe.read(256)
+ radio.pipe.timeout = STIMEOUT
+
+ status = chirp_common.Status()
+ status.cur = 0
+ status.max = radio._upper + 10 # 10 settings
+ status.msg = "Reading Memory..."
+ radio.status_fn(status)
+
+ mtx = ""
+ for ix in range(0, 32): # blank channel block
+ mtx += chr(0)
+ memdat = ""
+ preamble = "\xFE\xFE\x94\xE0\x1A\x00"
+ for chn in range(1, 100): # 1-99
+ vstr = _encode_chn(chn)
+ cmdx = preamble + vstr + "\xFD"
+ radio.pipe.write(cmdx)
+ resp = radio.pipe.read(18) # read only the echo and Split bytes
+ if resp[17] == "\xFF": # This chan is empty
+ memdat += mtx
+ resp = radio.pipe.read(1) # the trailing FD
+ else: # read the rest and decode
+ split = resp[17]
+ resp = radio.pipe.read(39)
+ resp = split + resp[:38] # strip trailing FD
+ memdat += resp[0] # split & selmem
+ memdat += _rhcd_decode(resp[1:6], 4) # rxfreq string
+ memdat += _rhcd_decode(resp[15:20], 4) # txfreq
+ memdat += resp[6] # tmode
+ vstr = resp[7] # IF Filter
+ if vstr == "\x00": # Not valid, must be 1 - 3
+ vstr = "\x01"
+ memdat += vstr
+ memdat += resp[8] # data & tone
+ v2 = _fhdc_decode(resp[9:], 3) # Decode hcd rcts
+ vx = float(v2) / 10
+ ix = TONES.index(vx)
+ memdat += chr(ix)
+ v2 = _fhdc_decode(resp[12:], 3) # Decode hcd tsql
+ vx = float(v2) / 10
+ ix = TONES.index(vx)
+ memdat += chr(ix)
+ memdat += resp[29:] # name
+ memdat += mtx[0:8] # pad
+ # UI Update
+ status.cur = chn
+ radio.status_fn(status)
+ # End for chn loop
+ if len(memdat) == 0: # To satisfy run_tests
+ raise errors.RadioError('No data received.')
+ # Read some settings
+ vbits = 0
+ radio.pipe.write("\xFE\xFE\x94\xE0\x14\x0A\xFD") # 14 0A: RF Power
+ resp = radio.pipe.read(16)
+ rfp = _fhdc_decode(resp[13:], 2) # Decode rf power 0-255
+ memdat += chr(rfp)
+ status.cur += 1
+ radio.status_fn(status)
+ radio.pipe.write("\xFE\xFE\x94\xE0\x1A\x05\x00\x21\xFD")
+ resp = radio.pipe.read(20) # Beep volume 00-255
+ bpv = _fhdc_decode(resp[17:], 2)
+ memdat += chr(bpv)
+ radio.pipe.write("\xFE\xFE\x94\xE0\x1A\x05\x00\x31\xFD")
+ resp = radio.pipe.read(22) # HF Offset
+ ohfs = _rhcd_decode(resp[17:], 3) # 4-byte RHCD string
+ memdat += ohfs[:2] # only store as 16 bit
+ status.cur += 1
+ radio.status_fn(status)
+ if resp[20] == "\x01": # sign bit set
+ vbits += 2
+ radio.pipe.write("\xFE\xFE\x94\xE0\x1A\x05\x00\x32\xFD")
+ resp = radio.pipe.read(22) # 6m Offset
+ o6ms = _rhcd_decode(resp[17:], 3)
+ memdat += o6ms[:2]
+ status.cur += 1
+ radio.status_fn(status)
+ if resp[20] == "\x01":
+ vbits += 1
+ radio.pipe.write("\xFE\xFE\x94\xE0\x1A\x05\x00\x89\xFD")
+ resp = radio.pipe.read(19) # Screen Saver Timeout
+ memdat += resp[17]
+ status.cur += 1
+ radio.status_fn(status)
+ radio.pipe.write("\xFE\xFE\x94\xE0\x1A\x05\x00\x23\xFD")
+ resp = radio.pipe.read(19) # Confirmation Beep
+ if resp[17] == "\x01":
+ vbits += 8
+ status.cur += 1
+ radio.status_fn(status)
+ radio.pipe.write("\xFE\xFE\x94\xE0\x1A\x05\x00\x90\xFD")
+ resp = radio.pipe.read(19) # Opening Msg on/off
+ if resp[17] == "\x01":
+ vbits += 4
+ status.cur += 1
+ radio.status_fn(status)
+ radio.pipe.write("\xFE\xFE\x94\xE0\x1A\x05\x00\x92\xFD")
+ resp = radio.pipe.read(19) # Show RF power at power on
+ if resp[17] == "\x01":
+ vbits += 16
+ status.cur += 1
+ radio.status_fn(status)
+ radio.pipe.write("\xFE\xFE\x94\xE0\x1A\x05\x00\x91\xFD")
+ resp = radio.pipe.read(30) # Opening Msg contents: 10 chars
+ memdat += resp[17:27]
+ status.cur += 1
+ radio.status_fn(status)
+ memdat += chr(vbits)
+ return memdat
+
+
+def _rhcd_encode(inum):
+ """ Convert integer inum into reverse hex coded decimal string """
+ sval = "%010d" % inum
+ hval = chr(int(sval[8:], 16)) + chr(int(sval[6:8], 16))
+ hval += chr(int(sval[4:6], 16)) + chr(int(sval[2:4], 16))
+ hval += chr(int(sval[:2], 16))
+ return hval # 5 bytes
+
+
+def _fhcd_encode(inum):
+ """ Convert integer inum into forward hex coded decimal string """
+ sval = "%010d" % inum
+ hval = chr(int(sval[:2], 16)) + chr(int(sval[2:4], 16))
+ hval += chr(int(sval[4:6], 16)) + chr(int(sval[6:8], 16))
+ hval += chr(int(sval[8:], 16))
+ return hval # 5 bytes
+
+
+def _sendcmd(radio, stat, cmds, dbg=0):
+ """ Send the cmds command string to the radio
+ and show debugging strings based on dbg bits set
+ dbg = 1: show outbound command string
+ dbg = 2: show returned status string
+ dbg = 4: DO NOT actually send the string, just show it """
+ if dbg & 5:
+ dbg_dump(cmds, 99, ">>", False, 1, True)
+ if (dbg & 4) == 0:
+ radio.pipe.write(cmds)
+ kx = len(cmds) + 6 # Cmds echo and status
+ stx = radio.pipe.read(kx) # Read status
+ if dbg & 2:
+ dbg_dump(stx, 99, "<<", False, 1, True)
+ slx = len(stx)
+ if slx < kx:
+ msg = "No response from radio. Cable? Power?"
+ raise errors.RadioError(msg)
+ # Raise error if next to last status char is not \xFB
+ if stx[slx - 2] != "\xFB":
+ msg = "Verification error writing to radio."
+ raise errors.RadioError(msg)
+ stat.cur += 1
+ radio.status_fn(stat)
+ return
+
+
+def _write_mem(radio):
+ """ Send CI-V data to radio """
+ radio.pipe.baudrate = BAUD
+ # Flush the input buffer
+ radio.pipe.timeout = 0.005
+ junk = radio.pipe.read(256)
+ radio.pipe.timeout = STIMEOUT
+
+ status = chirp_common.Status()
+ status.cur = 0
+ status.max = radio._upper + 7 # 8 settings
+ status.msg = "Writing Memory..."
+ radio.status_fn(status)
+
+ preamble = "\xFE\xFE\x94\xE0\x1A\x00"
+ for chn in range(1, 100):
+ _mem = radio._memobj.ch_mem[chn - 1]
+ vstr = _encode_chn(chn)
+ cmdx = preamble + vstr
+ if _mem.rxfreq == 0:
+ cmdx += "\xFF\xFD"
+ else:
+ datstr = chr((_mem.split << 4) + _mem.selmem)
+ datstr += _rhcd_encode(_mem.rxfreq)
+ datstr += chr(_mem.tmode)
+ if _mem.fltr < 1: # Not allowed
+ _mem.fltr = 1
+ datstr += chr(_mem.fltr)
+ datstr += chr((_mem.data << 4) + _mem.tone)
+ datstr += _fhcd_encode(TONES[_mem.rcts] * 10.0)[2:]
+ datstr += _fhcd_encode(TONES[_mem.tsql] * 10.0)[2:]
+ # Repeat tx freq and same tmode, fltr, data, tone, rcts, tsql
+ datstr += _rhcd_encode(_mem.txfreq)
+ datstr += chr(_mem.tmode)
+ datstr += chr(_mem.fltr)
+ datstr += chr((_mem.data << 4) + _mem.tone)
+ datstr += _fhcd_encode(TONES[_mem.rcts] * 10.0)[2:]
+ datstr += _fhcd_encode(TONES[_mem.tsql] * 10.0)[2:]
+ datstr += str(_mem.name)
+ cmdx += datstr + "\xFD"
+ _sendcmd(radio, status, cmdx)
+ # Send Settings
+ _sets = radio._memobj.settings
+ preamble = "\xFE\xFE\x94\xE0"
+ vstr = _fhcd_encode(int(_sets.rfpwr))[4:] # RF Power 0-255 hcd
+ cmdx = "%s\x14\x0A%s\xFD" % (preamble, vstr)
+ _sendcmd(radio, status, cmdx)
+ vstr = chr(int(_sets.rfpwron)) # RF power msg at poweron
+ cmdx = "%s\x1A\x05\x00\x92%s\xFD" % (preamble, vstr)
+ _sendcmd(radio, status, cmdx)
+ vstr = str(_sets.msg).upper() # Requires uppercase
+ cmdx = "%s\x1A\x05\x00\x91%s\xFD" % (preamble, vstr) # opening msg
+ _sendcmd(radio, status, cmdx)
+ vstr = chr(int(_sets.cfmbeep)) # Confirmation beep
+ cmdx = "%s\x1A\x05\x00\x92%s\xFD" % (preamble, vstr)
+ _sendcmd(radio, status, cmdx)
+ vstr = _fhcd_encode(int(_sets.beepv))[4:] # Beep volume 0-255
+ cmdx = "%s\x1A\x05\x00\x21%s\xFD" % (preamble, vstr)
+ _sendcmd(radio, status, cmdx)
+ vstr = chr(int(_sets.scrnsav)) # Screen saver timeout
+ cmdx = "%s\x1A\x05\x00\x89%s\xFD" % (preamble, vstr)
+ _sendcmd(radio, status, cmdx)
+ vstr = _rhcd_encode(_sets.hf_ofst)[:3] + chr(int(_sets.hfsign))
+ cmdx = "%s\x1A\x05\x00\x31%s\xFD" % (preamble, vstr)
+ _sendcmd(radio, status, cmdx)
+ vstr = _rhcd_encode(_sets.m6_ofst)[:3] + chr(int(_sets.m6sign))
+ cmdx = "%s\x1A\x05\x00\x32%s\xFD" % (preamble, vstr)
+ _sendcmd(radio, status, cmdx)
+ return
+
+
+ at directory.register
+class IC7300Radio(chirp_common.CloneModeRadio):
+ """Icom IC-7300"""
+ VENDOR = "Icom"
+ MODEL = "IC-7300"
+
+ _upper = 99
+
+ def get_features(self):
+ rf = chirp_common.RadioFeatures()
+ rf.has_settings = True
+ rf.has_dtcs = False
+ rf.has_dtcs_polarity = False
+ rf.has_bank = False
+ rf.memory_bounds = (1, 99)
+ rf.valid_modes = list(MODES)
+ rf.valid_tmodes = list(TMODES)
+ rf.valid_duplexes = list(set(DUPLEX))
+ rf.valid_tuning_steps = list(chirp_common.TUNING_STEPS[0:9])
+ rf.valid_bands = [(1800000, 1999999),
+ (3500000, 3999999),
+ (5255000, 5405000),
+ (7000000, 7300000),
+ (10100000, 10150000),
+ (14000000, 14350000),
+ (18068000, 18168000),
+ (21000000, 21450000),
+ (24890000, 24990000),
+ (28000000, 29700000),
+ (50000000, 54000000),
+ (70000000, 70500000)]
+ rf.valid_skips = ["", "S", "P"]
+ rf_valid_tones = list(TONES)
+ rf.valid_characters = chirp_common.CHARSET_ASCII
+ rf.valid_name_length = 10
+ return rf
+
+ @classmethod
+ def get_prompts(cls):
+ rp = chirp_common.RadioPrompts()
+ rp.info = _(dedent("""\
+ Use the channel 'Properties' window, 'Other' tab to
+ set the IF Filter bandwidth and assign the Selected Memory
+ scan group.
+ """))
+ rp.pre_download = _(dedent("""\
+ Follow these instructions to download your config:
+
+ 1 - Connect a USB type B (Printer) cable to the rear USB jack.
+ 2 - In the radio MENU > SET > Connectors > CI-V
+ Set/Verify the CI-V Baud Rate is "Auto"
+ Set/Verify the CI-V Address is "94h"
+ Set/Verify the CI-V Transeive is "ON"
+ 3 - In the radio MENU > SET > Connectors > USB Serial Function
+ Set/Verify the mode is "CI-V"
+ 4 - Radio > Download from radio
+ """))
+ rp.pre_upload = _(dedent("""\
+ Follow these instructions to upload your config:
+
+ 1 - Verify the MENU configuration is the same as for download.
+ 2 - Connect a USB type B cable to the rear USB jack.
+ 3 - Radio > Upload to radio
+ """))
+ return rp
+
+ def sync_in(self):
+ """Download from radio"""
+ try:
+ _setbaud(self)
+ data = bytes(_read_mem(self))
+ except errors.RadioError:
+ # Pass through any real errors we raise
+ raise
+ except Exception:
+ # If anything unexpected happens, make sure we raise
+ # a RadioError and log the problem
+ LOG.exception('Unexpected error during download')
+ raise errors.RadioError('Unexpected error communicating '
+ 'with the radio')
+
+ self._mmap = memmap.MemoryMapBytes(data)
+ self.process_mmap()
+ return
+
+ def sync_out(self):
+ """Upload to radio"""
+ try:
+ _setbaud(self)
+ _write_mem(self)
+ except errors.RadioError:
+ # Pass through any real errors we raise
+ raise
+ except Exception:
+ # If anything unexpected happens, make sure we raise
+ # a RadioError and log the problem
+ LOG.exception('Unexpected error during upload')
+ raise errors.RadioError('Unexpected error communicating '
+ 'with the radio')
+ return
+
+ def process_mmap(self):
+ """Process the mem map into the mem object"""
+ self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
+ return
+
+ def get_memory(self, number):
+ """Convert raw channel data (_mem) into UI columns (mem)"""
+ mem = chirp_common.Memory()
+ _mem = self._memobj.ch_mem[number - 1]
+ mem.number = number
+ mnx = ""
+ if _mem.rxfreq == 0:
+ mem.empty = True
+ # mem.name = ""
+ # mem.mode = MODES[0]
+ return mem
+ for char in _mem.name:
+ mnx += chr(char)
+ mem.name = mnx.strip()
+ mem.empty = False
+ mem.freq = int(_mem.rxfreq)
+ mem.duplex = DUPLEX[0] # None by default
+ mem.offset = 0
+ if _mem.rxfreq < _mem.txfreq: # + shift
+ mem.duplex = DUPLEX[2]
+ mem.offset = _mem.txfreq - _mem.rxfreq
+ if _mem.rxfreq > _mem.txfreq: # - shift
+ mem.duplex = DUPLEX[1]
+ mem.offset = _mem.rxfreq - _mem.txfreq
+ if _mem.txfreq == 0:
+ # leave offset alone, or run_tests will bomb
+ mem.duplex = DUPLEX[0]
+ mem.mode = MODES[_mem.tmode + (_mem.data * 8)]
+ mem.tmode = TMODES[_mem.tone]
+ mem.ctone = TONES[_mem.tsql]
+ mem.rtone = TONES[_mem.rcts]
+
+ # Extra
+ mem.extra = RadioSettingGroup("extra", "Extra")
+
+ options = ["N/A", "Fil 1: Wide", "Fil 2: Mid", "Fil 3: Narrow"]
+ vx = int(_mem.fltr)
+ if vx == 0:
+ vx = 1
+ rx = RadioSettingValueList(options, options[vx])
+ rset = RadioSetting("fltr", "IF Filter BW", rx)
+ mem.extra.append(rset)
+
+ options = ["None", "*1", "*2", "*3"]
+ vx = int(_mem.selmem)
+ rx = RadioSettingValueList(options, options[vx])
+ rset = RadioSetting("selmem", "Selected Memory Scan Group", rx)
+ mem.extra.append(rset)
+
+ return mem
+
+ def set_memory(self, mem):
+ """Convert UI column data (mem) into MEM_FORMAT memory (_mem)"""
+ _mem = self._memobj.ch_mem[mem.number - 1]
+
+ if mem.empty:
+ _mem.split = 0
+ _mem.selmem = 0
+ _mem.txfreq = 0
+ _mem.rxfreq = 0
+ _mem.tmode = 0
+ _mem.fltr = 1 # fltr can't be <1
+ _mem.data = 0
+ _mem.tone = 0
+ _mem.rcts = 8
+ _mem.tsql = 8
+ _mem.name = " "
+ return
+
+ _mem.rxfreq = mem.freq
+ if mem.duplex == "":
+ _mem.split = 0
+ _mem.txfreq = _mem.rxfreq
+ elif mem.duplex == "+":
+ _mem.txfreq = mem.freq + mem.offset
+ _mem.split = 1
+ else:
+ _mem.txfreq = mem.freq - mem.offset
+ _mem.split = 1
+ if mem.mode == "Data+LSB" or mem.mode == "Data+USB":
+ _mem.tmode = MODES.index(mem.mode) - 8
+ _mem.data = 1
+ else:
+ _mem.tmode = MODES.index(mem.mode)
+ _mem.data = 0
+ _mem.tone = 0
+ if mem.tmode == "Tone":
+ _mem.tone = 1
+ if mem.tmode == "TSQL":
+ _mem.tone = 2
+ _mem.rcts = chirp_common.TONES.index(mem.rtone)
+ _mem.tsql = chirp_common.TONES.index(mem.ctone)
+ _mem.name = mem.name.ljust(10)
+
+ # Extra settings
+ for setting in mem.extra:
+ setattr(_mem, setting.get_name(), setting.value)
+
+ return
+
+ def get_settings(self):
+ """Translate the MEM_FORMAT structs into settings in the UI"""
+ # Define mem struct write-back shortcuts
+ _sets = self._memobj.settings
+ basic = RadioSettingGroup("basic", "Basic Settings")
+ groups = RadioSettings(basic)
+
+ def chars2str(cary, knt):
+ """Convert raw memory char array to a string.
+ NOT a callback."""
+ stx = ""
+ for char in cary[:knt]:
+ stx += chr(char)
+ stx = stx.ljust(10)
+ return stx
+
+ def _do_ofst(setting, obj, atrb, arg):
+ """ Adjust the offset freq and sset sign bit """
+ sv = str(setting.value)
+ vz = float(sv)
+ if atrb == "hf_ofst":
+ if vz < 0:
+ setattr(obj, "hfsign", 1)
+ vz = abs(vz)
+ else:
+ setattr(obj, "hfsign", 0)
+ else:
+ if vz < 0:
+ setattr(obj, "m6sign", 1)
+ vz = abs(vz)
+ else:
+ setattr(obj, "m6sign", 0)
+ vz = vz * arg
+ setattr(obj, atrb, int(vz))
+ return
+
+ def _domath(setting, obj, atrb, opr, arg):
+ """ Apply a math operation to the modified atrb
+ If opr = "M" then multiply by arg, else add arg. """
+ sv = str(setting.value)
+ vz = float(sv)
+ if opr == "M":
+ vz = vz * arg
+ else:
+ vz = vz + arg
+ setattr(obj, atrb, int(vz))
+ return
+
+ # --- Basic
+ vlu = int(_sets.rfpwr) // 2.55
+ rx = RadioSettingValueInteger(0, 100, vlu)
+ rset = RadioSetting("settings.rfpwr",
+ "RF Power (%)", rx)
+
+ rset.set_apply_callback(_domath, _sets, "rfpwr", "M", 2.55)
+ basic.append(rset)
+
+ rx = RadioSettingValueBoolean(bool(_sets.rfpwron))
+ rset = RadioSetting("settings.rfpwron",
+ "Show RF Power at power on", rx)
+ basic.append(rset)
+
+ rx = RadioSettingValueBoolean(bool(_sets.opnmsg))
+ rset = RadioSetting("settings.opnmsg",
+ "Show MyCall message at power on", rx)
+ basic.append(rset)
+
+ tmp = chars2str(_sets.msg, 10)
+ rx = RadioSettingValueString(0, 10, tmp)
+ rset = RadioSetting("settings.msg",
+ "MyCall Power-on message", rx)
+ basic.append(rset)
+
+ rx = RadioSettingValueBoolean(bool(_sets.cfmbeep))
+ rset = RadioSetting("settings.cfmbeep", "Confirmation Beep", rx)
+ basic.append(rset)
+
+ vlu = int(_sets.beepv / 2.55)
+ rx = RadioSettingValueInteger(0, 255, vlu)
+ rset = RadioSetting("settings.beepv",
+ "Confirmation Beep Volume (%)", rx)
+ rset.set_apply_callback(_domath, _sets, "beepv", "M", 2.55)
+ basic.append(rset)
+
+ options = ["Off", "15 Mins", "30 Mins", "60 Mins"]
+ rx = RadioSettingValueList(options, options[_sets.scrnsav])
+ rset = RadioSetting("settings.scrnsav",
+ "Screensaver Timeout", rx)
+ basic.append(rset)
+
+ vlu = int(_sets.hf_ofst)
+ vlu = vlu / 10000.0
+ if _sets.hfsign:
+ vlu = -vlu
+ rx = RadioSettingValueFloat(-9.999, 9.999, vlu, 0.001, 4)
+ rset = RadioSetting("settings.hf_ofst",
+ "HF Band default offset (Mhz)", rx)
+ rset.set_apply_callback(_do_ofst, _sets, "hf_ofst", 10000.0)
+ basic.append(rset)
+
+ vlu = int(_sets.m6_ofst)
+ vlu = vlu / 10000.0
+ if _sets.m6sign:
+ vlu = -vlu
+ rx = RadioSettingValueFloat(-9.999, 9.999, vlu, 0.001, 4)
+ rset = RadioSetting("settings.m6_ofst",
+ "HF Band default offset (Mhz)", rx)
+ rset.set_apply_callback(_do_ofst, _sets, "m6_ofst", 10000.0)
+ basic.append(rset)
+
+ return groups
+
+ def set_settings(self, settings):
+ _settings = self._memobj.settings
+ for element in settings:
+ if not isinstance(element, RadioSetting):
+ self.set_settings(element)
+ continue
+ else:
+ try:
+ name = element.get_name()
+ if "." in name:
+ bits = name.split(".")
+ obj = self._memobj
+ for bit in bits[:-1]:
+ if "/" in bit:
+ bit, index = bit.split("/", 1)
+ index = int(index)
+ obj = getattr(obj, bit)[index]
+ else:
+ obj = getattr(obj, bit)
+ setting = bits[-1]
+ else:
+ obj = _settings
+ setting = element.get_name()
+
+ if element.has_apply_callback():
+ LOG.debug("Using apply callback")
+ element.run_apply_callback()
+ elif element.value.get_mutable():
+ LOG.debug("Setting %s = %s" % (setting, element.value))
+ setattr(obj, setting, element.value)
+ except Exception, e:
+ LOG.debug(element.get_name())
+ raise
diff -r 2d7b5508d895 -r 077d24409132 tools/cpep8.manifest
--- a/tools/cpep8.manifest Tue Sep 08 11:53:20 2020 -0700
+++ b/tools/cpep8.manifest Tue Sep 15 13:54:59 2020 -0700
@@ -43,6 +43,7 @@
./chirp/drivers/ic2720.py
./chirp/drivers/ic2730.py
./chirp/drivers/ic2820.py
+./chirp/drivers/ic7300.py
./chirp/drivers/ic9x.py
./chirp/drivers/ic9x_icf.py
./chirp/drivers/ic9x_icf_ll.py
-------------- next part --------------
./chirp/__init__.py
./chirp/bandplan.py
./chirp/bandplan_au.py
./chirp/bandplan_iaru_r1.py
./chirp/bandplan_iaru_r2.py
./chirp/bandplan_iaru_r3.py
./chirp/bandplan_na.py
./chirp/bitwise.py
./chirp/bitwise_grammar.py
./chirp/chirp_common.py
./chirp/detect.py
./chirp/directory.py
./chirp/drivers/__init__.py
./chirp/drivers/alinco.py
./chirp/drivers/anytone.py
./chirp/drivers/ap510.py
./chirp/drivers/baofeng_uv3r.py
./chirp/drivers/baofeng_wp970i.py
./chirp/drivers/bjuv55.py
./chirp/drivers/btech.py
./chirp/drivers/ft1500m.py
./chirp/drivers/ft1802.py
./chirp/drivers/ft1d.py
./chirp/drivers/ft2800.py
./chirp/drivers/ft2900.py
./chirp/drivers/ft4.py
./chirp/drivers/ft50.py
./chirp/drivers/ft60.py
./chirp/drivers/ft7100.py
./chirp/drivers/ft7800.py
./chirp/drivers/ft817.py
./chirp/drivers/ft818.py
./chirp/drivers/ft857.py
./chirp/drivers/ft90.py
./chirp/drivers/ftm350.py
./chirp/drivers/generic_csv.py
./chirp/drivers/generic_tpe.py
./chirp/drivers/generic_xml.py
./chirp/drivers/h777.py
./chirp/drivers/ic208.py
./chirp/drivers/ic2100.py
./chirp/drivers/ic2200.py
./chirp/drivers/ic2720.py
./chirp/drivers/ic2730.py
./chirp/drivers/ic2820.py
./chirp/drivers/ic7300.py
./chirp/drivers/ic9x.py
./chirp/drivers/ic9x_icf.py
./chirp/drivers/ic9x_icf_ll.py
./chirp/drivers/ic9x_ll.py
./chirp/drivers/icf.py
./chirp/drivers/icomciv.py
./chirp/drivers/icq7.py
./chirp/drivers/ict70.py
./chirp/drivers/ict7h.py
./chirp/drivers/ict8.py
./chirp/drivers/icw32.py
./chirp/drivers/icx8x.py
./chirp/drivers/icx8x_ll.py
./chirp/drivers/id31.py
./chirp/drivers/id51.py
./chirp/drivers/id800.py
./chirp/drivers/id880.py
./chirp/drivers/idrp.py
./chirp/drivers/kenwood_hmk.py
./chirp/drivers/kenwood_itm.py
./chirp/drivers/kenwood_live.py
./chirp/drivers/kguv8d.py
./chirp/drivers/kguv9dplus.py
./chirp/drivers/kyd.py
./chirp/drivers/leixen.py
./chirp/drivers/puxing.py
./chirp/drivers/radioddity_r2.py
./chirp/drivers/rfinder.py
./chirp/drivers/template.py
./chirp/drivers/th350.py
./chirp/drivers/th9800.py
./chirp/drivers/th_uv3r.py
./chirp/drivers/th_uv3r25.py
./chirp/drivers/th_uv8000.py
./chirp/drivers/th_uvf8d.py
./chirp/drivers/thd72.py
./chirp/drivers/thuv1f.py
./chirp/drivers/tk8102.py
./chirp/drivers/tk8180.py
./chirp/drivers/tmd710.py
./chirp/drivers/tmv71.py
./chirp/drivers/tmv71_ll.py
./chirp/drivers/ts480.py
./chirp/drivers/ts590.py
./chirp/drivers/uv5r.py
./chirp/drivers/uvb5.py
./chirp/drivers/vx170.py
./chirp/drivers/vx2.py
./chirp/drivers/vx3.py
./chirp/drivers/vx5.py
./chirp/drivers/vx510.py
./chirp/drivers/vx6.py
./chirp/drivers/vx7.py
./chirp/drivers/vx8.py
./chirp/drivers/vxa700.py
./chirp/drivers/wouxun.py
./chirp/drivers/wouxun_common.py
./chirp/drivers/yaesu_clone.py
./chirp/elib_intl.py
./chirp/errors.py
./chirp/import_logic.py
./chirp/logger.py
./chirp/memmap.py
./chirp/platform.py
./chirp/pyPEG.py
./chirp/radioreference.py
./chirp/settings.py
./chirp/ui/__init__.py
./chirp/ui/bandplans.py
./chirp/ui/bankedit.py
./chirp/ui/clone.py
./chirp/ui/cloneprog.py
./chirp/ui/common.py
./chirp/ui/config.py
./chirp/ui/dstaredit.py
./chirp/ui/editorset.py
./chirp/ui/fips.py
./chirp/ui/importdialog.py
./chirp/ui/inputdialog.py
./chirp/ui/mainapp.py
./chirp/ui/memdetail.py
./chirp/ui/memedit.py
./chirp/ui/miscwidgets.py
./chirp/ui/radiobrowser.py
./chirp/ui/reporting.py
./chirp/ui/settingsedit.py
./chirp/ui/shiftdialog.py
./chirp/util.py
./chirp/xml_ll.py
./chirpc
./chirpw
./locale/check_parameters.py
./rpttool
./setup.py
./share/make_supported.py
./tests/__init__.py
./tests/run_tests
./tests/unit/__init__.py
./tests/unit/base.py
./tests/unit/test_bitwise.py
./tests/unit/test_chirp_common.py
./tests/unit/test_import_logic.py
./tests/unit/test_mappingmodel.py
./tests/unit/test_memedit_edits.py
./tests/unit/test_platform.py
./tests/unit/test_settings.py
./tests/unit/test_shiftdialog.py
./tools/bitdiff.py
./tools/cpep8.py
./tools/img2thd72.py
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Icom_IC-7300.img
Type: application/octet-stream
Size: 3351 bytes
Desc: not available
Url : http://intrepid.danplanet.com/pipermail/chirp_devel/attachments/20200915/3575ce0a/attachment-0001.img
More information about the chirp_devel
mailing list