Project

General

Profile

Feature #10298 » vx6.py

Dan Smith, 01/22/2023 12:25 AM

 
# Copyright 2010 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/>.

from chirp.drivers import yaesu_clone
from chirp import chirp_common, directory, bitwise
from chirp.settings import RadioSettingGroup, RadioSetting, RadioSettings
from chirp.settings import RadioSettingValueString, RadioSettingValueList
from chirp.settings import RadioSettingValueBoolean
from textwrap import dedent
import re

# flags.{even|odd}_pskip: These are actually "preferential *scan* channels".
# Is that what they mean on other radios as well?

# memory {
# step_changed: Channel step has been changed. Bit stays on even after
# you switch back to default step. Don't know why you would
# care
# half_deviation: 2.5 kHz deviation
# cpu_shifted: CPU freq has been shifted (to move a birdie out of channel)
# power: 0-3: ["L1", "L2", "L3", "Hi"]
# pager: Set if this is a paging memory
# tmodes: 0-7: ["", "Tone", "TSQL", "DTCS", "Rv Tn", "D Code",
# "T DCS", "D Tone"]
# Rv Tn: Reverse CTCSS - mutes receiver on tone
# The final 3 are for split:
# D Code: DCS Encode only
# T DCS: Encodes tone, decodes DCS code
# D Tone: Encodes DCS code, decodes tone
# }
MEM_FORMAT = """
#seekto 0x010A;
struct {
u8 auto_power_off;
u8 arts_beep;
u8 bell;
u8 beep_level;
u8 arts_cwid_alpha[16];
u8 unk1[2];
u8 channel_counter_width;
u8 lcd_dimmer;
u8 last_dtmf;
u8 unk2;
u8 internet_code;
u8 last_internet_dtmf;
u8 unk3[3];
u8 emergency;
u8 unk4[16];
u8 lamp;
u8 lock;
u8 unk5;
u8 mic_gain;
u8 unk6[2];
u8 on_timer;
u8 open_message_mode;
u8 open_message[6];
u8 unk7;
u8 unk8:6,
pager_answer_back:1,
unk9:1;
u8 pager_rx_tone1;
u8 pager_rx_tone2;
u8 pager_tx_tone1;
u8 pager_tx_tone2;
u8 password[4];
u8 ptt_delay;
u8 rf_squelch;
u8 rx_save;
u8 resume;
u8 unk10[5];
u8 tx_timeout;
u8 wakeup;
u8 vfo_mode:1,
arts_cwid:1,
scan_lamp:1,
ts_speed:1,
unk11:1,
beep:1,
unk12:1,
dtmf_autodial:1;
u8 busy_led:1,
tone_search_mute:1,
int_autodial:1,
bclo:1,
edge_beep:1,
unk13:1,
dmr_wrt:1,
tx_saver:1;
u8 unk14:2,
smart_search:1,
unk15:3,
home_rev:1,
moni_tcall:1;
u8 unk16:3,
arts_interval:1,
unk17:3,
memory_method:1;
u8 unk18:2,
internet_mode:1,
wx_alert:1,
unk19:1,
att:1,
unk20:2;
} settings;

#seekto 0x018A;
struct {
u16 in_use;
} bank_used[24];

#seekto 0x01D8;
u8 clock_shift;

#seekto 0x0214;
u16 banksoff1;

#seekto 0x0248;
u8 lastsetting1;

#seekto 0x0294;
u16 banksoff2;

#seekto 0x0248;
u8 lastsetting2;

#seekto 0x02CA;
struct {
u8 memory[16];
} dtmf[10];

#seekto 0x03CA;
struct {
u8 memory[8];
u8 empty_ff[8];
} internet_dtmf[64];

#seekto 0x097A;
struct {
u8 name[6];
} bank_names[24];

#seekto 0x0C0A;
struct {
u16 channels[100];
} banks[24];

#seekto 0x1ECA;
struct {
u8 even_pskip:1,
even_skip:1,
even_valid:1,
even_masked:1,
odd_pskip:1,
odd_skip:1,
odd_valid:1,
odd_masked:1;
} flags[500];

#seekto 0x21CA;
struct {
u8 unknown11:1,
step_changed:1,
half_deviation:1,
cpu_shifted:1,
unknown12:4;
u8 mode:2,
duplex:2,
tune_step:4;
bbcd freq[3];
u8 power:2,
unknown2:2,
pager:1,
tmode:3;
u8 name[6];
bbcd offset[3];
u8 tone;
u8 dcs;
u8 unknown5;
} memory[999];
"""

