[chirp_devel] [PATCH] [ic2730a] Add support for Icom IC-2730A. Fixes #2745
Rhett Robinson
Sun Jan 14 15:03:00 PST 2018
# HG changeset patch
# User Rhett Robinson <rrhett at gmail.com>
# Date 1515970977 28800
# Sun Jan 14 15:02:57 2018 -0800
# Node ID 30023a69e963ce27fbdbe2dd30fe5e5db0c7dfbe
# Parent ebcb6aeda1b85ef516247e69b21c24d33cd1d423
[ic2730a] Add support for Icom IC-2730A. Fixes #2745.
diff -r ebcb6aeda1b8 -r 30023a69e963 chirp/drivers/ic2730.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chirp/drivers/ic2730.py Sun Jan 14 15:02:57 2018 -0800
@@ -0,0 +1,273 @@
+# Copyright 2018 Rhett Robinson <rrhett at gmail.com>
+#
+# 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/>.
+
+from chirp.drivers import icf
+from chirp import chirp_common, util, directory, bitwise, memmap
+
+
+# Still missing:
+# - scan edges
+# - priority watch
+# - hope channel beep
+# - DTMF memory
+# - weather channel alert
+MEM_FORMAT = """
+struct {
+ u24 freq;
+ u16 offset;
+ u8 tune_step:4,
+ unknown5:3,
+ mode:1;
+ u8 unknown6:2,
+ rtone:6;
+ u8 unknown7:2,
+ ctone:6;
+ u8 dtcs;
+ u8 dtcs1;
+ u8 tmode:4,
+ duplex:2,
+ dtcs_polarity:2;
+ char name[6];
+} memory[1002];
+
+#seekto 0x42c0;
+u8 used_flags[125];
+
+#seekto 0x433e;
+u8 skip_flags[125];
+u8 pskip_flags[125];
+
+#seekto 0x4440;
+struct {
+ u8 bank;
+ u8 index;
+} bank_info[1000];
+
+#seekto 0x4c50;
+struct {
+ char name[6];
+} bank_names[10];
+
+#seekto 0x5004;
+u8 unknown12:4,
+ autorptr:2,
+ unknown13:2;
+
+#seekto 0x5030;
+u8 unknown14:6,
+ backlight:2;
+
+#seekto 0x5056;
+u8 unknown15:6,
+ power:2;
+
+#seekto 0x5220;
+u16 left_memory;
+u16 right_memory;
+
+#seekto 0x5280;
+u16 mem_writes_count;
+"""
+
+# Guessing some of these intermediate values are with the Pocket Beep function,
+# but I haven't reliably reproduced these.
+TMODES = ["", "Tone", "??0", "TSQL", "??1", "DTCS", "TSQL-R", "DTCS-R",
+ "DTC.OFF", "TON.DTC", "DTC.TSQ", "TON.TSQ"]
+DUPLEX = ["", "-", "+"]
+MODES = ["FM", "NFM"]
+DTCSP = ["NN", "NR", "RN", "RR"]
+
+AUTOREPEATER = ["OFF", "DUP", "DUP.TON"]
+
+
+class IC2730Bank(icf.IcomNamedBank):
+ """An IC2730 bank"""
+ def get_name(self):
+ _banks = self._model._radio._memobj.bank_names
+ return str(_banks[self.index].name).rstrip()
+
+ def set_name(self, name):
+ _banks = self._model._radio._memobj.bank_names
+ _banks[self.index].name = str(name).ljust(6)[:6]
+
+
+def _get_special():
+ special = {"C0": 1000,
+ "C1": 1001}
+ return special
+
+
+def _resolve_memory_number(number):
+ if isinstance(number, str):
+ return _get_special()[number]
+ else:
+ return number
+
+
+def _wipe_memory(mem, char):
+ mem.set_raw(char * (mem.size() / 8))
+
+
+ at directory.register
+class IC2730Radio(icf.IcomRawCloneModeRadio):
+ """Icom IC-2730A"""
+ VENDOR = "Icom"
+ MODEL = "IC-2730A"
+
+ _model = "\x35\x98\x00\x01"
+ _memsize = 21312 # 0x5340
+ _endframe = "Icom Inc\x2e4E"
+
+ _ranges = [(0x0000, 0x5300, 64),
+ (0x5300, 0x5310, 16),
+ (0x5310, 0x5340, 48),
+ ]
+
+ _num_banks = 10
+ _bank_class = IC2730Bank
+ _can_hispeed = True
+
+ def _get_bank(self, loc):
+ _bank = self._memobj.bank_info[loc]
+ if _bank.bank == 0x1F:
+ return None
+ else:
+ return _bank.bank
+
+ def _set_bank(self, loc, bank):
+ _bank = self._memobj.bank_info[loc]
+ if bank is None:
+ _bank.bank = 0x1F
+ else:
+ _bank.bank = bank
+
+ def _get_bank_index(self, loc):
+ _bank = self._memobj.bank_info[loc]
+ return _bank.index
+
+ def _set_bank_index(self, loc, index):
+ _bank = self._memobj.bank_info[loc]
+ _bank.index = index
+
+ def get_features(self):
+ rf = chirp_common.RadioFeatures()
+ rf.has_settings = True
+ rf.has_bank_index = True
+ rf.has_bank_names = True
+ rf.requires_call_lists = False
+ rf.memory_bounds = (0, 999)
+ 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 = [(118000000, 174000000),
+ (375000000, 550000000),
+ ]
+ rf.valid_skips = ["", "S", "P"]
+ rf.valid_characters = chirp_common.CHARSET_ASCII
+ rf.valid_name_length = 6
+ rf.valid_special_chans = sorted(_get_special().keys())
+
+ return rf
+
+ def process_mmap(self):
+ self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
+
+ def get_memory(self, number):
+ bitpos = (1 << (number % 8))
+ bytepos = number / 8
+
+ _mem = self._memobj.memory[number]
+ _used = self._memobj.used_flags[bytepos]
+
+ is_used = ((_used & bitpos) == 0)
+
+ mem = chirp_common.Memory()
+
+ mem.number = number
+
+ _skip = self._memobj.skip_flags[bytepos]
+ _pskip = self._memobj.pskip_flags[bytepos]
+ if _skip & bitpos:
+ mem.skip = "S"
+ elif _pskip & bitpos:
+ mem.skip = "P"
+
+ if not is_used:
+ mem.empty = True
+ return mem
+
+ # Frequencies are stored as kHz/5
+ mem.freq = int(_mem.freq) * 5000
+ mem.offset = int(_mem.offset) * 5000
+ mem.rtone = chirp_common.TONES[_mem.rtone]
+ mem.ctone = chirp_common.TONES[_mem.ctone]
+ mem.tmode = TMODES[_mem.tmode]
+ mem.duplex = DUPLEX[_mem.duplex]
+ mem.mode = MODES[_mem.mode]
+ mem.dtcs = chirp_common.DTCS_CODES[_mem.dtcs]
+ mem.dtcs_polarity = DTCSP[_mem.dtcs_polarity]
+ if _mem.tune_step > 8:
+ mem.tuning_step = 5.0 # Sometimes TS is garbage?
+ else:
+ mem.tuning_step = chirp_common.TUNING_STEPS[_mem.tune_step]
+ mem.name = str(_mem.name).rstrip()
+
+ return mem
+
+ def set_memory(self, mem):
+ bitpos = (1 << (mem.number % 8))
+ bytepos = mem.number / 8
+
+ _mem = self._memobj.memory[mem.number]
+ _used = self._memobj.used_flags[bytepos]
+
+ was_empty = _used & bitpos
+
+ skip = self._memobj.skip_flags[bytepos]
+ pskip = self._memobj.pskip_flags[bytepos]
+ if mem.skip == "S":
+ skip |= bitpos
+ else:
+ skip &= ~bitpos
+ if mem.skip == "P":
+ pskip |= bitpos
+ else:
+ pskip &= ~bitpos
+
+ if mem.empty:
+ _used |= bitpos
+ _wipe_memory(_mem, "\xFF")
+ self._set_bank(mem.number, None)
+ return
+
+ _used &= ~bitpos
+ if was_empty:
+ _wipe_memory(_mem, "\x00")
+
+ _mem.freq = mem.freq / 5000
+ _mem.offset = mem.offset / 5000
+ _mem.rtone = chirp_common.TONES.index(mem.rtone)
+ _mem.ctone = chirp_common.TONES.index(mem.ctone)
+ _mem.tmode = TMODES.index(mem.tmode)
+ _mem.duplex = DUPLEX.index(mem.duplex)
+ _mem.mode = MODES.index(mem.mode)
+ _mem.dtcs = chirp_common.DTCS_CODES.index(mem.dtcs)
+ _mem.dtcs_polarity = DTCSP.index(mem.dtcs_polarity)
+ _mem.tune_step = chirp_common.TUNING_STEPS.index(mem.tuning_step)
+ _mem.name = mem.name.ljust(6)
+
+ def get_raw_memory(self, number):
+ return repr(self._memobj.memory[number])
More information about the chirp_devel
mailing list