Skip to content

Commit

Permalink
ic9700: Add satellite memories
Browse files Browse the repository at this point in the history
This is sort of an approximation as we don't have a good way to
support pairs of full memories stored together, but it's probably
close enough.

Related to #10018
  • Loading branch information
kk7ds committed Aug 23, 2024
1 parent 61fa50f commit 8c234a9
Showing 1 changed file with 213 additions and 3 deletions.
216 changes: 213 additions & 3 deletions chirp/drivers/icomciv.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,45 @@
char name[16];
"""

MEM_IC9700_SAT_FORMAT = """
bbcd number[2];
lbcd freq[5];
bbcd mode;
u8 filter;
bbcd data_mode;
u8 unused1:4,
tmode:4;
u8 unused2:4,
dig_sql:4;
bbcd rtone[3];
bbcd ctone[3];
u8 dtcs_polarity;
bbcd dtcs[2];
u8 dig_code;
char urcall[8];
char rpt1call[8];
char rpt2call[8];
struct {
lbcd freq[5];
bbcd mode;
u8 filter;
bbcd data_mode;
u8 unused1:4,
tmode:4;
u8 unused2:4,
dig_sql:4;
bbcd rtone[3];
bbcd ctone[3];
u8 dtcs_polarity;
bbcd dtcs[2];
u8 dig_code;
char urcall[8];
char rpt1call[8];
char rpt2call[8];
} tx;
char name[16];
"""

MEM_IC7400_FORMAT = """
bbcd number[2];
u8 unknown1;
Expand Down Expand Up @@ -325,8 +364,7 @@ def get_obj(self):