DUPLEX = ["", "-", "+", "split"]
MODES = ["FM", "AM", "WFM", "FM"] # last is auto
TMODES = ["", "Tone", "TSQL",
"", # is this 1750?
"DTCS", "DTCS->", "Tone->DTCS", "DTCS->Tone"]
DTMFCHARSET = list("0123456789ABCD*#-")
STEPS = [5.0, 10.0, 12.5, 15.0, 20.0, 25.0, 50.0, 100.0,
9.0, 200.0, 5.0] # last is auto, 9.0k and 200.0k are unadvertised

CHARSET = ["%i" % int(x) for x in range(10)] + \
[chr(x) for x in range(ord("A"), ord("Z")+1)] + \
list(" +-/?[]u_" + ("\x00" * 9) + "$%%\x00*#.|=\\o@") + \
list("\x00" * 100)

PASS_CHARSET = list("0123456789ABCDEF")

POWER_LEVELS = [chirp_common.PowerLevel("Hi", watts=5.00),
chirp_common.PowerLevel("L3", watts=2.50),
chirp_common.PowerLevel("L2", watts=1.00),
chirp_common.PowerLevel("L1", watts=0.30)]
POWER_LEVELS_220 = [chirp_common.PowerLevel("Hi", watts=1.50),
chirp_common.PowerLevel("L3", watts=1.00),
chirp_common.PowerLevel("L2", watts=0.50),
chirp_common.PowerLevel("L1", watts=0.20)]


class VX6Bank(chirp_common.NamedBank):
"""A VX6 Bank"""
def get_name(self):
_bank = self._model._radio._memobj.bank_names[self.index]
name = ""
for i in _bank.name:
if i == 0xFF:
break
name += CHARSET[i & 0x7F]
return name.rstrip()

def set_name(self, name):
name = name.upper()
_bank = self._model._radio._memobj.bank_names[self.index]
_bank.name = [CHARSET.index(x) for x in name.ljust(6)[:6]]


class VX6BankModel(chirp_common.BankModel):
"""A VX-6 bank model"""

def get_num_mappings(self):
return len(self.get_mappings())

def get_mappings(self):
banks = self._radio._memobj.banks
bank_mappings = []
for index, _bank in enumerate(banks):
bank = VX6Bank(self, "%i" % index, "b%i" % (index + 1))
bank.index = index
bank_mappings.append(bank)

return bank_mappings

def _get_channel_numbers_in_bank(self, bank):
_bank_used = self._radio._memobj.bank_used[bank.index]
if _bank_used.in_use == 0xFFFF:
return set()

_members = self._radio._memobj.banks[bank.index]
return set([int(ch) + 1 for ch in _members.channels if ch != 0xFFFF])

def _update_bank_with_channel_numbers(self, bank, channels_in_bank):
_members = self._radio._memobj.banks[bank.index]
if len(channels_in_bank) > len(_members.channels):
raise Exception("Too many entries in bank %d" % bank.index)

empty = 0
for index, channel_number in enumerate(sorted(channels_in_bank)):
_members.channels[index] = channel_number - 1
empty = index + 1
for index in range(empty, len(_members.channels)):
_members.channels[index] = 0xFFFF

def add_memory_to_mapping(self, memory, bank):
channels_in_bank = self._get_channel_numbers_in_bank(bank)
channels_in_bank.add(memory.number)
self._update_bank_with_channel_numbers(bank, channels_in_bank)
_bank_used = self._radio._memobj.bank_used[bank.index]
_bank_used.in_use = 0x0000 # enable

# also needed for unit to recognize any banks?
self._radio._memobj.banksoff1 = 0x0000
self._radio._memobj.banksoff2 = 0x0000
# TODO: turn back off (0xFFFF) when all banks are empty?

def remove_memory_from_mapping(self, memory, bank):
channels_in_bank = self._get_channel_numbers_in_bank(bank)
try:
channels_in_bank.remove(memory.number)
except KeyError:
raise Exception("Memory %i is not in bank %s. Cannot remove" %
(memory.number, bank))
self._update_bank_with_channel_numbers(bank, channels_in_bank)

if not channels_in_bank:
_bank_used = self._radio._memobj.bank_used[bank.index]
_bank_used.in_use = 0xFFFF # disable bank

