# Quansheng UV-K5 driver (c) 2023 Jacek Lipkowski # Adapted For UV-K5 EGZUMER custom software By EGZUMER, JOC2 # # based on template.py Copyright 2012 Dan Smith # # 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 2 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 . import logging from chirp import chirp_common, directory, bitwise from chirp.drivers import uvk5 from chirp.settings import RadioSetting, RadioSettingGroup, \ RadioSettingValueBoolean, RadioSettingValueList, \ RadioSettingValueInteger, RadioSettingValueString, \ RadioSettings, InvalidValueError, RadioSettingSubGroup LOG = logging.getLogger(__name__) MEM_FORMAT = """ //#seekto 0x0000; struct { ul32 freq; ul32 offset; // 0x08 u8 rxcode; u8 txcode; // 0x0A u8 txcodeflag:4, rxcodeflag:4; // 0x0B u8 modulation:4, shift:4; // 0x0C u8 __UNUSED1:3, bclo:1, txpower:2, bandwidth:1, freq_reverse:1; // 0x0D u8 __UNUSED2:4, dtmf_pttid:3, dtmf_decode:1; // 0x0E u8 step; u8 scrambler; } channel[214]; //#seekto 0xd60; struct { u8 is_scanlist1:1, is_scanlist2:1, compander:2, is_free:1, band:3; } channel_attributes[207]; #seekto 0xe40; ul16 fmfreq[20]; #seekto 0xe70; u8 call_channel; u8 squelch; u8 max_talk_time; u8 noaa_autoscan; u8 key_lock; u8 vox_switch; u8 vox_level; u8 mic_gain; u8 backlight_min:4, backlight_max:4; u8 channel_display_mode; u8 crossband; u8 battery_save; u8 dual_watch; u8 backlight_time; u8 ste; u8 freq_mode_allowed; #seekto 0xe80; u8 ScreenChannel_A; u8 MrChannel_A; u8 FreqChannel_A; u8 ScreenChannel_B; u8 MrChannel_B; u8 FreqChannel_B; u8 NoaaChannel_A; u8 NoaaChannel_B; #seekto 0xe90; u8 keyM_longpress_action:7, button_beep:1; u8 key1_shortpress_action; u8 key1_longpress_action; u8 key2_shortpress_action; u8 key2_longpress_action; u8 scan_resume_mode; u8 auto_keypad_lock; u8 power_on_dispmode; ul32 password; #seekto 0xea0; u8 voice; u8 s0_level; u8 s9_level; #seekto 0xea8; u8 alarm_mode; u8 roger_beep; u8 rp_ste; u8 TX_VFO; u8 Battery_type; #seekto 0xeb0; char logo_line1[16]; char logo_line2[16]; //#seekto 0xed0; struct { u8 side_tone; char separate_code; char group_call_code; u8 decode_response; u8 auto_reset_time; u8 preload_time; u8 first_code_persist_time; u8 hash_persist_time; u8 code_persist_time; u8 code_interval_time; u8 permit_remote_kill; #seekto 0xee0; char local_code[3]; #seek 5; char kill_code[5]; #seek 3; char revive_code[5]; #seek 3; char up_code[16]; char down_code[16]; } dtmf; //#seekto 0xf18; u8 slDef; u8 sl1PriorEnab; u8 sl1PriorCh1; u8 sl1PriorCh2; u8 sl2PriorEnab; u8 sl2PriorCh1; u8 sl2PriorCh2; #seekto 0xf40; u8 int_flock; u8 int_350tx; u8 int_KILLED; u8 int_200tx; u8 int_500tx; u8 int_350en; u8 int_scren; u8 backlight_on_TX_RX:2, AM_fix:1, mic_bar:1, battery_text:2, live_DTMF_decoder:1, unknown:1; #seekto 0xf50; struct { char name[16]; } channelname[200]; #seekto 0x1c00; struct { char name[8]; char number[3]; #seek 5; } dtmfcontact[16]; struct { struct { #seekto 0x1E00; u8 openRssiThr[10]; #seekto 0x1E10; u8 closeRssiThr[10]; #seekto 0x1E20; u8 openNoiseThr[10]; #seekto 0x1E30; u8 closeNoiseThr[10]; #seekto 0x1E40; u8 closeGlitchThr[10]; #seekto 0x1E50; u8 openGlitchThr[10]; } sqlBand4_7; struct { #seekto 0x1E60; u8 openRssiThr[10]; #seekto 0x1E70; u8 closeRssiThr[10]; #seekto 0x1E80; u8 openNoiseThr[10]; #seekto 0x1E90; u8 closeNoiseThr[10]; #seekto 0x1EA0; u8 closeGlitchThr[10]; #seekto 0x1EB0; u8 openGlitchThr[10]; } sqlBand1_3; #seekto 0x1EC0; struct { ul16 level1; ul16 level2; ul16 level4; ul16 level6; } rssiLevelsBands3_7; struct { ul16 level1; ul16 level2; ul16 level4; ul16 level6; } rssiLevelsBands1_2; struct { struct { u8 lower; u8 center; u8 upper; } low; struct { u8 lower; u8 center; u8 upper; } mid; struct { u8 lower; u8 center; u8 upper; } hi; #seek 7; } txp[7]; #seekto 0x1F40; ul16 batLvl[6]; #seekto 0x1F50; ul16 vox1Thr[10]; #seekto 0x1F68; ul16 vox0Thr[10]; #seekto 0x1F80; u8 micLevel[5]; #seekto 0x1F88; il16 xtalFreqLow; #seekto 0x1F8E; u8 volumeGain; u8 dacGain; } cal; #seekto 0x1FF0; struct { u8 ENABLE_DTMF_CALLING:1, ENABLE_PWRON_PASSWORD:1, ENABLE_TX1750:1, ENABLE_ALARM:1, ENABLE_VOX:1, ENABLE_VOICE:1, ENABLE_NOAA:1, ENABLE_FMRADIO:1; u8 __UNUSED:2, ENABLE_SPECTRUM:1, ENABLE_AM_FIX:1, ENABLE_BLMIN_TMP_OFF:1, ENABLE_RAW_DEMODULATORS:1, ENABLE_WIDE_RX:1, ENABLE_FLASHLIGHT:1; } BUILD_OPTIONS; """ # power UVK5_POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=1.50), chirp_common.PowerLevel("Med", watts=3.00), chirp_common.PowerLevel("High", watts=5.00), ] # scrambler SCRAMBLER_LIST = ["Off", "2600Hz", "2700Hz", "2800Hz", "2900Hz", "3000Hz", "3100Hz", "3200Hz", "3300Hz", "3400Hz", "3500Hz"] # compander COMPANDER_LIST = ["Off", "TX", "RX", "TX/RX"] # rx mode RXMODE_LIST = ["Main only", "Dual RX, respond", "Crossband", "Dual RX, TX on main"] # channel display mode CHANNELDISP_LIST = ["Frequency", "Channel Number", "Name", "Name + Frequency"] # TalkTime TALK_TIME_LIST = ["30 sec", "1 min", "2 min", "3 min", "4 min", "5 min", "6 min", "7 min", "8 min", "9 min", "15 min"] # battery save BATSAVE_LIST = ["Off", "1:1", "1:2", "1:3", "1:4"] # battery type BATTYPE_LIST = ["1600 mAh", "2200 mAh"] # bat txt BAT_TXT_LIST = ["None", "Voltage", "Percentage"] # Backlight auto mode BACKLIGHT_LIST = ["Off", "5s", "10s", "20s", "1min", "2min", "4min", "Always On"] # Backlight LVL BACKLIGHT_LVL_LIST = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] # Backlight _TX_RX_LIST BACKLIGHT_TX_RX_LIST = ["Off", "TX", "RX", "TX/RX"] # flock list extended FLOCK_LIST = ["Default+ (137-174, 400-470 + Tx200, Tx350, Tx500)", "FCC HAM (144-148, 420-450)", "CE HAM (144-146, 430-440)", "GB HAM (144-148, 430-440)", "137-174, 400-430", "137-174, 400-438", "Disable All", "Unlock All"] SCANRESUME_LIST = ["Listen 5 seconds and resume", "Listen until carrier disappears", "Stop scanning after receiving a signal"] WELCOME_LIST = ["Full screen test", "User message", "Battery voltage", "None"] VOICE_LIST = ["Off", "Chinese", "English"] # ACTIVE CHANNEL TX_VFO_LIST = ["A", "B"] ALARMMODE_LIST = ["Site", "Tone"] ROGER_LIST = ["Off", "Roger beep", "MDC data burst"] RTE_LIST = ["Off", "100ms", "200ms", "300ms", "400ms", "500ms", "600ms", "700ms", "800ms", "900ms", "1000ms"] VOX_LIST = ["Off", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] # fm radio supported frequencies FMMIN = 76.0 FMMAX = 108.0 # bands supported by the UV-K5 BANDS_STANDARD = { 0: [50.0, 76.0], 1: [108.0, 136.9999], 2: [137.0, 173.9999], 3: [174.0, 349.9999], 4: [350.0, 399.9999], 5: [400.0, 469.9999], 6: [470.0, 600.0] } BANDS_WIDE = { 0: [18.0, 108.0], 1: [108.0, 136.9999], 2: [137.0, 173.9999], 3: [174.0, 349.9999], 4: [350.0, 399.9999], 5: [400.0, 469.9999], 6: [470.0, 1300.0] } SCANLIST_SELECT_LIST = ["List 1", "List 2", "All channels"] DTMF_CHARS = "0123456789ABCD*# " DTMF_CHARS_ID = "0123456789ABCDabcd" DTMF_CHARS_KILL = "0123456789ABCDabcd" DTMF_CHARS_UPDOWN = "0123456789ABCDabcd#* " DTMF_CODE_CHARS = "ABCD*# " DTMF_DECODE_RESPONSE_LIST = ["Do nothing", "Local ringing", "Replay response", "Local ringing + reply response"] KEYACTIONS_LIST = ["None", "Flashlight", "TX power", "Monitor", "Scan", "VOX", "Alarm", "FM broadcast radio", "1750Hz tone", "Lock keypad", "Switch main VFO", "Switch frequency/memory mode", "Switch demodulation", "Min backlight temporary off", "Spectrum analyzer" ] MIC_GAIN_LIST = ["+1.1dB", "+4.0dB", "+8.0dB", "+12.0dB", "+15.1dB"] def min_max_def(value, min_val, max_val, default): """returns value if in bounds or default otherwise""" if min_val is not None and value < min_val: return default if max_val is not None and value > max_val: return default return value def list_def(value, lst, default): """return value if is in the list, default otherwise""" if isinstance(default, str): default = lst.index(default) if value < 0 or value >= len(lst): return default return value @directory.register @directory.detected_by(uvk5.UVK5Radio) class UVK5RadioEgzumer(uvk5.UVK5RadioBase): """Quansheng UV-K5 (egzumer)""" VENDOR = "Quansheng" MODEL = "UV-K5" VARIANT = "egzumer" BAUD_RATE = 38400 NEEDS_COMPAT_SERIAL = False FIRMWARE_VERSION = "" _cal_start = 0x1E00 # calibration memory start address _pttid_list = ["Off", "Up code", "Down code", "Up+Down code", "Apollo Quindar"] _steps = [2.5, 5, 6.25, 10, 12.5, 25, 8.33, 0.01, 0.05, 0.1, 0.25, 0.5, 1, 1.25, 9, 15, 20, 30, 50, 100, 125, 200, 250, 500] @classmethod def k5_approve_firmware(cls, firmware): return firmware.startswith('EGZUMER ') def _get_bands(self): is_wide = self._memobj.BUILD_OPTIONS.ENABLE_WIDE_RX \ if self._memobj is not None else True bands = BANDS_WIDE if is_wide else BANDS_STANDARD return bands def _find_band(self, hz): mhz = hz/1000000.0 bands = self._get_bands() for bnd, rng in bands.items(): if rng[0] <= mhz <= rng[1]: return bnd return False def _get_vfo_channel_names(self): """generates VFO_CHANNEL_NAMES""" bands = self._get_bands() names = [] for bnd, rng in bands.items(): name = f"F{bnd + 1}({round(rng[0])}M-{round(rng[1])}M)" names.append(name + "A") names.append(name + "B") return names def _get_specials(self): """generates SPECIALS""" specials = {} for idx, name in enumerate(self._get_vfo_channel_names()): specials[name] = 200 + idx return specials # Return information about this radio's features, including # how many memories it has, what bands it supports, etc def get_features(self): rf = super().get_features() rf.valid_special_chans = self._get_vfo_channel_names() rf.valid_modes = ["FM", "NFM", "AM", "NAM", "USB"] rf.valid_bands = [] bands = self._get_bands() for _, rng in bands.items(): rf.valid_bands.append( (int(rng[0]*1000000), int(rng[1]*1000000))) return rf # Convert the raw byte array into a memory object structure def process_mmap(self): self._check_firmware_at_load() self._memobj = bitwise.parse(MEM_FORMAT, self._mmap) def _get_mem_mode(self, _mem): temp_modes = self.get_features().valid_modes temp_modul = _mem.modulation * 2 + _mem.bandwidth if temp_modul < len(temp_modes): return temp_modes[temp_modul] elif temp_modul == 5: # USB with narrow setting return temp_modes[4] elif temp_modul >= len(temp_modes): LOG.error('Mode %i unsupported', temp_modul) return "FM" def get_memory(self, number): mem = super().get_memory(number) try: number = self._get_specials()[number] except KeyError: number -= 1 if number < 200: comp = list_def(self._memobj.channel_attributes[number].compander, COMPANDER_LIST, 0) else: comp = 0 val = RadioSettingValueList(COMPANDER_LIST, None, comp) rs = RadioSetting("compander", "Compander (Compnd)", val) mem.extra.append(rs) return mem def _set_mem_mode(self, _mem, mode): tmp_mode = self.get_features().valid_modes.index(mode) _mem.modulation = tmp_mode / 2 _mem.bandwidth = tmp_mode % 2 if mode == "USB": _mem.bandwidth = 1 # narrow def set_memory(self, mem): super().set_memory(mem) try: number = self._get_specials()[mem.number] except KeyError: number = mem.number - 1 if number < 200 and 'compander' in mem.extra: self._memobj.channel_attributes[number].compander = ( COMPANDER_LIST.index(str(mem.extra['compander'].value))) def set_settings(self, settings): _mem = self._memobj for element in settings: if not isinstance(element, RadioSetting): self.set_settings(element) continue elname = element.get_name() # basic settings # VFO_A e80 ScreenChannel_A if elname == "VFO_A_chn": _mem.ScreenChannel_A = element.value if _mem.ScreenChannel_A < 200: _mem.MrChannel_A = _mem.ScreenChannel_A elif _mem.ScreenChannel_A < 207: _mem.FreqChannel_A = _mem.ScreenChannel_A else: _mem.NoaaChannel_A = _mem.ScreenChannel_A # VFO_B e83 elif elname == "VFO_B_chn": _mem.ScreenChannel_B = element.value if _mem.ScreenChannel_B < 200: _mem.MrChannel_B = _mem.ScreenChannel_B elif _mem.ScreenChannel_B < 207: _mem.FreqChannel_B = _mem.ScreenChannel_B else: _mem.NoaaChannel_B = _mem.ScreenChannel_B # TX_VFO channel selected A,B elif elname == "TX_VFO": _mem.TX_VFO = element.value # call channel elif elname == "call_channel": _mem.call_channel = element.value # squelch elif elname == "squelch": _mem.squelch = element.value # TOT elif elname == "tot": _mem.max_talk_time = element.value # NOAA autoscan elif elname == "noaa_autoscan": _mem.noaa_autoscan = element.value # VOX elif elname == "vox": voxvalue = int(element.value) _mem.vox_switch = voxvalue > 0 _mem.vox_level = (voxvalue - 1) if _mem.vox_switch else 0 # mic gain elif elname == "mic_gain": _mem.mic_gain = element.value # Channel display mode elif elname == "channel_display_mode": _mem.channel_display_mode = element.value # RX Mode elif elname == "rx_mode": tmptxmode = int(element.value) tmpmainvfo = _mem.TX_VFO + 1 _mem.crossband = tmpmainvfo * bool(tmptxmode & 0b10) _mem.dual_watch = tmpmainvfo * bool(tmptxmode & 0b01) # Battery Save elif elname == "battery_save": _mem.battery_save = element.value # Backlight auto mode elif elname == "backlight_time": _mem.backlight_time = element.value # Backlight min elif elname == "backlight_min": _mem.backlight_min = element.value # Backlight max elif elname == "backlight_max": _mem.backlight_max = element.value # Backlight TX_RX elif elname == "backlight_on_TX_RX": _mem.backlight_on_TX_RX = element.value # AM_fix elif elname == "AM_fix": _mem.AM_fix = element.value # mic_bar elif elname == "mem.mic_bar": _mem.mic_bar = element.value # Batterie txt elif elname == "_mem.battery_text": _mem.battery_text = element.value # Tail tone elimination elif elname == "ste": _mem.ste = element.value # VFO Open elif elname == "freq_mode_allowed": _mem.freq_mode_allowed = element.value # Beep control elif elname == "button_beep": _mem.button_beep = element.value # Scan resume mode elif elname == "scan_resume_mode": _mem.scan_resume_mode = element.value # Keypad lock elif elname == "key_lock": _mem.key_lock = element.value # Auto keypad lock elif elname == "auto_keypad_lock": _mem.auto_keypad_lock = element.value # Power on display mode elif elname == "welcome_mode": _mem.power_on_dispmode = element.value # Keypad Tone elif elname == "voice": _mem.voice = element.value elif elname == "s0_level": _mem.s0_level = element.value * -1 elif elname == "s9_level": _mem.s9_level = element.value * -1 elif elname == "password": if element.value.get_value() is None or element.value == "": _mem.password = 0xFFFFFFFF else: _mem.password = element.value # Alarm mode elif elname == "alarm_mode": _mem.alarm_mode = element.value # Reminding of end of talk elif elname == "roger_beep": _mem.roger_beep = element.value # Repeater tail tone elimination elif elname == "rp_ste": _mem.rp_ste = element.value # Logo string 1 elif elname == "logo1": bts = str(element.value).rstrip("\x20\xff\x00")+"\x00" * 12 _mem.logo_line1 = bts[0:12] + "\x00\xff\xff\xff" # Logo string 2 elif elname == "logo2": bts = str(element.value).rstrip("\x20\xff\x00")+"\x00" * 12 _mem.logo_line2 = bts[0:12] + "\x00\xff\xff\xff" # unlock settings # FLOCK elif elname == "int_flock": _mem.int_flock = element.value # 350TX elif elname == "int_350tx": _mem.int_350tx = element.value # KILLED elif elname == "int_KILLED": _mem.int_KILLED = element.value # 200TX elif elname == "int_200tx": _mem.int_200tx = element.value # 500TX elif elname == "int_500tx": _mem.int_500tx = element.value # 350EN elif elname == "int_350en": _mem.int_350en = element.value # SCREN elif elname == "int_scren": _mem.int_scren = element.value # battery type elif elname == "Battery_type": _mem.Battery_type = element.value # fm radio for i in range(1, 21): freqname = "FM_%i" % i if elname == freqname: val = str(element.value).strip() try: val2 = int(float(val) * 10) except Exception: val2 = 0xffff if val2 < FMMIN * 10 or val2 > FMMAX * 10: val2 = 0xffff # raise errors.InvalidValueError( # "FM radio frequency should be a value " # "in the range %.1f - %.1f" % (FMMIN , FMMAX)) _mem.fmfreq[i-1] = val2 # dtmf settings if elname == "dtmf_side_tone": _mem.dtmf.side_tone = element.value elif elname == "dtmf_separate_code": _mem.dtmf.separate_code = element.value elif elname == "dtmf_group_call_code": _mem.dtmf.group_call_code = element.value elif elname == "dtmf_decode_response": _mem.dtmf.decode_response = element.value elif elname == "dtmf_auto_reset_time": _mem.dtmf.auto_reset_time = element.value elif elname == "dtmf_preload_time": _mem.dtmf.preload_time = element.value // 10 elif elname == "dtmf_first_code_persist_time": _mem.dtmf.first_code_persist_time = element.value // 10 elif elname == "dtmf_hash_persist_time": _mem.dtmf.hash_persist_time = element.value // 10 elif elname == "dtmf_code_persist_time": _mem.dtmf.code_persist_time = element.value // 10 elif elname == "dtmf_code_interval_time": _mem.dtmf.code_interval_time = element.value // 10 elif elname == "dtmf_permit_remote_kill": _mem.dtmf.permit_remote_kill = element.value elif elname == "dtmf_dtmf_local_code": k = str(element.value).rstrip("\x20\xff\x00") + "\x00" * 3 _mem.dtmf.local_code = k[0:3] elif elname == "dtmf_dtmf_up_code": k = str(element.value).strip("\x20\xff\x00") + "\x00" * 16 _mem.dtmf.up_code = k[0:16] elif elname == "dtmf_dtmf_down_code": k = str(element.value).rstrip("\x20\xff\x00") + "\x00" * 16 _mem.dtmf.down_code = k[0:16] elif elname == "dtmf_kill_code": k = str(element.value).strip("\x20\xff\x00") + "\x00" * 5 _mem.dtmf.kill_code = k[0:5] elif elname == "dtmf_revive_code": k = str(element.value).strip("\x20\xff\x00") + "\x00" * 5 _mem.dtmf.revive_code = k[0:5] elif elname == "live_DTMF_decoder": _mem.live_DTMF_decoder = element.value # dtmf contacts for i in range(1, 17): varname = "DTMF_%i" % i if elname == varname: k = str(element.value).rstrip("\x20\xff\x00") + "\x00" * 8 _mem.dtmfcontact[i-1].name = k[0:8] varnumname = "DTMFNUM_%i" % i if elname == varnumname: k = str(element.value).rstrip("\x20\xff\x00") + "\xff" * 3 _mem.dtmfcontact[i-1].number = k[0:3] # scanlist stuff if elname == "slDef": _mem.slDef = element.value elif elname == "sl1PriorEnab": _mem.sl1PriorEnab = element.value elif elname == "sl2PriorEnab": _mem.sl2PriorEnab = element.value elif elname in ["sl1PriorCh1", "sl1PriorCh2", "sl2PriorCh1", "sl2PriorCh2"]: val = int(element.value) if val > 200 or val < 1: val = 0xff else: val -= 1 _mem[elname] = val if elname == "key1_shortpress_action": _mem.key1_shortpress_action = \ KEYACTIONS_LIST.index(element.value) elif elname == "key1_longpress_action": _mem.key1_longpress_action = \ KEYACTIONS_LIST.index(element.value) elif elname == "key2_shortpress_action": _mem.key2_shortpress_action = \ KEYACTIONS_LIST.index(element.value) elif elname == "key2_longpress_action": _mem.key2_longpress_action = \ KEYACTIONS_LIST.index(element.value) elif elname == "keyM_longpress_action": _mem.keyM_longpress_action = \ KEYACTIONS_LIST.index(element.value) elif elname == "upload_calibration": self._upload_calibration = bool(element.value) elif element.changed() and elname.startswith("cal."): _mem.get_path(elname).set_value(element.value) def get_settings(self): _mem = self._memobj basic = RadioSettingGroup("basic", "Basic Settings") advanced = RadioSettingGroup("advanced", "Advanced Settings") keya = RadioSettingGroup("keya", "Programmable Keys") dtmf = RadioSettingGroup("dtmf", "DTMF Settings") dtmfc = RadioSettingGroup("dtmfc", "DTMF Contacts") scanl = RadioSettingGroup("scn", "Scan Lists") unlock = RadioSettingGroup("unlock", "Unlock Settings") fmradio = RadioSettingGroup("fmradio", "FM Radio") calibration = RadioSettingGroup("calibration", "Calibration") roinfo = RadioSettingGroup("roinfo", "Driver Information") top = RadioSettings() top.append(basic) top.append(advanced) top.append(keya) top.append(dtmf) if _mem.BUILD_OPTIONS.ENABLE_DTMF_CALLING: top.append(dtmfc) top.append(scanl) top.append(unlock) if _mem.BUILD_OPTIONS.ENABLE_FMRADIO: top.append(fmradio) top.append(roinfo) top.append(calibration) # helper function def append_label(radio_setting, label, descr=""): if not hasattr(append_label, 'idx'): append_label.idx = 0 val = RadioSettingValueString(len(descr), len(descr), descr) val.set_mutable(False) rs = RadioSetting("label%s" % append_label.idx, label, val) append_label.idx += 1 radio_setting.append(rs) # Programmable keys def get_action(action_num): """"get actual key action""" lst = KEYACTIONS_LIST.copy() if not self._memobj.BUILD_OPTIONS.ENABLE_ALARM: lst.remove("Alarm") if not self._memobj.BUILD_OPTIONS.ENABLE_TX1750: lst.remove("1750Hz tone") if not self._memobj.BUILD_OPTIONS.ENABLE_FLASHLIGHT: lst.remove("Flashlight") if not self._memobj.BUILD_OPTIONS.ENABLE_VOX: lst.remove("VOX") if not self._memobj.BUILD_OPTIONS.ENABLE_FMRADIO: lst.remove("FM broadcast radio") if not self._memobj.BUILD_OPTIONS.ENABLE_BLMIN_TMP_OFF: lst.remove("Min backlight temporary off") if not self._memobj.BUILD_OPTIONS.ENABLE_SPECTRUM: lst.remove("Spectrum analyzer") action_num = int(action_num) if action_num >= len(KEYACTIONS_LIST) or \ KEYACTIONS_LIST[action_num] not in lst: action_num = 0 return lst, KEYACTIONS_LIST[action_num] val = RadioSettingValueList(*get_action(_mem.key1_shortpress_action)) rs = RadioSetting("key1_shortpress_action", "Side key 1 short press (F1Shrt)", val) keya.append(rs) val = RadioSettingValueList(*get_action(_mem.key1_longpress_action)) rs = RadioSetting("key1_longpress_action", "Side key 1 long press (F1Long)", val) keya.append(rs) val = RadioSettingValueList(*get_action(_mem.key2_shortpress_action)) rs = RadioSetting("key2_shortpress_action", "Side key 2 short press (F2Shrt)", val) keya.append(rs) val = RadioSettingValueList(*get_action(_mem.key2_longpress_action)) rs = RadioSetting("key2_longpress_action", "Side key 2 long press (F2Long)", val) keya.append(rs) val = RadioSettingValueList(*get_action(_mem.keyM_longpress_action)) rs = RadioSetting("keyM_longpress_action", "Menu key long press (M Long)", val) keya.append(rs) # ----------------- DTMF settings tmpval = str(_mem.dtmf.separate_code) if tmpval not in DTMF_CODE_CHARS: tmpval = '*' val = RadioSettingValueString(1, 1, tmpval) val.set_charset(DTMF_CODE_CHARS) sep_code_setting = RadioSetting("dtmf_separate_code", "Separate Code", val) tmpval = str(_mem.dtmf.group_call_code) if tmpval not in DTMF_CODE_CHARS: tmpval = '#' val = RadioSettingValueString(1, 1, tmpval) val.set_charset(DTMF_CODE_CHARS) group_code_setting = RadioSetting("dtmf_group_call_code", "Group Call Code", val) tmpval = min_max_def(_mem.dtmf.first_code_persist_time * 10, 30, 1000, 300) val = RadioSettingValueInteger(30, 1000, tmpval, 10) first_code_per_setting = \ RadioSetting("dtmf_first_code_persist_time", "First code persist time (ms)", val) tmpval = min_max_def(_mem.dtmf.hash_persist_time * 10, 30, 1000, 300) val = RadioSettingValueInteger(30, 1000, tmpval, 10) spec_per_setting = RadioSetting("dtmf_hash_persist_time", "#/* persist time (ms)", val) tmpval = min_max_def(_mem.dtmf.code_persist_time * 10, 30, 1000, 300) val = RadioSettingValueInteger(30, 1000, tmpval, 10) code_per_setting = RadioSetting("dtmf_code_persist_time", "Code persist time (ms)", val) tmpval = min_max_def(_mem.dtmf.code_interval_time * 10, 30, 1000, 300) val = RadioSettingValueInteger(30, 1000, tmpval, 10) code_int_setting = RadioSetting("dtmf_code_interval_time", "Code interval time (ms)", val) tmpval = str(_mem.dtmf.local_code).upper().strip( "\x00\xff\x20") for i in tmpval: if i in DTMF_CHARS_ID: continue tmpval = "103" break val = RadioSettingValueString(3, 3, tmpval) val.set_charset(DTMF_CHARS_ID) ani_id_setting = \ RadioSetting("dtmf_dtmf_local_code", "Local code (ANI ID)", val) ani_id_setting.set_doc('3 chars 0-9 ABCD') tmpval = str(_mem.dtmf.up_code).upper().strip( "\x00\xff\x20") for i in tmpval: if i in DTMF_CHARS_UPDOWN or i == "": continue else: tmpval = "123" break val = RadioSettingValueString(1, 16, tmpval) val.set_charset(DTMF_CHARS_UPDOWN) up_code_setting = \ RadioSetting("dtmf_dtmf_up_code", "Up code", val) up_code_setting.set_doc('1-16 chars 0-9 ABCD*#') tmpval = str(_mem.dtmf.down_code).upper().strip( "\x00\xff\x20") for i in tmpval: if i in DTMF_CHARS_UPDOWN: continue else: tmpval = "456" break val = RadioSettingValueString(1, 16, tmpval) val.set_charset(DTMF_CHARS_UPDOWN) dw_code_setting = \ RadioSetting("dtmf_dtmf_down_code", "Down code", val) dw_code_setting.set_doc('1-16 chars 0-9 ABCD*#') val = RadioSettingValueBoolean(_mem.dtmf.side_tone) dtmf_side_tone_setting = \ RadioSetting("dtmf_side_tone", "DTMF Sidetone on speaker when sent (D ST)", val) tmpval = list_def(_mem.dtmf.decode_response, DTMF_DECODE_RESPONSE_LIST, 0) val = RadioSettingValueList(DTMF_DECODE_RESPONSE_LIST, None, tmpval) dtmf_resp_setting = RadioSetting("dtmf_decode_response", "Decode Response (D Resp)", val) tmpval = min_max_def(_mem.dtmf.auto_reset_time, 5, 60, 10) val = RadioSettingValueInteger(5, 60, tmpval) d_hold_setting = RadioSetting("dtmf_auto_reset_time", "Auto reset time (s) (D Hold)", val) # D Prel tmpval = min_max_def(_mem.dtmf.preload_time * 10, 30, 990, 300) val = RadioSettingValueInteger(30, 990, tmpval, 10) d_prel_setting = RadioSetting("dtmf_preload_time", "Pre-load time (ms) (D Prel)", val) # D LIVE val = RadioSettingValueBoolean(_mem.live_DTMF_decoder) d_live_setting = \ RadioSetting("live_DTMF_decoder", "Displays DTMF codes" " received in the middle of the screen (D Live)", val) val = RadioSettingValueBoolean(_mem.dtmf.permit_remote_kill) perm_kill_setting = RadioSetting("dtmf_permit_remote_kill", "Permit remote kill", val) tmpval = str(_mem.dtmf.kill_code).upper().strip( "\x00\xff\x20") for i in tmpval: if i in DTMF_CHARS_KILL: continue else: tmpval = "77777" break if not len(tmpval) == 5: tmpval = "77777" val = RadioSettingValueString(5, 5, tmpval) val.set_charset(DTMF_CHARS_KILL) kill_code_setting = RadioSetting("dtmf_kill_code", "Kill code", val) kill_code_setting.set_doc('5 chars 0-9 ABCD') tmpval = str(_mem.dtmf.revive_code).upper().strip( "\x00\xff\x20") for i in tmpval: if i in DTMF_CHARS_KILL: continue else: tmpval = "88888" break if not len(tmpval) == 5: tmpval = "88888" val = RadioSettingValueString(5, 5, tmpval) val.set_charset(DTMF_CHARS_KILL) rev_code_setting = RadioSetting("dtmf_revive_code", "Revive code", val) rev_code_setting.set_doc('5 chars 0-9 ABCD') val = RadioSettingValueBoolean(_mem.int_KILLED) killed_setting = RadioSetting("int_KILLED", "DTMF kill lock", val) # ----------------- DTMF Contacts for i in range(1, 17): varname = "DTMF_"+str(i) varnumname = "DTMFNUM_"+str(i) vardescr = "DTMF Contact "+str(i)+" name" varinumdescr = "DTMF Contact "+str(i)+" number" cntn = str(_mem.dtmfcontact[i-1].name).strip("\x20\x00\xff") cntnum = str(_mem.dtmfcontact[i-1].number).strip("\x20\x00\xff") val = RadioSettingValueString(0, 8, cntn) rs = RadioSetting(varname, vardescr, val) dtmfc.append(rs) val = RadioSettingValueString(0, 3, cntnum) val.set_charset(DTMF_CHARS) rs = RadioSetting(varnumname, varinumdescr, val) rs.set_doc("DTMF Contacts are 3 codes (valid: 0-9 * # ABCD), " "or an empty string") dtmfc.append(rs) # ----------------- Scan Lists tmpscanl = list_def(_mem.slDef, SCANLIST_SELECT_LIST, 0) val = RadioSettingValueList(SCANLIST_SELECT_LIST, None, tmpscanl) rs = RadioSetting("slDef", "Default scanlist (SList)", val) scanl.append(rs) val = RadioSettingValueBoolean(_mem.sl1PriorEnab) rs = RadioSetting("sl1PriorEnab", "List 1 priority channel scan", val) scanl.append(rs) ch_list = ["None"] for ch in range(1, 201): ch_list.append("Channel M%i" % ch) tmpch = list_def(_mem.sl1PriorCh1 + 1, ch_list, 0) val = RadioSettingValueList(ch_list, None, tmpch) rs = RadioSetting("sl1PriorCh1", "List 1 priority channel 1", val) scanl.append(rs) tmpch = list_def(_mem.sl1PriorCh2 + 1, ch_list, 0) val = RadioSettingValueList(ch_list, None, tmpch) rs = RadioSetting("sl1PriorCh2", "List 1 priority channel 2", val) scanl.append(rs) val = RadioSettingValueBoolean(_mem.sl2PriorEnab) rs = RadioSetting("sl2PriorEnab", "List 2 priority channel scan", val) scanl.append(rs) tmpch = list_def(_mem.sl2PriorCh1 + 1, ch_list, 0) val = RadioSettingValueList(ch_list, None, tmpch) rs = RadioSetting("sl2PriorCh1", "List 2 priority channel 1", val) scanl.append(rs) tmpch = list_def(_mem.sl2PriorCh2 + 1, ch_list, 0) val = RadioSettingValueList(ch_list, None, tmpch) rs = RadioSetting("sl2PriorCh2", "List 2 priority channel 2", val) scanl.append(rs) # ----------------- Basic settings ch_list = [] for ch in range(1, 201): ch_list.append("Channel M%i" % ch) for bnd in range(1, 8): ch_list.append("Band F%i" % bnd) if _mem.BUILD_OPTIONS.ENABLE_NOAA: for bnd in range(1, 11): ch_list.append("NOAA N%i" % bnd) tmpfreq0 = list_def(_mem.ScreenChannel_A, ch_list, 0) val = RadioSettingValueList(ch_list, None, tmpfreq0) freq0_setting = RadioSetting("VFO_A_chn", "VFO A current channel/band", val) tmpfreq1 = list_def(_mem.ScreenChannel_B, ch_list, 0) val = RadioSettingValueList(ch_list, None, tmpfreq1) freq1_setting = RadioSetting("VFO_B_chn", "VFO B current channel/band", val) tmptxvfo = list_def(_mem.TX_VFO, TX_VFO_LIST, 0) val = RadioSettingValueList(TX_VFO_LIST, None, tmptxvfo) tx_vfo_setting = RadioSetting("TX_VFO", "Main VFO", val) tmpsq = min_max_def(_mem.squelch, 0, 9, 1) val = RadioSettingValueInteger(0, 9, tmpsq) squelch_setting = RadioSetting("squelch", "Squelch (Sql)", val) ch_list = [] for ch in range(1, 201): ch_list.append("Channel M%i" % ch) tmpc = list_def(_mem.call_channel, ch_list, 0) val = RadioSettingValueList(ch_list, None, tmpc) call_channel_setting = RadioSetting("call_channel", "One key call channel (1 Call)", val) val = RadioSettingValueBoolean(_mem.key_lock) keypad_cock_setting = RadioSetting("key_lock", "Keypad locked", val) val = RadioSettingValueBoolean(_mem.auto_keypad_lock) auto_keypad_lock_setting = \ RadioSetting("auto_keypad_lock", "Auto keypad lock (KeyLck)", val) tmptot = list_def(_mem.max_talk_time, TALK_TIME_LIST, 1) val = RadioSettingValueList(TALK_TIME_LIST, None, tmptot) tx_t_out_setting = RadioSetting("tot", "Max talk, TX Time Out (TxTOut)", val) tmpbatsave = list_def(_mem.battery_save, BATSAVE_LIST, 4) val = RadioSettingValueList(BATSAVE_LIST, None, tmpbatsave) bat_save_setting = RadioSetting("battery_save", "Battery save (BatSav)", val) val = RadioSettingValueBoolean(_mem.noaa_autoscan) noaa_auto_scan_setting = RadioSetting("noaa_autoscan", "NOAA Autoscan (NOAA-S)", val) tmpmicgain = list_def(_mem.mic_gain, MIC_GAIN_LIST, 2) val = RadioSettingValueList(MIC_GAIN_LIST, None, tmpmicgain) mic_gain_setting = RadioSetting("mic_gain", "Mic Gain (Mic)", val) val = RadioSettingValueBoolean(_mem.mic_bar) mic_bar_setting = RadioSetting("mic_bar", "Microphone Bar display (MicBar)", val) tmpchdispmode = list_def(_mem.channel_display_mode, CHANNELDISP_LIST, 0) val = RadioSettingValueList(CHANNELDISP_LIST, None, tmpchdispmode) ch_disp_setting = RadioSetting("channel_display_mode", "Channel display mode (ChDisp)", val) tmpdispmode = list_def(_mem.power_on_dispmode, WELCOME_LIST, 0) val = RadioSettingValueList(WELCOME_LIST, None, tmpdispmode) p_on_msg_setting = RadioSetting("welcome_mode", "Power ON display message (POnMsg)", val) logo1 = str(_mem.logo_line1).strip("\x20\x00\xff") + "\x00" logo1 = uvk5._getstring(logo1.encode('ascii', errors='ignore'), 0, 12) val = RadioSettingValueString(0, 12, logo1) logo1_setting = RadioSetting("logo1", "Message line 1", val) logo2 = str(_mem.logo_line2).strip("\x20\x00\xff") + "\x00" logo2 = uvk5._getstring(logo2.encode('ascii', errors='ignore'), 0, 12) val = RadioSettingValueString(0, 12, logo2) logo2_setting = RadioSetting("logo2", "Message line 2", val) tmpbattxt = list_def(_mem.battery_text, BAT_TXT_LIST, 2) val = RadioSettingValueList(BAT_TXT_LIST, None, tmpbattxt) bat_txt_setting = RadioSetting("battery_text", "Battery Level Display (BatTXT)", val) tmpback = list_def(_mem.backlight_time, BACKLIGHT_LIST, 0) val = RadioSettingValueList(BACKLIGHT_LIST, None, tmpback) back_lt_setting = RadioSetting("backlight_time", "Backlight time (BackLt)", val) tmpback = list_def(_mem.backlight_min, BACKLIGHT_LVL_LIST, 0) val = RadioSettingValueList(BACKLIGHT_LVL_LIST, None, tmpback) bl_min_setting = RadioSetting("backlight_min", "Backlight level min (BLMin)", val) tmpback = list_def(_mem.backlight_max, BACKLIGHT_LVL_LIST, 10) val = RadioSettingValueList(BACKLIGHT_LVL_LIST, None, tmpback) bl_max_setting = RadioSetting("backlight_max", "Backlight level max (BLMax)", val) tmpback = list_def(_mem.backlight_on_TX_RX, BACKLIGHT_TX_RX_LIST, 0) val = RadioSettingValueList(BACKLIGHT_TX_RX_LIST, None, tmpback) blt_trx_setting = RadioSetting("backlight_on_TX_RX", "Backlight on TX/RX (BltTRX)", val) val = RadioSettingValueBoolean(_mem.button_beep) beep_setting = RadioSetting("button_beep", "Key press beep sound (Beep)", val) tmpalarmmode = list_def(_mem.roger_beep, ROGER_LIST, 0) val = RadioSettingValueList(ROGER_LIST, None, tmpalarmmode) roger_setting = RadioSetting("roger_beep", "End of transmission beep (Roger)", val) val = RadioSettingValueBoolean(_mem.ste) ste_setting = RadioSetting("ste", "Squelch tail elimination (STE)", val) tmprte = list_def(_mem.rp_ste, RTE_LIST, 0) val = RadioSettingValueList(RTE_LIST, None, tmprte) rp_ste_setting = \ RadioSetting("rp_ste", "Repeater squelch tail elimination (RP STE)", val) val = RadioSettingValueBoolean(_mem.AM_fix) am_fix_setting = RadioSetting("AM_fix", "AM reception fix (AM Fix)", val) tmpvox = min_max_def((_mem.vox_level + 1) * _mem.vox_switch, 0, 10, 0) val = RadioSettingValueList(VOX_LIST, None, tmpvox) vox_setting = RadioSetting("vox", "Voice-operated switch (VOX)", val) tmprxmode = list_def((bool(_mem.crossband) << 1) + bool(_mem.dual_watch), RXMODE_LIST, 0) val = RadioSettingValueList(RXMODE_LIST, None, tmprxmode) rx_mode_setting = RadioSetting("rx_mode", "RX Mode (RxMode)", val) val = RadioSettingValueBoolean(_mem.freq_mode_allowed) freq_mode_allowed_setting = RadioSetting("freq_mode_allowed", "Frequency mode allowed", val) tmpscanres = list_def(_mem.scan_resume_mode, SCANRESUME_LIST, 0) val = RadioSettingValueList(SCANRESUME_LIST, None, tmpscanres) scn_rev_setting = RadioSetting("scan_resume_mode", "Scan resume mode (ScnRev)", val) tmpvoice = list_def(_mem.voice, VOICE_LIST, 0) val = RadioSettingValueList(VOICE_LIST, None, tmpvoice) voice_setting = RadioSetting("voice", "Voice", val) tmpalarmmode = list_def(_mem.alarm_mode, ALARMMODE_LIST, 0) val = RadioSettingValueList(ALARMMODE_LIST, None, tmpalarmmode) alarm_setting = RadioSetting("alarm_mode", "Alarm mode", val) # ----------------- Extra settings # S-meter tmp_s0 = -int(_mem.s0_level) tmp_s9 = -int(_mem.s9_level) if tmp_s0 not in range(-200, -91) or tmp_s9 not in range(-160, -51) \ or tmp_s9 < tmp_s0+9: tmp_s0 = -130 tmp_s9 = -76 val = RadioSettingValueInteger(-200, -90, tmp_s0) s0_level_setting = RadioSetting("s0_level", "S-meter S0 level [dBm]", val) val = RadioSettingValueInteger(-160, -50, tmp_s9) s9_level_setting = RadioSetting("s9_level", "S-meter S9 level [dBm]", val) # Battery Type tmpbtype = list_def(_mem.Battery_type, BATTYPE_LIST, 0) val = RadioSettingValueList(BATTYPE_LIST, BATTYPE_LIST[tmpbtype]) bat_type_setting = RadioSetting("Battery_type", "Battery Type (BatTyp)", val) # Power on password def validate_password(value): value = value.strip(" ") if value.isdigit(): return value.zfill(6) if value != "": raise InvalidValueError("Power on password " "can only have digits") return "" pswd_str = str(int(_mem.password)).zfill(6) \ if _mem.password < 1000000 else "" val = RadioSettingValueString(0, 6, pswd_str) val.set_validate_callback(validate_password) pswd_setting = RadioSetting("password", "Power on password", val) # ----------------- FM radio for i in range(1, 21): fmfreq = _mem.fmfreq[i-1] / 10.0 freq_name = str(fmfreq) if fmfreq < FMMIN or fmfreq > FMMAX: freq_name = "" rs = RadioSetting("FM_%i" % i, "Ch %i" % i, RadioSettingValueString(0, 5, freq_name)) fmradio.append(rs) rs.set_doc('Frequency in MHz') # ----------------- Unlock settings # F-LOCK def validate_int_flock(value): mem_val = self._memobj.int_flock if mem_val != 7 and value == FLOCK_LIST[7]: msg = "%r can only be enabled from radio menu" % value raise InvalidValueError(msg) return value tmpflock = list_def(_mem.int_flock, FLOCK_LIST, 0) val = RadioSettingValueList(FLOCK_LIST, None, tmpflock) val.set_validate_callback(validate_int_flock) f_lock_setting = RadioSetting("int_flock", "TX Frequency Lock (F Lock)", val) val = RadioSettingValueBoolean(_mem.int_200tx) tx200_setting = RadioSetting("int_200tx", "Unlock 174-350MHz TX (Tx 200)", val) val = RadioSettingValueBoolean(_mem.int_350tx) tx350_setting = RadioSetting("int_350tx", "Unlock 350-400MHz TX (Tx 350)", val) val = RadioSettingValueBoolean(_mem.int_500tx) tx500_setting = RadioSetting("int_500tx", "Unlock 500-600MHz TX (Tx 500)", val) val = RadioSettingValueBoolean(_mem.int_350en) en350_setting = RadioSetting("int_350en", "Unlock 350-400MHz RX (350 En)", val) val = RadioSettingValueBoolean(_mem.int_scren) en_scrambler_setting = RadioSetting("int_scren", "Scrambler enabled (ScraEn)", val) # ----------------- Driver Info firmware = self.metadata.get('uvk5_firmware', 'UNKNOWN') append_label(roinfo, "Firmware Version", firmware) # ----------------- Calibration val = RadioSettingValueBoolean(False) radio_setting = RadioSetting("upload_calibration", "Upload calibration", val) radio_setting.set_warning( _('This option may break your radio! ' 'Each radio has a unique set of calibration data ' 'and uploading the data from the image will cause ' 'physical harm to the radio if it is from a ' 'different piece of hardware. Do not use this ' 'unless you know what you are doing and accept the ' 'risk of destroying your radio!'), safe_value=False) calibration.append(radio_setting) radio_setting_group = RadioSettingGroup("squelch_calibration", "Squelch") calibration.append(radio_setting_group) bands = {"sqlBand1_3": "Frequency Band 1-3", "sqlBand4_7": "Frequency Band 4-7"} for bnd, bndn in bands.items(): band_group_range = RadioSettingSubGroup(bnd, bndn) radio_setting_group.append(band_group_range) for sql in range(0, 10): band_group = RadioSettingSubGroup( '%s_%i' % (bnd, sql), "Squelch %i" % sql) band_group_range.append(band_group) name = 'cal.%s.openRssiThr[%i]' % (bnd, sql) tempval = min_max_def(_mem.get_path(name), 0, 255, 0) val = RadioSettingValueInteger(0, 255, tempval) radio_setting = RadioSetting(name, "RSSI threshold open", val) band_group.append(radio_setting) name = 'cal.%s.closeRssiThr[%i]' % (bnd, sql) tempval = min_max_def(_mem.get_path(name), 0, 255, 0) val = RadioSettingValueInteger(0, 255, tempval) radio_setting = RadioSetting(name, "RSSI threshold close", val) band_group.append(radio_setting) name = "cal.%s.openNoiseThr[%i]" % (bnd, sql) tempval = min_max_def(_mem.get_path(name), 0, 127, 0) val = RadioSettingValueInteger(0, 127, tempval) radio_setting = RadioSetting(name, "Noise threshold open", val) band_group.append(radio_setting) name = "cal.%s.closeNoiseThr[%i]" % (bnd, sql) tempval = min_max_def(_mem.get_path(name), 0, 127, 0) val = RadioSettingValueInteger(0, 127, tempval) radio_setting = RadioSetting(name, "Noise threshold close", val) band_group.append(radio_setting) name = "cal.%s.openGlitchThr[%i]" % (bnd, sql) tempval = min_max_def(_mem.get_path(name), 0, 255, 0) val = RadioSettingValueInteger(0, 255, tempval) radio_setting = RadioSetting(name, "Glitch threshold open", val) band_group.append(radio_setting) name = "cal.%s.closeGlitchThr[%i]" % (bnd, sql) tempval = min_max_def(_mem.get_path(name), 0, 255, 0) val = RadioSettingValueInteger(0, 255, tempval) radio_setting = RadioSetting(name, "Glitch threshold close", val) band_group.append(radio_setting) # radio_setting_group = RadioSettingGroup("rssi_level_calibration", "RSSI levels") calibration.append(radio_setting_group) bands = {"rssiLevelsBands1_2": "1-2 ", "rssiLevelsBands3_7": "3-7 "} for bnd, bndn in bands.items(): band_group = RadioSettingSubGroup(bnd, 'Frequency Band %s' % bndn) radio_setting_group.append(band_group) for lvl in [1, 2, 4, 6]: name = "cal.%s.level%i" % (bnd, lvl) value = int(_mem.get_path(name)) tempval = min_max_def(value, 0, 65535, 0) val = RadioSettingValueInteger(0, 65535, tempval) radio_setting = RadioSetting(name, "Level %i" % lvl, val) band_group.append(radio_setting) # radio_setting_group = RadioSettingGroup("tx_power_calibration", "TX power") calibration.append(radio_setting_group) for bnd in range(0, 7): band_group = RadioSettingSubGroup('txpower_band_%i' % bnd, 'Band %i' % (bnd + 1)) powers = {"low": "Low", "mid": "Medium", "hi": "High"} radio_setting_group.append(band_group) for pwr, pwrn in powers.items(): bounds = ["lower", "center", "upper"] subgroup = RadioSettingSubGroup('txpower_band_%i_%s' % ( bnd, pwr), pwrn) band_group.append(subgroup) for bound in bounds: name = f"cal.txp[{bnd}].{pwr}.{bound}" tempval = min_max_def(_mem.get_path(name), 0, 255, 0) val = RadioSettingValueInteger(0, 255, tempval) radio_setting = RadioSetting(name, bound.capitalize(), val) subgroup.append(radio_setting) # radio_setting_group = RadioSettingGroup("battery_calibration", "Battery") calibration.append(radio_setting_group) for lvl in range(0, 6): name = "cal.batLvl[%i]" % lvl temp_val = min_max_def(_mem.get_path(name), 0, 4999, 4999) val = RadioSettingValueInteger(0, 4999, temp_val) label = 'Level %i%s' % ( lvl, " (voltage calibration)" if lvl == 3 else "") radio_setting = RadioSetting(name, label, val) radio_setting_group.append(radio_setting) radio_setting_group = RadioSettingGroup("vox_calibration", "VOX") calibration.append(radio_setting_group) for lvl in range(0, 10): name = "cal.vox1Thr[%s]" % lvl val = RadioSettingValueInteger(0, 65535, _mem.get_path(name)) radio_setting = RadioSetting(name, "Level %i On" % (lvl + 1), val) radio_setting_group.append(radio_setting) name = "cal.vox0Thr[%s]" % lvl val = RadioSettingValueInteger(0, 65535, _mem.get_path(name)) radio_setting = RadioSetting(name, "Level %i Off" % (lvl + 1), val) radio_setting_group.append(radio_setting) radio_setting_group = RadioSettingGroup("mic_calibration", "Microphone sensitivity") calibration.append(radio_setting_group) for lvl in range(0, 5): name = "cal.micLevel[%s]" % lvl tempval = min_max_def(_mem.get_path(name), 0, 31, 31) val = RadioSettingValueInteger(0, 31, tempval) radio_setting = RadioSetting(name, "Level %i" % lvl, val) radio_setting_group.append(radio_setting) radio_setting_group = RadioSettingGroup("other_calibration", "Other") calibration.append(radio_setting_group) name = "cal.xtalFreqLow" temp_val = min_max_def(_mem.get_path(name), -1000, 1000, 0) val = RadioSettingValueInteger(-1000, 1000, temp_val) radio_setting = RadioSetting(name, "Xtal frequency low", val) radio_setting_group.append(radio_setting) name = "cal.volumeGain" temp_val = min_max_def(_mem.get_path(name), 0, 63, 58) val = RadioSettingValueInteger(0, 63, temp_val) radio_setting = RadioSetting(name, "Volume gain", val) radio_setting_group.append(radio_setting) name = "cal.dacGain" temp_val = min_max_def(_mem.get_path(name), 0, 15, 8) val = RadioSettingValueInteger(0, 15, temp_val) radio_setting = RadioSetting(name, "DAC gain", val) radio_setting_group.append(radio_setting) # -------- LAYOUT basic.append(squelch_setting) basic.append(rx_mode_setting) basic.append(call_channel_setting) basic.append(auto_keypad_lock_setting) basic.append(tx_t_out_setting) basic.append(bat_save_setting) basic.append(scn_rev_setting) if _mem.BUILD_OPTIONS.ENABLE_NOAA: basic.append(noaa_auto_scan_setting) if _mem.BUILD_OPTIONS.ENABLE_AM_FIX: basic.append(am_fix_setting) dispSubGrp = RadioSettingSubGroup("dispSubGrp", "Display settings") basic.append(dispSubGrp) dispSubGrp.append(bat_txt_setting) dispSubGrp.append(mic_bar_setting) dispSubGrp.append(ch_disp_setting) dispSubGrp.append(p_on_msg_setting) dispSubGrp.append(logo1_setting) dispSubGrp.append(logo2_setting) bcklSubGrp = RadioSettingSubGroup("bcklSubGrp", "Backlight settings") basic.append(bcklSubGrp) bcklSubGrp.append(back_lt_setting) bcklSubGrp.append(bl_min_setting) bcklSubGrp.append(bl_max_setting) bcklSubGrp.append(blt_trx_setting) audioSubGrp = RadioSettingSubGroup("audioSubGrp", "Audio related settings") basic.append(audioSubGrp) if _mem.BUILD_OPTIONS.ENABLE_VOX: audioSubGrp.append(vox_setting) audioSubGrp.append(mic_gain_setting) audioSubGrp.append(beep_setting) audioSubGrp.append(roger_setting) audioSubGrp.append(ste_setting) audioSubGrp.append(rp_ste_setting) if _mem.BUILD_OPTIONS.ENABLE_VOICE: audioSubGrp.append(voice_setting) if _mem.BUILD_OPTIONS.ENABLE_ALARM: audioSubGrp.append(alarm_setting) stateSubGrp = RadioSettingSubGroup("stateSubGrp", "Radio state") basic.append(stateSubGrp) stateSubGrp.append(freq0_setting) stateSubGrp.append(freq1_setting) stateSubGrp.append(tx_vfo_setting) stateSubGrp.append(keypad_cock_setting) advanced.append(freq_mode_allowed_setting) advanced.append(bat_type_setting) advanced.append(s0_level_setting) advanced.append(s9_level_setting) if _mem.BUILD_OPTIONS.ENABLE_PWRON_PASSWORD: advanced.append(pswd_setting) if _mem.BUILD_OPTIONS.ENABLE_DTMF_CALLING: dtmf.append(sep_code_setting) dtmf.append(group_code_setting) dtmf.append(first_code_per_setting) dtmf.append(spec_per_setting) dtmf.append(code_per_setting) dtmf.append(code_int_setting) if _mem.BUILD_OPTIONS.ENABLE_DTMF_CALLING: dtmf.append(ani_id_setting) dtmf.append(up_code_setting) dtmf.append(dw_code_setting) dtmf.append(d_prel_setting) dtmf.append(dtmf_side_tone_setting) if _mem.BUILD_OPTIONS.ENABLE_DTMF_CALLING: dtmf.append(dtmf_resp_setting) dtmf.append(d_hold_setting) dtmf.append(d_live_setting) dtmf.append(perm_kill_setting) dtmf.append(kill_code_setting) dtmf.append(rev_code_setting) dtmf.append(killed_setting) unlock.append(f_lock_setting) unlock.append(tx200_setting) unlock.append(tx350_setting) unlock.append(tx500_setting) unlock.append(en350_setting) unlock.append(en_scrambler_setting) return top