def initialize(self):
"""Initialize to sane values"""
self._data = MemoryMapBytes(
bytes(b'\x00' * (self.get_obj().size() / 8)))
self._data = bytes(b'\x00' * (self.get_obj().size() // 8))


class BankMemFrame(MemFrame):
Expand Down Expand Up @@ -384,6 +422,11 @@ class IC9700MemFrame(BankMemFrame):
FORMAT = MEM_IC9700_FORMAT


class IC9700SatMemFrame(MemFrame):
_sub = 0x07
FORMAT = MEM_IC9700_SAT_FORMAT


class SpecialChannel(object):
"""Info for special (named) channels"""

Expand Down Expand Up @@ -1203,7 +1246,8 @@ class Icom9700Radio(IcomCIVRadio):
def get_sub_devices(self):
return [Icom9700RadioBand(self, 1),
Icom9700RadioBand(self, 2),
Icom9700RadioBand(self, 3)]
Icom9700RadioBand(self, 3),
Icom9700SatelliteBand(self)]

def _initialize(self):
super()._initialize()
Expand Down Expand Up @@ -1279,6 +1323,172 @@ def _initialize(self):
self._classes['mem'] = IC9700MemFrame


class Icom9700SatelliteBand(Icom9700Radio):
VARIANT = 'Satellite'

def __init__(self, parent):
self._parent = parent
super().__init__(parent.pipe)

def _detect_echo(self):
self._parent._willecho

def _initialize(self):
super()._initialize()
self._rf.has_name = True
self._rf.valid_tmodes = ['', 'Tone', 'TSQL', 'DTCS']
self._rf.has_dtcs = True
self._rf.has_dtcs_polarity = True
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_bands = [(x * 1000000, y * 1000000) for x, y in
self.BANDS.values()]
self._rf.valid_name_length = 16
self._rf.valid_characters = (chirp_common.CHARSET_ALPHANUMERIC +
'!#$%&\\?"\'`^+-*/.,:=<>()[]{}|_~@')
# Last item is RPS for DD mode
self._rf.valid_duplexes = ['split']
self._rf.valid_modes = [x for x in self._MODES if x]
self._rf.valid_modes.remove('DD')
self._classes['mem'] = IC9700SatMemFrame

def _get_template_memory(self):
f = self._classes["mem"]()
f.initialize()
return f

def get_memory(self, number):
self._detect_baudrate()
LOG.debug("Getting %s" % number)
f = self._classes["mem"]()
mem = chirp_common.Memory()
f.set_location(number)
mem.number = number
self._send_frame(f)

f = self._recv_frame(f)
if len(f.get_data()) == 0:
raise errors.RadioError("Radio reported error")
if f.get_data() and f.get_data()[-1] == 0xFF:
mem.empty = True
mem.duplex = 'split'
LOG.debug("Found %i empty" % mem.number)
return mem

memobj = f.get_obj()
LOG.debug(repr(memobj))

mem.freq = int(memobj.freq)
mem.mode = self._MODES[int(memobj.mode)]
mem.name = str(memobj.name).rstrip()
mem.tmode = self._rf.valid_tmodes[memobj.tmode]

if memobj.dtcs_polarity == 0x11:
mem.dtcs_polarity = "RR"
elif memobj.dtcs_polarity == 0x10:
mem.dtcs_polarity = "RN"
elif memobj.dtcs_polarity == 0x01:
mem.dtcs_polarity = "NR"
else:
mem.dtcs_polarity = "NN"

mem.dtcs = bitwise.bcd_to_int(memobj.dtcs)
mem.rtone = int(memobj.rtone) / 10.0
mem.ctone = int(memobj.ctone) / 10.0
mem.duplex = 'split'
mem.offset = int(memobj.tx.freq)
mem.immutable = ["duplex"]

try:
dig = RadioSetting("dig", "Digital",
RadioSettingValueBoolean(bool(memobj.dig)))
except AttributeError:
pass
else:
dig.set_doc("Enable digital mode")
if not mem.extra:
mem.extra = RadioSettingGroup("extra", "Extra")
mem.extra.append(dig)

options = ["Wide", "Mid", "Narrow"]
fil = RadioSetting(
"filter", "Filter",
RadioSettingValueList(options,
options[memobj.filter - 1]))
fil.set_doc("Filter settings")
if not mem.extra:
mem.extra = RadioSettingGroup("extra", "Extra")
mem.extra.append(fil)

return mem

def set_memory(self, mem):
self._detect_baudrate()
LOG.debug("Setting %s(%s)" % (mem.number, mem.extd_number))
f = self._get_template_memory()
ch = mem.number
if mem.empty:
LOG.debug("Making %i empty" % mem.number)
f.set_location(ch)
f.make_empty()
self._send_frame(f)
f = self._recv_frame()
LOG.debug("Result (%r):\n%s",
f._cmd, util.hexprint(bytes(f.get_data())))
return

memobj = f.get_obj()
memobj.number = ch
memobj.freq = int(mem.freq)
mode = mem.mode
memobj.mode = self._MODES.index(mode)
name_length = len(memobj.name.get_value())
memobj.name = mem.name.ljust(name_length)[:name_length]
memobj.tmode = self._rf.valid_tmodes.index(mem.tmode)
memobj.ctone = int(mem.ctone * 10)
memobj.rtone = int(mem.rtone * 10)

if mem.dtcs_polarity == "RR":
memobj.dtcs_polarity = 0x11
elif mem.dtcs_polarity == "RN":
memobj.dtcs_polarity = 0x10
elif mem.dtcs_polarity == "NR":
memobj.dtcs_polarity = 0x01
else:
memobj.dtcs_polarity = 0x00

bitwise.int_to_bcd(memobj.dtcs, mem.dtcs)

memobj.tx.freq = int(mem.offset)
memobj.tx.tmode = memobj.tmode
memobj.tx.ctone = memobj.ctone
memobj.tx.rtone = memobj.rtone
memobj.tx.dtcs_polarity = memobj.dtcs_polarity
memobj.tx.dtcs = memobj.dtcs

memobj.urcall = memobj.rpt1call = memobj.rpt2call = ' ' * 8
memobj.tx.urcall = memobj.tx.rpt1call = memobj.tx.rpt2call = ' ' * 8
memobj.filter = memobj.tx.filter = 1

for setting in mem.extra:
if setting.get_name() == "filter":
setattr(memobj, setting.get_name(), int(setting.value) + 1)
else:
setattr(memobj, setting.get_name(), setting.value)

LOG.debug(repr(memobj))
self._send_frame(f)

f = self._recv_frame()
LOG.debug("Result (%r):\n%s",
f._cmd, util.hexprint(bytes(f.get_data())))
if f._cmd == 0xFA:
LOG.error('Radio refused memory')


def probe_model(ser):
"""Probe the radio attached to @ser for its model"""
f = Frame()
Expand Down

0 comments on commit 8c234a9

Please sign in to comment.