def get_mapping_memories(self, bank):
memories = []
for channel in self._get_channel_numbers_in_bank(bank):
memories.append(self._radio.get_memory(channel))

return memories

def get_memory_mappings(self, memory):
banks = []
for bank in self.get_mappings():
if memory.number in self._get_channel_numbers_in_bank(bank):
banks.append(bank)

return banks


@directory.register
class VX6Radio(yaesu_clone.YaesuCloneModeRadio):
"""Yaesu VX-6"""
BAUD_RATE = 19200
VENDOR = "Yaesu"
MODEL = "VX-6"

_model = b"AH021"
_memsize = 32587
_block_lengths = [10, 32577]
_block_size = 16

_APO = ("OFF", "30 min", "1 hour", "3 hour", "5 hour", "8 hour")
_ARTSBEEP = ("Off", "In Range", "Always")
_ARTS_INT = ("15 S", "25 S")
_BELL = ("OFF", "1", "3", "5", "8", "Continuous")
_BEEP_LEVEL = ["%i" % int(x) for x in range(1, 10)]
_CH_CNT = ("5 MHZ", "10 MHZ", "50 MHZ", "100 MHZ")
_DIM_LEVEL = ["%i" % int(x) for x in range(0, 13)]
_EMERGENCY = ("Beep", "Strobe", "Bp+Str", "Beam", "Bp+Bem", "CW",
"Bp+CW", "CWT")
_HOME_REV = ("HOME", "REV")
_INT_CD = ["%i" % int(x) for x in range(0, 10)] + \
[chr(x) for x in range(ord("A"), ord("F")+1)]
_INT_MD = ("SRG: Sister Radio Group", "FRG: Friendly Radio Group")
_LAMP = ("Key", "Continuous", "Off")
_LOCK = ("Key", "Dial", "Key+Dial", "PTT", "Key+PTT", "Dial+PTT", "All")
_MAN_AUTO = ("Manual", "Auto")
_MEM_W_MD = ("Lower", "Next")
_MONI_TCALL = ("MONI", "T-CALL")
_NUM_1_9 = ["%i" % int(x) for x in range(1, 10)]
_NUM_0_9 = ["%i" % int(x) for x in range(10)]
_NUM_0_63 = ["%i" % int(x) for x in range(64)]
_NUM_1_50 = ["%i" % int(x) for x in range(1, 51)]
_ON_TIMER = ["OFF"] + \
["%02d:%02d" % (t / 60, t % 60) for t in range(10, 1450, 10)]
_OPEN_MSG = ("Off", "DC Voltage", "Message")
_PTT_DELAY = ("OFF", "20MS", "50MS", "100MS", "200MS")
_RF_SQL = ("OFF", "S1", "S2", "S3", "S4", "S5",
"S6", "S7", "S8", "S9", "S9+")
_RX_SAVE = ("OFF", "200 ms", "300 MS", "500 MS", "1 S", "2 S")
_RESUME = ("3 SEC", "5 SEC", "10 SEC", "BUSY", "HOLD")
_SMART_SEARCH = ("SINGLE", "CONT")
_TOT = ("OFF", "1MIN", "3MIN", "5MIN", "10MIN")
_TS_SPEED = ("FAST", "SLOW")
_VFO_MODE = ("ALL", "BAND")
_WAKEUP = ("OFF", "5S", "10S", "20S", "30S", "EAI")

@classmethod
def get_prompts(cls):
rp = chirp_common.RadioPrompts()
rp.pre_download = _(dedent("""\
1. Turn radio off.
2. Connect cable to MIC/SP jack.
3. Press and hold in the [F/W] key while turning the radio on
("CLONE" will appear on the display).
4. <b>After clicking OK</b>, press the [BAND] key to send image."""))
rp.pre_upload = _(dedent("""\
1. Turn radio off.
2. Connect cable to MIC/SP jack.
3. Press and hold in the [F/W] key while turning the radio on
("CLONE" will appear on the display).
4. Press the [V/M] key ("-WAIT-" will appear on the LCD)."""))
return rp

def _checksums(self):
return [yaesu_clone.YaesuChecksum(0x0000, 0x7F49)]

def process_mmap(self):
self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)

