# HG changeset patch # User Richard Birch # Date 1492720810 21600 # Thu Apr 20 14:40:10 2017 -0600 # Node ID 1f571016d77658bd2853621d8fc5b2544a45222a # Parent 0714032989d2d0ea7fa82c231e4ab374835375b4 [vx5] Added some of the settings, corrected upload Fixes #4749 Corrected upload issue, and added some settings. Submitting now rather than waiting till complete as it works and there is an open bug report on this. diff -r 0714032989d2 -r 1f571016d776 chirp/drivers/vx5.py --- a/chirp/drivers/vx5.py Sun Apr 02 10:39:43 2017 -0400 +++ b/chirp/drivers/vx5.py Thu Apr 20 14:40:10 2017 -0600 @@ -13,11 +13,36 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import logging from chirp.drivers import yaesu_clone from chirp import chirp_common, directory, errors, bitwise +from chirp.settings import RadioSetting, RadioSettingGroup, \ + RadioSettingValueInteger, RadioSettingValueList, \ + RadioSettings +from textwrap import dedent + +LOG = logging.getLogger(__name__) MEM_FORMAT = """ +struct icons { + u8 mw_icon; + u8 sw_icon; + u8 fm_icon; + u8 tv_icon; + u8 6m_icon; + u8 2m_icon; + u8 70cm_icon; + u8 air_icon; + u8 act1_icon; + u8 act2_icon; + u8 vfo_icon; + u8 mem_icon; + u8 mem_tune_icon; + u8 pms_icon; + u8 home_icon; +}; + #seekto 0x002A; struct { u8 current_member; @@ -40,13 +65,16 @@ used: 1; } flag[220]; -#seekto 0x0269; -struct { +struct mem_struct { u8 unknown1; u8 unknown2:2, half_deviation:1, - unknown3:5; - u8 unknown4:4, + cpu_shift:1, + unknown3:1, + sp_rx1:1, + unknown4:1 + sp_rx2:1; + u8 unknown5:4, tuning_step:4; bbcd freq[3]; u8 icon:6, @@ -56,17 +84,58 @@ u8 tmode:4, power:2, duplex:2; - u8 unknown7:2, + u8 unknown6:2, tone:6; - u8 unknown8:1, + u8 unknown7:1, dtcs:7; + u8 unknown8; +}; + +#seekto 0x0269; +struct mem_struct memory[220]; + +#seekto 0x1568; +struct mem_struct smemory[10]; + +#seekto 0x1BDE; +struct { + u8 lcd_contrast; + u8 disp_mode; + u8 baro_offset[2]; + u8 alt_offset[2]; + u8 lock_mode; + u8 scn_resume; + u8 rx_save; + u8 lamp_mode; u8 unknown9; -} memory[220]; + u8 arts_beep; + u8 pl_bell; + u8 cwid; + u8 callsign[16]; + u8 off_disp_mode; + struct icons icon; + u8 apo; + u8 tot; + u8 on_time; + u8 meter_symbol; + u8 meter_char[8]; + struct { + u8 digits[16]; + } autodial[8]; + struct { + u8 digits[16]; + } dtmf_decode; + #seekto 0x1D12; + u8 sq_lvl; + u8 w_sq_lvl; +} settings; #seekto 0x1D03; u8 current_bank; + +#seekto 0x1FB9; +u8 checksum; """ - TMODES = ["", "Tone", "TSQL", "DTCS"] DUPLEX = ["", "-", "+", "split"] MODES = ["FM", "AM", "WFM"] @@ -75,6 +144,7 @@ chirp_common.PowerLevel("L3", watts=2.50), chirp_common.PowerLevel("L2", watts=1.00), chirp_common.PowerLevel("L1", watts=0.05)] +SPECIALS = ["%s%d" % (c, i + 1) for i in range(0, 5) for c in ('L', 'U')] class VX5BankModel(chirp_common.BankModel): @@ -167,6 +237,7 @@ def get_features(self): rf = chirp_common.RadioFeatures() rf.can_odd_split = True + rf.has_settings = True rf.has_bank = True rf.has_ctone = False rf.has_dtcs_polarity = False @@ -182,6 +253,7 @@ rf.valid_power_levels = POWER_LEVELS rf.valid_name_length = 8 rf.valid_characters = chirp_common.CHARSET_ASCII + # rf.valid_special_chans = SPECIALS return rf def process_mmap(self): @@ -234,9 +306,10 @@ _mem.unknown3 = 0x00 _mem.unknown4 = 0x00 _mem.icon = 12 # file cabinet icon - _mem.unknown7 = 0x00 + _mem.unknown5 = 0x00 + _mem.unknown6 = 0x0 + _mem.unknown7 = 0x0 _mem.unknown8 = 0x00 - _mem.unknown9 = 0x00 if mem.empty and _flg.used and not _flg.visible: _flg.used = False @@ -272,6 +345,130 @@ _flg.skip = mem.skip == "S" _flg.pskip = mem.skip == "P" + def get_settings(self): + _settings = self._memobj.settings + basic = RadioSettingGroup("basic", "Basic") + display = RadioSettingGroup("display", "Display") + top = RadioSettings(basic, display) + + options = ["key", "dial", "key & dial", "ptt", + "key & ptt", "dial & ptt", "all"] + rs = RadioSetting( + "lock_mode", "Lock Mode", + RadioSettingValueList(options, options[_settings.lock_mode])) + basic.append(rs) + + options = ["5 sec", "busy", "hold"] + rs = RadioSetting( + "scn_resume", "Scan Resume", + RadioSettingValueList(options, options[_settings.scn_resume])) + basic.append(rs) + + options = ["off", "200mS (1:1)", "300mS (1:1.5)", "500mS (1:2.5)", + "1S (1:5)", "2S (1:10)"] + rs = RadioSetting( + "rx_save", "Receive Battery Saver", + RadioSettingValueList(options, options[_settings.rx_save])) + basic.append(rs) + + options = ["key", "toggle", "5 sec"] + rs = RadioSetting( + "lamp_mode", "Lamp Mode", + RadioSettingValueList(options, options[_settings.lamp_mode-1])) + display.append(rs) + + options = ["off", "in range", "always"] + rs = RadioSetting( + "arts_beep", "ARTS Beep", + RadioSettingValueList(options, options[_settings.arts_beep])) + basic.append(rs) + + options = ["off", "1", "3", "5", "8", "repeat"] + rs = RadioSetting( + "pl_bell", "CTCSS/DCS Bell", + RadioSettingValueList(options, options[_settings.pl_bell])) + basic.append(rs) + + options = ["none", "temp", "baro", "alti", "temp & baro", + "temp & alti", "all"] + rs = RadioSetting( + "off_disp_mode", "Power-Off Display Mode", + RadioSettingValueList(options, options[_settings.off_disp_mode])) + display.append(rs) + + options = ["off", "30m", "1h", "3h", "5h", "8h"] + rs = RadioSetting( + "apo", "APO time (hrs)", + RadioSettingValueList(options, options[_settings.apo])) + basic.append(rs) + + options = ["off", "1min", "2.5min", "5min", "10min"] + rs = RadioSetting( + "tot", "Time-Out Timer", + RadioSettingValueList(options, options[_settings.tot])) + basic.append(rs) + + rs = RadioSetting( + "lcd_contrast", "LCD Contrast", + RadioSettingValueInteger(1, 10, _settings.lcd_contrast-5)) + display.append(rs) + + options = [">>", "block", "dot", "equal", "arrow", "minus", "custom"] + rs = RadioSetting( + "meter_symbol", "Meter Symbol", + RadioSettingValueList(options, options[_settings.meter_symbol])) + display.append(rs) + + rs = RadioSetting( + "sq_lvl", "FM Squelch", + RadioSettingValueInteger(1, 15, _settings.sq_lvl)) + basic.append(rs) + + rs = RadioSetting( + "w_sq_lvl", "Wide-FM Squelch", + RadioSettingValueInteger(1, 15, _settings.w_sq_lvl)) + basic.append(rs) + + return top + + 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 + newval = element.value + oldval = getattr(_settings, setting) + LOG.debug("Setting %s(%s) <= %s" % (setting, oldval, newval)) + setattr(_settings, setting, newval) + except Exception: + LOG.debug(element.get_name()) + raise + + @classmethod + def get_prompts(cls): + rp = chirp_common.RadioPrompts() + rp.pre_download = _(dedent("""\ + 1. Turn radio off. + 2. Connect cable to MIC/EAR jack. + 3. Press and hold in the [F/W] key while turning the radio on + ("CLONE" will appear on the display). + 4. After clicking OK, press the [VFO(DW)SC] key to recive + the image from radio.""")) + rp.pre_upload = _(dedent("""\ + 1. Turn radio off. + 2. Connect cable to MIC/EAR jack. + 3. Press and hold in the [F/W] key while turning the radio on + ("CLONE" will appear on the display). + 4. Press the [MR(SKP)SC] key ("CLONE WAIT" will appear on the + LCD). + 5. Click OK to send image to radio.""")) + return rp + @classmethod def match_model(cls, filedata, filename): return len(filedata) == cls._memsize