# HG changeset patch
# User Kosta A. <ve7kcy@gmail.com>
# Date 1619800737 25200
# Fri Apr 30 09:38:57 2021 -0700
# Node ID 941a95de942d7c263a6197bf115cc75bc3624de9
# Parent cd3e2444040876b4a19b41c6cfecedb79ff4a8fe
[icomciv] Restructuring of IcomCIVRadio radio classes; breakout each radio into its own module in preparetion for simplifying support for upcomming CIV feature #4547.
diff --git a/chirp/drivers/ic7000.py b/chirp/drivers/ic7000.py
new file mode 100644
--- /dev/null
+++ b/chirp/drivers/ic7000.py
@@ -0,0 +1,84 @@
+# Copyright 2008 Dan Smith <dsmith@danplanet.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/>.
+
+import struct
+import logging
+
+from chirp import chirp_common, errors, directory
+from chirp.drivers import icf, icomciv
+
+LOG = logging.getLogger(__name__)
+
+# http://www.vk4adc.com/
+# web/index.php/reference-information/49-general-ref-info/182-civ7400
+MEM_IC7000_FORMAT = """
+u8 bank;
+bbcd number[2];
+u8 spl:4,
+ skip:4;
+lbcd freq[5];
+u8 mode;
+u8 filter;
+u8 duplex:4,
+ tmode:4;
+bbcd rtone[3];
+bbcd ctone[3];
+u8 dtcs_polarity;
+bbcd dtcs[2];
+lbcd freq_tx[5];
+u8 mode_tx;
+u8 filter_tx;
+u8 duplex_tx:4,
+ tmode_tx:4;
+bbcd rtone_tx[3];
+bbcd ctone_tx[3];
+u8 dtcs_polarity_tx;
+bbcd dtcs_tx[2];
+char name[9];
+"""
+
+class IC7000MemFrame(icomciv.BankMemFrame):
+ FORMAT = MEM_IC7000_FORMAT
+
+@directory.register
+class Icom7000Radio(icomciv.IcomCIVRadio):
+ """Icom IC-7000"""
+ MODEL = "IC-7000"
+ _model = "\x70"
+ _template = 102
+
+ _num_banks = 5 # Banks A-E
+ _bank_index_bounds = (1, 99)
+ _bank_class = icf.IcomBank
+
+ def _initialize(self):
+ self._classes["mem"] = IC7000MemFrame
+ self._rf.has_bank = True
+ self._rf.has_dtcs_polarity = True
+ self._rf.has_dtcs = True
+ self._rf.has_ctone = True
+ self._rf.has_offset = True
+ self._rf.has_name = True
+ self._rf.has_tuning_step = False
+ self._rf.valid_modes = ["LSB", "USB", "AM", "CW", "RTTY", "FM", "WFM"]
+ self._rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS"]
+ self._rf.valid_duplexes = ["", "-", "+", "split"]
+ self._rf.valid_bands = [(30000, 199999999), (400000000, 470000000)]
+ self._rf.valid_tuning_steps = []
+ self._rf.valid_skips = ["S", ""]
+ self._rf.valid_name_length = 9
+ self._rf.valid_characters = chirp_common.CHARSET_ASCII
+ self._rf.memory_bounds = (0, 99 * self._num_banks - 1)
+ self._rf.can_odd_split = True
diff --git a/chirp/drivers/ic7100.py b/chirp/drivers/ic7100.py
new file mode 100644
--- /dev/null
+++ b/chirp/drivers/ic7100.py
@@ -0,0 +1,88 @@
+# Copyright 2008 Dan Smith <dsmith@danplanet.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/>.
+
+import struct
+import logging
+
+from chirp import chirp_common, errors, directory
+from chirp.drivers import icf, icomciv
+
+LOG = logging.getLogger(__name__)
+
+
+MEM_IC7100_FORMAT = """
+u8 bank; // 1 bank number
+bbcd number[2]; // 2,3
+u8 splitSelect; // 4 split and select memory settings
+lbcd freq[5]; // 5-9 operating freq
+u8 mode; // 10 operating mode
+u8 filter; // 11 filter
+u8 dataMode; // 12 data mode setting (on or off)
+u8 duplex:4, // 13 duplex on/-/+
+ tmode:4; // 13 tone
+u8 dsql:4, // 14 digital squelch
+ unknown1:4; // 14 zero
+bbcd rtone[3]; // 15-17 repeater tone freq
+bbcd ctone[3]; // 18-20 tone squelch setting
+u8 dtcsPolarity; // 21 DTCS polarity
+u8 unknown2:4, // 22 zero
+ firstDtcs:4; // 22 first digit of DTCS code
+u8 secondDtcs:4, // 23 second digit DTCS
+ thirdDtcs:4; // 23 third digit DTCS
+u8 digitalSquelch; // 24 Digital code squelch setting
+lbcd duplexOffset[3]; // 25-27 duplex offset freq
+char destCall[8]; // 28-35 destination call sign
+char accessRepeaterCall[8];// 36-43 access repeater call sign
+char linkRepeaterCall[8]; // 44-51 gateway/link repeater call sign
+bbcd duplexSettings[47]; // repeat of 5-51 for duplex
+char name[16]; // 52-60 Name of station
+"""
+
+class IC7100MemFrame(icomciv.BankMemFrame):
+ FORMAT = MEM_IC7100_FORMAT
+
+@directory.register
+class Icom7100Radio(icomciv.IcomCIVRadio):
+ """Icom IC-7100"""
+ MODEL = "IC-7100"
+ _model = "\x88"
+ _template = 102
+
+ _num_banks = 5
+ _bank_index_bounds = (1, 99)
+ _bank_class = icf.IcomBank
+
+ def _initialize(self):
+ self._classes["mem"] = IC7100MemFrame
+ self._rf.has_bank = True
+ self._rf.has_bank_index = False
+ self._rf.has_bank_names = False
+ self._rf.has_dtcs_polarity = False
+ self._rf.has_dtcs = False
+ self._rf.has_ctone = True
+ self._rf.has_offset = False
+ self._rf.has_name = True
+ self._rf.has_tuning_step = False
+ self._rf.valid_modes = [
+ "LSB", "USB", "AM", "CW", "RTTY", "FM", "WFM", "CWR", "RTTYR", "DV"
+ ]
+ self._rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS"]
+ self._rf.valid_duplexes = ["", "-", "+"]
+ self._rf.valid_bands = [(30000, 199999999), (400000000, 470000000)]
+ self._rf.valid_tuning_steps = []
+ self._rf.valid_skips = []
+ self._rf.valid_name_length = 16
+ self._rf.valid_characters = chirp_common.CHARSET_ASCII
+ self._rf.memory_bounds = (0, 99 * self._num_banks - 1)
diff --git a/chirp/drivers/ic7200.py b/chirp/drivers/ic7200.py
new file mode 100644
--- /dev/null
+++ b/chirp/drivers/ic7200.py
@@ -0,0 +1,48 @@
+# Copyright 2008 Dan Smith <dsmith@danplanet.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/>.
+
+import struct
+import logging
+
+from chirp import chirp_common, errors, directory
+from chirp.drivers import icf, icomciv
+
+LOG = logging.getLogger(__name__)
+
+
+@directory.register
+class Icom7200Radio(icomciv.IcomCIVRadio):
+ """Icom IC-7200"""
+ MODEL = "7200"
+ _model = "\x76"
+ _template = 201
+
+ _num_banks = 1 # Banks not supported
+
+ def _initialize(self):
+ self._rf.has_bank = False
+ self._rf.has_dtcs_polarity = False
+ self._rf.has_dtcs = False
+ self._rf.has_ctone = False
+ self._rf.has_offset = False
+ self._rf.has_name = False
+ self._rf.has_tuning_step = False
+ self._rf.valid_modes = ["LSB", "USB", "AM", "CW", "RTTY",
+ "CWR", "RTTYR"]
+ self._rf.valid_tmodes = []
+ self._rf.valid_duplexes = []
+ self._rf.valid_bands = [(30000, 60000000)]
+ self._rf.valid_skips = []
+ self._rf.memory_bounds = (1, 201)
diff --git a/chirp/drivers/ic7300.py b/chirp/drivers/ic7300.py
new file mode 100644
--- /dev/null
+++ b/chirp/drivers/ic7300.py
@@ -0,0 +1,103 @@
+# Copyright 2008 Dan Smith <dsmith@danplanet.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/>.
+
+import struct
+import logging
+
+from chirp import chirp_common, errors, directory
+from chirp.drivers import icf, icomciv
+
+LOG = logging.getLogger(__name__)
+
+
+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
+"""
+
+class IC7300MemFrame(icomciv.MemFrame):
+ FORMAT = MEM_IC7300_FORMAT
+
+@directory.register
+class Icom7300Radio(icomciv.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 = 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())
diff --git a/chirp/drivers/ic746.py b/chirp/drivers/ic746.py
new file mode 100644
--- /dev/null
+++ b/chirp/drivers/ic746.py
@@ -0,0 +1,76 @@
+# Copyright 2008 Dan Smith <dsmith@danplanet.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/>.
+
+import struct
+import logging
+
+from chirp import chirp_common, errors, directory
+from chirp.drivers import icf, icomciv
+
+LOG = logging.getLogger(__name__)
+
+
+MEM_IC746_FORMAT = """
+bbcd number[2];
+u8 unknown1;
+lbcd freq[5];
+u8 unknown2:5,
+ mode:3;
+u8 unknown1;
+u8 unknown2:2,
+ duplex:2,
+ unknown3:1,
+ tmode:3;
+u8 unknown4;
+bbcd rtone[2];
+u8 unknown5;
+bbcd ctone[2];
+u8 dtcs_polarity;
+bbcd dtcs[2];
+u8 unknown[11];
+char name[9];
+"""
+
+class IC746MemFrame(icomciv.MemFrame):
+ FORMAT = MEM_IC746_FORMAT
+
+@directory.register
+class Icom746Radio(icomciv.IcomCIVRadio):
+ """Icom IC-746"""
+ MODEL = "746"
+ BAUD_RATE = 9600
+ _model = "\x56"
+ _template = 102
+
+ _num_banks = 1 # Banks not supported
+
+ def _initialize(self):
+ self._classes["mem"] = IC746MemFrame
+ self._rf.has_bank = False
+ self._rf.has_dtcs_polarity = False
+ self._rf.has_dtcs = False
+ self._rf.has_ctone = True
+ self._rf.has_offset = False
+ self._rf.has_name = True
+ self._rf.has_tuning_step = False
+ self._rf.valid_modes = ["LSB", "USB", "AM", "CW", "RTTY", "FM"]
+ self._rf.valid_tmodes = ["", "Tone", "TSQL"]
+ self._rf.valid_duplexes = ["", "-", "+"]
+ self._rf.valid_bands = [(30000, 199999999)]
+ self._rf.valid_tuning_steps = []
+ self._rf.valid_skips = []
+ self._rf.valid_name_length = 9
+ self._rf.valid_characters = chirp_common.CHARSET_ASCII
+ self._rf.memory_bounds = (1, 99)
diff --git a/chirp/drivers/ic910.py b/chirp/drivers/ic910.py
new file mode 100644
--- /dev/null
+++ b/chirp/drivers/ic910.py
@@ -0,0 +1,142 @@
+# Copyright 2008 Dan Smith <dsmith@danplanet.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/>.
+
+import struct
+import logging
+
+from chirp import chirp_common, errors, directory
+from chirp.drivers import icf, icomciv
+
+LOG = logging.getLogger(__name__)
+
+
+MEM_IC910_FORMAT = """
+u8 bank; // 1 bank number
+bbcd number[2]; // 2,3
+lbcd freq[5]; // 4-8 operating freq
+u8 mode; // 9 operating mode
+u8 filter; // 10 filter
+u8 tmode:4, // 11 tone
+ duplex:4; // 11 duplex off/-/+
+bbcd rtone[3]; // 12-14 repeater tone freq
+bbcd ctone[3]; // 15-17 tone squelch setting
+lbcd duplexOffset[3]; // 18-20 duplex offset freq
+"""
+
+class IC910MemFrame(icomciv.BankMemFrame):
+ FORMAT = MEM_IC910_FORMAT
+
+@directory.register
+class Icom910Radio(icomciv.IcomCIVRadio):
+ """Icom IC-910"""
+ MODEL = "IC-910"
+ BAUD_RATE = 19200
+ _model = "\x60"
+ _template = 100
+
+ _num_banks = 3 # Banks for 2m, 70cm, 23cm
+ _bank_index_bounds = (1, 99)
+ _bank_class = icf.IcomBank
+
+ _SPECIAL_CHANNELS = {
+ "1A": 100,
+ "1b": 101,
+ "2A": 102,
+ "2b": 103,
+ "3A": 104,
+ "3b": 105,
+ "C": 106,
+ }
+ _SPECIAL_CHANNELS_REV = {v: k for k, v in _SPECIAL_CHANNELS.items()}
+
+ _SPECIAL_BANKS = {
+ "2m": 1,
+ "70cm": 2,
+ "23cm": 3,
+ }
+ _SPECIAL_BANKS_REV = {v: k for k, v in _SPECIAL_BANKS.items()}
+
+ def _get_special_names(self, band):
+ return sorted([band + "-" + key
+ for key in self._SPECIAL_CHANNELS.keys()])
+
+ def _is_special(self, number):
+ return number >= 1000 or isinstance(number, str)
+
+ def _get_special_info(self, number):
+ info = BankSpecialChannel()
+ if isinstance(number, str):
+ info.name = number
+ (band_name, chan_name) = number.split("-")
+ info.bank = self._SPECIAL_BANKS[band_name]
+ info.channel = self._SPECIAL_CHANNELS[chan_name]
+ info.location = info.bank * 1000 + info.channel
+ else:
+ info.location = number
+ (info.bank, info.channel) = divmod(number, 1000)
+ band_name = self._SPECIAL_BANKS_REV[info.bank]
+ chan_name = self._SPECIAL_CHANNELS_REV[info.channel]
+ info.name = band_name + "-" + chan_name
+ return info
+
+ # The IC-910 has a bank of memories for each band. The 23cm band is only
+ # available when the optional UX-910 unit is installed, but there is no
+ # direct means of detecting its presence. Instead, attempt to access the
+ # first memory in the 23cm bank. If that's successful, the unit is there,
+ # and we can present all 3 banks to the user. Otherwise, the unit is not
+ # installed, so we present 2 banks to the user, for 2m and 70cm.
+ def _detect_23cm_unit(self):
+ if not self.pipe:
+ return True
+ f = IC910MemFrame()
+ f.set_location(1, 3) # First memory in 23cm bank
+ self._send_frame(f)
+ f.read(self.pipe)
+ if f._cmd == 0xFA: # Error code lands in command field
+ self._num_banks = 2
+ LOG.debug("UX-910 unit is %sinstalled" %
+ ("not " if self._num_banks == 2 else ""))
+ return self._num_banks == 3
+
+ def _initialize(self):
+ self._classes["mem"] = IC910MemFrame
+ self._has_23cm_unit = self._detect_23cm_unit()
+ self._rf.has_bank = True
+ self._rf.has_dtcs_polarity = False
+ self._rf.has_dtcs = False
+ self._rf.has_ctone = True
+ self._rf.has_offset = True
+ self._rf.has_name = False
+ self._rf.has_tuning_step = False
+ self._rf.valid_modes = ["LSB", "USB", "CW", "NCW", "FM", "NFM"]
+ self._rf.valid_tmodes = ["", "Tone", "TSQL"]
+ self._rf.valid_duplexes = ["", "-", "+"]
+ self._rf.valid_bands = [(136000000, 174000000),
+ (420000000, 480000000)]
+ self._rf.valid_tuning_steps = []
+ self._rf.valid_skips = []
+ self._rf.valid_special_chans = (self._get_special_names("2m") +
+ self._get_special_names("70cm"))
+ self._rf.memory_bounds = (1, 99 * self._num_banks)
+
+ if self._has_23cm_unit:
+ self._rf.valid_bands.append((1240000000, 1320000000))
+ self._rf.valid_special_chans += self._get_special_names("23cm")
+
+ # Combine mode and filter into unified mode
+ self._unified_modes = True
+
+ # Use Chirp locations starting with 1
+ self._adjust_bank_loc_start = True
diff --git a/chirp/drivers/icomciv.py b/chirp/drivers/icomciv.py
--- a/chirp/drivers/icomciv.py
+++ b/chirp/drivers/icomciv.py
@@ -1,6 +1,21 @@
-# Latest update: March, 2021 RJ DeWitt added IC-7300
+# Copyright 2008 Dan Smith <dsmith@danplanet.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/>.
+
import struct
import logging
+
from chirp.drivers import icf
from chirp import chirp_common, util, errors, bitwise, directory
from chirp.memmap import MemoryMap
@@ -23,122 +38,6 @@
unknown_2:4;
"""
-
-# http://www.vk4adc.com/
-# web/index.php/reference-information/49-general-ref-info/182-civ7400
-MEM_IC7000_FORMAT = """
-u8 bank;
-bbcd number[2];
-u8 spl:4,
- skip:4;
-lbcd freq[5];
-u8 mode;
-u8 filter;
-u8 duplex:4,
- tmode:4;
-bbcd rtone[3];
-bbcd ctone[3];
-u8 dtcs_polarity;
-bbcd dtcs[2];
-lbcd freq_tx[5];
-u8 mode_tx;
-u8 filter_tx;
-u8 duplex_tx:4,
- tmode_tx:4;
-bbcd rtone_tx[3];
-bbcd ctone_tx[3];
-u8 dtcs_polarity_tx;
-bbcd dtcs_tx[2];
-char name[9];
-"""
-
-MEM_IC7100_FORMAT = """
-u8 bank; // 1 bank number
-bbcd number[2]; // 2,3
-u8 splitSelect; // 4 split and select memory settings
-lbcd freq[5]; // 5-9 operating freq
-u8 mode; // 10 operating mode
-u8 filter; // 11 filter
-u8 dataMode; // 12 data mode setting (on or off)
-u8 duplex:4, // 13 duplex on/-/+
- tmode:4; // 13 tone
-u8 dsql:4, // 14 digital squelch
- unknown1:4; // 14 zero
-bbcd rtone[3]; // 15-17 repeater tone freq
-bbcd ctone[3]; // 18-20 tone squelch setting
-u8 dtcsPolarity; // 21 DTCS polarity
-u8 unknown2:4, // 22 zero
- firstDtcs:4; // 22 first digit of DTCS code
-u8 secondDtcs:4, // 23 second digit DTCS
- thirdDtcs:4; // 23 third digit DTCS
-u8 digitalSquelch; // 24 Digital code squelch setting
-lbcd duplexOffset[3]; // 25-27 duplex offset freq
-char destCall[8]; // 28-35 destination call sign
-char accessRepeaterCall[8];// 36-43 access repeater call sign
-char linkRepeaterCall[8]; // 44-51 gateway/link repeater call sign
-bbcd duplexSettings[47]; // repeat of 5-51 for duplex
-char name[16]; // 52-60 Name of station
-"""
-
-MEM_IC910_FORMAT = """
-u8 bank; // 1 bank number
-bbcd number[2]; // 2,3
-lbcd freq[5]; // 4-8 operating freq
-u8 mode; // 9 operating mode
-u8 filter; // 10 filter
-u8 tmode:4, // 11 tone
- duplex:4; // 11 duplex off/-/+
-bbcd rtone[3]; // 12-14 repeater tone freq
-bbcd ctone[3]; // 15-17 tone squelch setting
-lbcd duplexOffset[3]; // 18-20 duplex offset freq
-"""
-
-mem_duptone_format = """
-bbcd number[2];
-u8 unknown1;
-lbcd freq[5];
-u8 unknown2:5,
- mode:3;
-u8 unknown1;
-u8 unknown2:2,
- duplex:2,
- unknown3:1,
- tmode:3;
-u8 unknown4;
-bbcd rtone[2];
-u8 unknown5;
-bbcd ctone[2];
-u8 dtcs_polarity;
-bbcd dtcs[2];
-u8 unknown[11];
-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"]
@@ -207,6 +106,7 @@
class MemFrame(Frame):
"""A memory frame"""
+ FORMAT = MEM_FORMAT
_cmd = 0x1A
_sub = 0x00
_loc = 0
@@ -227,7 +127,7 @@
def get_obj(self):
"""Return a bitwise parsed object"""
self._data = MemoryMap(str(self._data)) # Make sure we're assignable
- return bitwise.parse(MEM_FORMAT, self._data)
+ return bitwise.parse(self.FORMAT, self._data)
def initialize(self):
"""Initialize to sane values"""
@@ -236,7 +136,7 @@
class BankMemFrame(MemFrame):
"""A memory frame for radios with multiple banks"""
- FORMAT = MEM_IC7000_FORMAT
+ FORMAT = None
_bnk = 0
def set_location(self, loc, bank=1):
@@ -256,28 +156,6 @@
return bitwise.parse(self.FORMAT, self._data)
-class IC7100MemFrame(BankMemFrame):
- FORMAT = MEM_IC7100_FORMAT
-
-
-class IC910MemFrame(BankMemFrame):
- FORMAT = MEM_IC910_FORMAT
-
-
-class DupToneMemFrame(MemFrame):
- def get_obj(self):
- self._data = MemoryMap(str(self._data))
- 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"""
@@ -442,10 +320,10 @@
else:
return repr(f.get_obj())
-# We have a simple mapping between the memory location in the frequency
-# editor and (bank, channel) of the radio. The mapping doesn't
-# change so we use a little math to calculate what bank a location
-# is in. We can't change the bank a location is in so we just pass.
+ # We have a simple mapping between the memory location in the frequency
+ # editor and (bank, channel) of the radio. The mapping doesn't
+ # change so we use a little math to calculate what bank a location
+ # is in. We can't change the bank a location is in so we just pass.
def _get_bank(self, loc):
if self._adjust_bank_loc_start:
loc -= 1
@@ -562,6 +440,8 @@
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"):
@@ -620,10 +500,10 @@
f.make_empty()
self._send_frame(f)
-# The next two lines accept the radio's status after setting the memory
-# and reports the results to the debug log. This is needed for the
-# IC-7000. No testing was done to see if it breaks memory delete on the
-# IC-746 or IC-7200.
+ # The next two lines accept the radio's status after setting the memory
+ # and reports the results to the debug log. This is needed for the
+ # IC-7000. No testing was done to see if it breaks memory delete on the
+ # IC-746 or IC-7200.
f = self._recv_frame()
LOG.debug("Result:\n%s" % util.hexprint(f.get_data()))
return
@@ -708,311 +588,28 @@
LOG.debug("Result:\n%s" % util.hexprint(f.get_data()))
-@directory.register
-class Icom7200Radio(IcomCIVRadio):
- """Icom IC-7200"""
- MODEL = "7200"
- _model = "\x76"
- _template = 201
-
- _num_banks = 1 # Banks not supported
-
- def _initialize(self):
- self._rf.has_bank = False
- self._rf.has_dtcs_polarity = False
- self._rf.has_dtcs = False
- self._rf.has_ctone = False
- self._rf.has_offset = False
- self._rf.has_name = False
- self._rf.has_tuning_step = False
- self._rf.valid_modes = ["LSB", "USB", "AM", "CW", "RTTY",
- "CWR", "RTTYR"]
- self._rf.valid_tmodes = []
- self._rf.valid_duplexes = []
- self._rf.valid_bands = [(30000, 60000000)]
- self._rf.valid_skips = []
- self._rf.memory_bounds = (1, 201)
-
-
-@directory.register
-class Icom7000Radio(IcomCIVRadio):
- """Icom IC-7000"""
- MODEL = "IC-7000"
- _model = "\x70"
- _template = 102
-
- _num_banks = 5 # Banks A-E
- _bank_index_bounds = (1, 99)
- _bank_class = icf.IcomBank
-
- def _initialize(self):
- self._classes["mem"] = BankMemFrame
- self._rf.has_bank = True
- self._rf.has_dtcs_polarity = True
- self._rf.has_dtcs = True
- self._rf.has_ctone = True
- self._rf.has_offset = True
- self._rf.has_name = True
- self._rf.has_tuning_step = False
- self._rf.valid_modes = ["LSB", "USB", "AM", "CW", "RTTY", "FM", "WFM"]
- self._rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS"]
- self._rf.valid_duplexes = ["", "-", "+", "split"]
- self._rf.valid_bands = [(30000, 199999999), (400000000, 470000000)]
- self._rf.valid_tuning_steps = []
- self._rf.valid_skips = ["S", ""]
- self._rf.valid_name_length = 9
- self._rf.valid_characters = chirp_common.CHARSET_ASCII
- self._rf.memory_bounds = (0, 99 * self._num_banks - 1)
- self._rf.can_odd_split = True
-
-
-@directory.register
-class Icom7100Radio(IcomCIVRadio):
- """Icom IC-7100"""
- MODEL = "IC-7100"
- _model = "\x88"
- _template = 102
-
- _num_banks = 5
- _bank_index_bounds = (1, 99)
- _bank_class = icf.IcomBank
-
- def _initialize(self):
- self._classes["mem"] = IC7100MemFrame
- self._rf.has_bank = True
- self._rf.has_bank_index = False
- self._rf.has_bank_names = False
- self._rf.has_dtcs_polarity = False
- self._rf.has_dtcs = False
- self._rf.has_ctone = True
- self._rf.has_offset = False
- self._rf.has_name = True
- self._rf.has_tuning_step = False
- self._rf.valid_modes = [
- "LSB", "USB", "AM", "CW", "RTTY", "FM", "WFM", "CWR", "RTTYR", "DV"
- ]
- self._rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS"]
- self._rf.valid_duplexes = ["", "-", "+"]
- self._rf.valid_bands = [(30000, 199999999), (400000000, 470000000)]
- self._rf.valid_tuning_steps = []
- self._rf.valid_skips = []
- self._rf.valid_name_length = 16
- self._rf.valid_characters = chirp_common.CHARSET_ASCII
- self._rf.memory_bounds = (0, 99 * self._num_banks - 1)
-
-
-@directory.register
-class Icom746Radio(IcomCIVRadio):
- """Icom IC-746"""
- MODEL = "746"
- BAUD_RATE = 9600
- _model = "\x56"
- _template = 102
-
- _num_banks = 1 # Banks not supported
-
- def _initialize(self):
- self._classes["mem"] = DupToneMemFrame
- self._rf.has_bank = False
- self._rf.has_dtcs_polarity = False
- self._rf.has_dtcs = False
- self._rf.has_ctone = True
- self._rf.has_offset = False
- self._rf.has_name = True
- self._rf.has_tuning_step = False
- self._rf.valid_modes = ["LSB", "USB", "AM", "CW", "RTTY", "FM"]
- self._rf.valid_tmodes = ["", "Tone", "TSQL"]
- self._rf.valid_duplexes = ["", "-", "+"]
- self._rf.valid_bands = [(30000, 199999999)]
- self._rf.valid_tuning_steps = []
- self._rf.valid_skips = []
- self._rf.valid_name_length = 9
- self._rf.valid_characters = chirp_common.CHARSET_ASCII
- self._rf.memory_bounds = (1, 99)
-
-
-@directory.register
-class Icom910Radio(IcomCIVRadio):
- """Icom IC-910"""
- MODEL = "IC-910"
- BAUD_RATE = 19200
- _model = "\x60"
- _template = 100
-
- _num_banks = 3 # Banks for 2m, 70cm, 23cm
- _bank_index_bounds = (1, 99)
- _bank_class = icf.IcomBank
-
- _SPECIAL_CHANNELS = {
- "1A": 100,
- "1b": 101,
- "2A": 102,
- "2b": 103,
- "3A": 104,
- "3b": 105,
- "C": 106,
- }
- _SPECIAL_CHANNELS_REV = {v: k for k, v in _SPECIAL_CHANNELS.items()}
-
- _SPECIAL_BANKS = {
- "2m": 1,
- "70cm": 2,
- "23cm": 3,
- }
- _SPECIAL_BANKS_REV = {v: k for k, v in _SPECIAL_BANKS.items()}
-
- def _get_special_names(self, band):
- return sorted([band + "-" + key
- for key in self._SPECIAL_CHANNELS.keys()])
-
- def _is_special(self, number):
- return number >= 1000 or isinstance(number, str)
-
- def _get_special_info(self, number):
- info = BankSpecialChannel()
- if isinstance(number, str):
- info.name = number
- (band_name, chan_name) = number.split("-")
- info.bank = self._SPECIAL_BANKS[band_name]
- info.channel = self._SPECIAL_CHANNELS[chan_name]
- info.location = info.bank * 1000 + info.channel
- else:
- info.location = number
- (info.bank, info.channel) = divmod(number, 1000)
- band_name = self._SPECIAL_BANKS_REV[info.bank]
- chan_name = self._SPECIAL_CHANNELS_REV[info.channel]
- info.name = band_name + "-" + chan_name
- return info
-
- # The IC-910 has a bank of memories for each band. The 23cm band is only
- # available when the optional UX-910 unit is installed, but there is no
- # direct means of detecting its presence. Instead, attempt to access the
- # first memory in the 23cm bank. If that's successful, the unit is there,
- # and we can present all 3 banks to the user. Otherwise, the unit is not
- # installed, so we present 2 banks to the user, for 2m and 70cm.
- def _detect_23cm_unit(self):
- if not self.pipe:
- return True
- f = IC910MemFrame()
- f.set_location(1, 3) # First memory in 23cm bank
- self._send_frame(f)
- f.read(self.pipe)
- if f._cmd == 0xFA: # Error code lands in command field
- self._num_banks = 2
- LOG.debug("UX-910 unit is %sinstalled" %
- ("not " if self._num_banks == 2 else ""))
- return self._num_banks == 3
-
- def _initialize(self):
- self._classes["mem"] = IC910MemFrame
- self._has_23cm_unit = self._detect_23cm_unit()
- self._rf.has_bank = True
- self._rf.has_dtcs_polarity = False
- self._rf.has_dtcs = False
- self._rf.has_ctone = True
- self._rf.has_offset = True
- self._rf.has_name = False
- self._rf.has_tuning_step = False
- self._rf.valid_modes = ["LSB", "USB", "CW", "NCW", "FM", "NFM"]
- self._rf.valid_tmodes = ["", "Tone", "TSQL"]
- self._rf.valid_duplexes = ["", "-", "+"]
- self._rf.valid_bands = [(136000000, 174000000),
- (420000000, 480000000)]
- self._rf.valid_tuning_steps = []
- self._rf.valid_skips = []
- self._rf.valid_special_chans = (self._get_special_names("2m") +
- self._get_special_names("70cm"))
- self._rf.memory_bounds = (1, 99 * self._num_banks)
-
- if self._has_23cm_unit:
- self._rf.valid_bands.append((1240000000, 1320000000))
- self._rf.valid_special_chans += self._get_special_names("23cm")
-
- # Combine mode and filter into unified mode
- self._unified_modes = True
-
- # Use Chirp locations starting with 1
- self._adjust_bank_loc_start = True
-
-
-@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,
- (0x70, 0xE0): Icom7000Radio,
- (0x46, 0xE0): Icom746Radio,
- (0x60, 0xE0): Icom910Radio,
- (0x94, 0xE0): Icom7300Radio,
-}
-
-
def probe_model(ser):
"""Probe the radio attatched to @ser for its model"""
f = Frame()
f.set_command(0x19, 0x00)
- for model, controller in CIV_MODELS.keys():
- f.send(model, controller, ser)
+ models = {}
+ for rclass in directory.DRV_TO_RADIO.values():
+ if issubclass(rclass, IcomCIVRadio):
+ models[rclass.MODEL] = rclass
+
+ for rclass in models.values():
+ model = ord(rclass._model)
+ f.send(model, 0xE0, ser)
try:
f.read(ser)
except errors.RadioError:
continue
if len(f.get_data()) == 1:
- model = ord(f.get_data()[0])
- return CIV_MODELS[(model, controller)]
+ md = ord(f.get_data()[0])
+ if (md == model):
+ return rclass
if f.get_data():
LOG.debug("Got data, but not 1 byte:")
_______________________________________________
chirp_devel mailing list
chirp_devel@intrepid.danplanet.com
http://intrepid.danplanet.com/mailman/listinfo/chirp_devel
Developer docs: http://chirp.danplanet.com/projects/chirp/wiki/Developers