def get_features(self):
rf = chirp_common.RadioFeatures()
rf.has_bank = True
rf.has_bank_names = True
rf.has_dtcs_polarity = False
rf.valid_modes = ["FM", "WFM", "AM", "NFM"]
rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS", "Cross"]
rf.valid_cross_modes = [x for x in TMODES if '-' in x]
rf.valid_duplexes = DUPLEX
rf.valid_tuning_steps = STEPS
rf.valid_power_levels = POWER_LEVELS
rf.memory_bounds = (1, 999)
rf.valid_bands = [(500000, 998990000)]
rf.valid_characters = "".join(CHARSET)
rf.valid_name_length = 6
rf.can_odd_split = True
rf.has_ctone = False
rf.has_settings = True
return rf

def get_raw_memory(self, number):
return repr(self._memobj.memory[number-1]) + \
repr(self._memobj.flags[(number-1)/2])

def get_memory(self, number):
_mem = self._memobj.memory[number-1]
_flg = self._memobj.flags[(number-1)/2]

nibble = ((number-1) % 2) and "even" or "odd"
used = _flg["%s_masked" % nibble]
valid = _flg["%s_valid" % nibble]
pskip = _flg["%s_pskip" % nibble]
skip = _flg["%s_skip" % nibble]

mem = chirp_common.Memory()
mem.number = number

if not used:
mem.empty = True
if not valid:
mem.empty = True
mem.power = POWER_LEVELS[0]
return mem

mem.freq = chirp_common.fix_rounded_step(int(_mem.freq) * 1000)
mem.offset = chirp_common.fix_rounded_step(int(_mem.offset) * 1000)
mem.rtone = mem.ctone = chirp_common.TONES[_mem.tone & 0x3f]
tmode = TMODES[_mem.tmode]
if '-' in tmode:
mem.tmode = 'Cross'
mem.cross_mode = tmode
else:
mem.tmode = tmode
mem.duplex = DUPLEX[_mem.duplex]
mem.mode = MODES[_mem.mode]
if mem.mode == "FM" and _mem.half_deviation:
mem.mode = "NFM"
mem.dtcs = chirp_common.DTCS_CODES[_mem.dcs & 0x7f]
mem.tuning_step = STEPS[_mem.tune_step]
mem.skip = pskip and "P" or skip and "S" or ""

if mem.freq > 220000000 and mem.freq < 225000000:
mem.power = POWER_LEVELS_220[3 - _mem.power]
else:
mem.power = POWER_LEVELS[3 - _mem.power]

for i in _mem.name:
if i == 0xFF:
break
mem.name += CHARSET[i & 0x7F]
mem.name = mem.name.rstrip()

return mem

def set_memory(self, mem):
_mem = self._memobj.memory[mem.number-1]
_flag = self._memobj.flags[(mem.number-1)/2]

nibble = ((mem.number-1) % 2) and "even" or "odd"
used = _flag["%s_masked" % nibble]
valid = _flag["%s_valid" % nibble]

# initialize new channel to safe defaults
if not mem.empty and not valid:
_flag["%s_valid" % nibble] = True
_mem.unknown11 = 0
_mem.step_changed = 0
_mem.cpu_shifted = 0
_mem.unknown12 = 0
_mem.unknown2 = 0
_mem.pager = 0
_mem.unknown5 = 0

if mem.empty and valid and not used:
_flag["%s_valid" % nibble] = False
return
_flag["%s_masked" % nibble] = not mem.empty

if mem.empty:
return

_mem.freq = mem.freq / 1000
_mem.offset = mem.offset / 1000
_mem.tone = chirp_common.TONES.index(mem.rtone)
if mem.tmode == 'Cross':
_mem.tmode = TMODES.index(mem.cross_mode)
else:
_mem.tmode = TMODES.index(mem.tmode)
_mem.duplex = DUPLEX.index(mem.duplex)
if mem.mode == "NFM":
_mem.mode = MODES.index("FM")
_mem.half_deviation = 1
else:
_mem.mode = MODES.index(mem.mode)
_mem.half_deviation = 0
_mem.dcs = chirp_common.DTCS_CODES.index(mem.dtcs)
_mem.tune_step = STEPS.index(mem.tuning_step)
if mem.power:
_mem.power = 3 - POWER_LEVELS.index(mem.power)
else:
_mem.power = 0

_flag["%s_pskip" % nibble] = mem.skip == "P"
_flag["%s_skip" % nibble] = mem.skip == "S"

_mem.name = [0xFF] * 6
for i in range(0, 6):
_mem.name[i] = CHARSET.index(mem.name.ljust(6)[i])

if mem.name.strip():
_mem.name[0] |= 0x80

def get_bank_model(self):
return VX6BankModel(self)

def _decode_chars(self, inarr):
outstr = ""
for i in inarr:
if i == 0xFF:
break
outchar = CHARSET[i & 0x7F]
if outchar != "\x00":
outstr += outchar
return outstr.rstrip()

def _encode_chars(self, instr, length=16):
outarr = []
instr = str(instr)
for i in range(length):
if i < len(instr):
outarr.append(CHARSET.index(instr[i]))
else:
outarr.append(0xFF)
return outarr

def _get_settings(self):
_settings = self._memobj.settings
basic = RadioSettingGroup("basic", "Basic")
arts = RadioSettingGroup("arts", "ARTS")
dtmf = RadioSettingGroup("dtmf", "DTMF")
wires = RadioSettingGroup("wires", "WIRES")
misc = RadioSettingGroup("misc", "Misc")
top = RadioSettings(basic, arts, dtmf, wires, misc)

# BASIC

val = RadioSettingValueList(
self._APO, self._APO[_settings.auto_power_off])
rs = RadioSetting("auto_power_off", "Auto Power Off", val)
basic.append(rs)

val = RadioSettingValueList(
self._BEEP_LEVEL, self._BEEP_LEVEL[_settings.beep_level])
rs = RadioSetting("beep_level", "Beep Level", val)
basic.append(rs)

val = RadioSettingValueList(
self._DIM_LEVEL, self._DIM_LEVEL[_settings.lcd_dimmer])
rs = RadioSetting("lcd_dimmer", "Dimmer Level", val)
basic.append(rs)

val = RadioSettingValueList(
self._LAMP, self._LAMP[_settings.lamp])
rs = RadioSetting("lamp", "Keypad Lamp", val)
basic.append(rs)

val = RadioSettingValueList(
self._LOCK, self._LOCK[_settings.lock])
rs = RadioSetting("lock", "Lock", val)
basic.append(rs)

val = RadioSettingValueList(
self._NUM_1_9, self._NUM_1_9[_settings.mic_gain])
rs = RadioSetting("mic_gain", "Mic Gain", val)
basic.append(rs)

val = RadioSettingValueList(
self._OPEN_MSG, self._OPEN_MSG[_settings.open_message_mode])
rs = RadioSetting("open_message_mode",
"Open Message Mode", val)
basic.append(rs)

val = RadioSettingValueString(0, 6,
self._decode_chars(
_settings.open_message))
val.set_charset(CHARSET)
rs = RadioSetting("open_message", "Opening Message", val)
basic.append(rs)

passstr = ""
for c in _settings.password:
if c < len(PASS_CHARSET):
passstr += PASS_CHARSET[c]
val = RadioSettingValueString(0, 4, passstr)
val.set_charset(PASS_CHARSET)
rs = RadioSetting("password", "Password", val)
basic.append(rs)

val = RadioSettingValueList(
self._RESUME, self._RESUME[_settings.resume])
rs = RadioSetting("resume", "Scan Resume", val)
basic.append(rs)

val = RadioSettingValueList(
self._MONI_TCALL, self._MONI_TCALL[_settings.moni_tcall])
rs = RadioSetting("moni_tcall", "MONI/T-CALL switch", val)
basic.append(rs)

rs = RadioSetting("scan_lamp", "Scan Lamp",
RadioSettingValueBoolean(_settings.scan_lamp))
basic.append(rs)

rs = RadioSetting("beep", "Keypad Beep",
RadioSettingValueBoolean(_settings.beep))
basic.append(rs)

rs = RadioSetting("busy_led", "Busy LED",
RadioSettingValueBoolean(_settings.busy_led))
basic.append(rs)

rs = RadioSetting("bclo", "Busy Channel Lock-Out",
RadioSettingValueBoolean(_settings.bclo))
basic.append(rs)

rs = RadioSetting("wx_alert", "WX Alert",
RadioSettingValueBoolean(_settings.wx_alert))
basic.append(rs)

rs = RadioSetting("att", "Attenuator",
RadioSettingValueBoolean(_settings.att))
basic.append(rs)

# ARTS

val = RadioSettingValueList(
self._ARTS_INT, self._ARTS_INT[_settings.arts_interval])
rs = RadioSetting("arts_interval", "ARTS Interval", val)
arts.append(rs)

val = RadioSettingValueList(
self._ARTSBEEP, self._ARTSBEEP[_settings.arts_beep])
rs = RadioSetting("arts_beep", "ARTS Beep", val)
arts.append(rs)

rs = RadioSetting("arts_cwid", "ARTS Send CWID",
RadioSettingValueBoolean(_settings.arts_cwid))
arts.append(rs)

val = RadioSettingValueString(0, 16,
self._decode_chars(
_settings.arts_cwid_alpha))
val.set_charset(CHARSET)
rs = RadioSetting("arts_cwid_alpha", "ARTS CW ID", val)
arts.append(rs)

# DTMF

val = RadioSettingValueList(
self._MAN_AUTO, self._MAN_AUTO[_settings.dtmf_autodial])
rs = RadioSetting("dtmf_autodial", "DTMF Autodial", val)
dtmf.append(rs)

val = RadioSettingValueList(
self._NUM_0_9, self._NUM_0_9[_settings.last_dtmf])
rs = RadioSetting("last_dtmf", "Last DTMF Memory Set", val)
dtmf.append(rs)

for i in range(10):
name = "dtmf_" + str(i)
dtmfsetting = self._memobj.dtmf[i]
dtmfstr = ""
for c in dtmfsetting.memory:
if c < len(DTMFCHARSET):
dtmfstr += DTMFCHARSET[c]
dtmfentry = RadioSettingValueString(0, 16, dtmfstr)
rs = RadioSetting(name, name.upper(), dtmfentry)
dtmf.append(rs)

# WIRES

val = RadioSettingValueList(
self._INT_CD, self._INT_CD[_settings.internet_code])
rs = RadioSetting("internet_code", "Internet Code", val)
wires.append(rs)

val = RadioSettingValueList(
self._INT_MD, self._INT_MD[_settings.internet_mode])
rs = RadioSetting("internet_mode",
"Internet Link Connection mode", val)
wires.append(rs)

val = RadioSettingValueList(
self._MAN_AUTO, self._MAN_AUTO[_settings.int_autodial])
rs = RadioSetting("int_autodial", "Internet Autodial", val)
wires.append(rs)

val = RadioSettingValueList(
self._NUM_0_63, self._NUM_0_63[_settings.last_internet_dtmf])
rs = RadioSetting("last_internet_dtmf",
"Last Internet DTMF Memory Set", val)
wires.append(rs)

for i in range(64):
name = "wires_dtmf_" + str(i)
dtmfsetting = self._memobj.internet_dtmf[i]
dtmfstr = ""
for c in dtmfsetting.memory:
if c < len(DTMFCHARSET):
dtmfstr += DTMFCHARSET[c]
dtmfentry = RadioSettingValueString(0, 8, dtmfstr)
rs = RadioSetting(name, name.upper(), dtmfentry)
wires.append(rs)

# MISC

val = RadioSettingValueList(
self._BELL, self._BELL[_settings.bell])
rs = RadioSetting("bell", "CTCSS/DCS Bell", val)
misc.append(rs)

val = RadioSettingValueList(
self._CH_CNT, self._CH_CNT[_settings.channel_counter_width])
rs = RadioSetting("channel_counter_width",
"Channel Counter Search Width", val)
misc.append(rs)

val = RadioSettingValueList(
self._EMERGENCY, self._EMERGENCY[_settings.emergency])
rs = RadioSetting("emergency", "Emergency alarm", val)
misc.append(rs)

val = RadioSettingValueList(
self._ON_TIMER, self._ON_TIMER[_settings.on_timer])
rs = RadioSetting("on_timer", "On Timer", val)
misc.append(rs)

rs = RadioSetting("pager_answer_back", "Pager Answer Back",
RadioSettingValueBoolean(
_settings.pager_answer_back))
misc.append(rs)

val = RadioSettingValueList(
self._NUM_1_50, self._NUM_1_50[_settings.pager_rx_tone1])
rs = RadioSetting("pager_rx_tone1", "Pager RX Tone 1", val)
misc.append(rs)

val = RadioSettingValueList(
self._NUM_1_50, self._NUM_1_50[_settings.pager_rx_tone2])
rs = RadioSetting("pager_rx_tone2", "Pager RX Tone 2", val)
misc.append(rs)

val = RadioSettingValueList(
self._NUM_1_50, self._NUM_1_50[_settings.pager_tx_tone1])
rs = RadioSetting("pager_tx_tone1", "Pager TX Tone 1", val)
misc.append(rs)

val = RadioSettingValueList(
self._NUM_1_50, self._NUM_1_50[_settings.pager_tx_tone2])
rs = RadioSetting("pager_tx_tone2", "Pager TX Tone 2", val)
misc.append(rs)

val = RadioSettingValueList(
self._PTT_DELAY, self._PTT_DELAY[_settings.ptt_delay])
rs = RadioSetting("ptt_delay", "PTT Delay", val)
misc.append(rs)

val = RadioSettingValueList(
self._RF_SQL, self._RF_SQL[_settings.rf_squelch])
rs = RadioSetting("rf_squelch", "RF Squelch", val)
misc.append(rs)

val = RadioSettingValueList(
self._RX_SAVE, self._RX_SAVE[_settings.rx_save])
rs = RadioSetting("rx_save", "RX Save", val)
misc.append(rs)

val = RadioSettingValueList(
self._TOT, self._TOT[_settings.tx_timeout])
rs = RadioSetting("tx_timeout", "TOT", val)
misc.append(rs)

val = RadioSettingValueList(
self._WAKEUP, self._WAKEUP[_settings.wakeup])
rs = RadioSetting("wakeup", "Wakeup", val)
misc.append(rs)

rs = RadioSetting("edge_beep", "Band-Edge Beep",
RadioSettingValueBoolean(_settings.edge_beep))
misc.append(rs)

val = RadioSettingValueList(
self._VFO_MODE, self._VFO_MODE[_settings.vfo_mode])
rs = RadioSetting("vfo_mode", "VFO Band Edge Limiting", val)
misc.append(rs)

rs = RadioSetting("tone_search_mute", "Tone Search Mute",
RadioSettingValueBoolean(_settings.tone_search_mute))
misc.append(rs)

val = RadioSettingValueList(
self._TS_SPEED, self._TS_SPEED[_settings.ts_speed])
rs = RadioSetting("ts_speed", "Tone Search Speed", val)
misc.append(rs)

rs = RadioSetting("dmr_wrt", "Direct Memory Recall Overwrite",
RadioSettingValueBoolean(_settings.dmr_wrt))
misc.append(rs)

rs = RadioSetting("tx_saver", "TX Battery Saver",
RadioSettingValueBoolean(_settings.tx_saver))
misc.append(rs)

val = RadioSettingValueList(
self._SMART_SEARCH, self._SMART_SEARCH[_settings.smart_search])
rs = RadioSetting("smart_search", "Smart Search", val)
misc.append(rs)

val = RadioSettingValueList(
self._HOME_REV, self._HOME_REV[_settings.home_rev])
rs = RadioSetting("home_rev", "HM/RV(EMG)R/H key", val)
misc.append(rs)

val = RadioSettingValueList(
self._MEM_W_MD, self._MEM_W_MD[_settings.memory_method])
rs = RadioSetting("memory_method", "Memory Write Method", val)
misc.append(rs)

return top

def get_settings(self):
try:
return self._get_settings()
except:
import traceback
print(traceback.format_exc())
return None

def set_settings(self, uisettings):
for element in uisettings:
if not isinstance(element, RadioSetting):
self.set_settings(element)
continue
if not element.changed():
continue
try:
setting = element.get_name()
_settings = self._memobj.settings
if re.match('internet_dtmf_\d', setting):
# set dtmf fields
dtmfstr = str(element.value).strip()
newval = []
for i in range(0, 8):
if i < len(dtmfstr):
newval.append(DTMFCHARSET.index(dtmfstr[i]))
else:
newval.append(0xFF)
idx = int(setting[-1:])
_settings = self._memobj.internet_dtmf[idx]
_settings.memory = newval
continue
elif re.match('dtmf_\d', setting):
# set dtmf fields
dtmfstr = str(element.value).strip()
newval = []
for i in range(0, 16):
if i < len(dtmfstr):
newval.append(DTMFCHARSET.index(dtmfstr[i]))
else:
newval.append(0xFF)
idx = int(setting[-1:])
_settings = self._memobj.dtmf[idx]
_settings.memory = newval
continue
oldval = getattr(_settings, setting)
newval = element.value
if setting == "arts_cwid_alpha":
newval = self._encode_chars(newval)
elif setting == "open_message":
newval = self._encode_chars(newval, 6)
elif setting == "password":
newval = self._encode_chars(newval, 4)
setattr(_settings, setting, newval)
except Exception as e:
raise
(5-5/6)