# HG changeset patch # User Jens Jensen kd4tjx@yahoo.com # Date 1388960912 21600 # Sun Jan 05 16:28:32 2014 -0600 # Node ID 53bdc54bcb55b584cac9af85169039d930693cb3 # Parent 3c9f030bbf7e4c6686a30bcc65fd4c11963f1eb6 [vx-3] add basic settings support #1291
diff -r 3c9f030bbf7e -r 53bdc54bcb55 chirp/vx3.py --- a/chirp/vx3.py Sun Jan 05 12:16:16 2014 -0600 +++ b/chirp/vx3.py Sun Jan 05 16:28:32 2014 -0600 @@ -16,7 +16,11 @@
from chirp import chirp_common, yaesu_clone, directory from chirp import bitwise +from chirp.settings import RadioSetting, RadioSettingGroup, \ + RadioSettingValueInteger, RadioSettingValueList, \ + RadioSettingValueBoolean, RadioSettingValueString from textwrap import dedent +import os, re
#interesting offsets which may be checksums needed later #0x0393 checksum1? @@ -24,10 +28,129 @@ #0x0409 checksum2? #0x04C9 checksum2a?
+if os.getenv("CHIRP_DEBUG"): + CHIRP_DEBUG = True +else: + CHIRP_DEBUG = False + MEM_FORMAT = """ #seekto 0x7F4A; u8 checksum;
+#seekto 0x024A; +struct { + u8 unk01_1:3, + att_broadcast:1, + att_marine:1, + unk01_2:2 + att_wx:1; + u8 unk02; + u8 apo; + u8 arts_beep; + u8 unk04_1; + u8 beep_level; + u8 beep_mode; + u8 unk04_2; + u8 arts_cwid[16]; + u8 unk05[10]; + u8 channel_counter; + u8 unk06_1[2]; + u8 dtmf_delay; + u8 dtmf_chan_active; + u8 unk06_2[5]; + u8 emergency_eai_time; + u8 emergency_signal; + u8 unk07[30]; + u8 fw_key_timer; + u8 internet_key; + u8 lamp; + u8 lock_mode; + u8 my_key; + u8 mic_gain; + u8 mem_ch_step; + u8 unk08[3]; + u8 sql_fm; + u8 sql_wfm; + u8 radio_am_sql; + u8 radio_fm_sql; + u8 on_timer; + u8 openmsg_mode; + u8 openmsg[6]; + u8 pager_rxtone1; + u8 pager_rxtone2; + u8 pager_txtone1; + u8 pager_txtone2; + u8 password[4]; + u8 unk10; + u8 priority_time; + u8 ptt_delay; + u8 rx_save; + u8 scan_resume; + u8 scan_restart; + u8 sub_rx_timer; + u8 unk11[7]; + u8 tot; + u8 wake_up; + u8 unk12[2]; + u8 vfo_mode:1, + arts_cwid_enable:1, + scan_lamp:1, + fast_tone_search:1, + ars:1, + dtmf_speed:1, + split_tone:1, + dtmf_autodialer:1; + u8 busy_led:1, + tone_search_mute:1, + unk14_1:1, + bclo:1, + band_edge_beep:1, + unk14_2:2, + txsave:1; + u8 unk15_1:2, + smart_search:1, + emergency_eai:1, + unk15_2:2, + hm_rv:1, + moni_tcall:1; + u8 lock:1, + unk16_1:1, + arts:1, + arts_interval:1, + unk16_2:1, + protect_memory:1, + unk16_3:1, + mem_storage:1; + u8 vol_key_mode:1, + unk17_1:2, + wx_alert:1, + temp_unit:1, + unk17_2:2, + password_active:1; + u8 fm_broadcast_mode:1, + fm_antenna:1, + am_antenna:1, + fm_speaker_out:1, + home_vfo:1, + unk18_1:2, + priority_revert:1; +} settings; + +// banks? +#seekto 0x034D; +u8 banks_unk1; + +#seekto 0x0356; +u32 banks_unk2; + +#seekto 0x0409; +u8 banks_unk3; + +#seekto 0x04CA; +struct { + u8 memory[16]; +} dtmf[10]; + #seekto 0x0B7A; struct { u8 name[6]; @@ -43,12 +166,17 @@ u16 in_use; } bank_used[24];
+#seekto 0x03FE; +struct { + u8 speaker; + u8 earphone; +} volumes;
#seekto 0x20CA; struct { u8 even_pskip:1, even_skip:1, - even_valid:1, + even_valid:1, // TODO: should be "showname", i.e., show alpha name even_masked:1, odd_pskip:1, odd_skip:1, @@ -68,7 +196,7 @@ bbcd freq[3]; u8 power:2, unknown2:4, - tmode:2; + tmode:2; // TODO: tmode should be 6 bits (extended tone modes) u8 name[6]; bbcd offset[3]; u8 unknown3:2, @@ -76,10 +204,13 @@ u8 unknown4:1, dcs:7; u8 unknown5; - u8 unknown6; - u8 unknown7:4, + u8 smetersquelch; + u8 unknown7a:2, + attenuate:1, + unknown7b:1, automode:1, - unknown8:3; + unknown8:1, + bell:2; } memory[999]; """
@@ -88,6 +219,8 @@ DUPLEX = ["", "-", "+", "split"] MODES = ["FM", "AM", "WFM", "Auto", "NFM"] # NFM handled specially in radio TMODES = ["", "Tone", "TSQL", "DTCS"] +## TODO: TMODES = ["", "Tone, "TSQL", "DTCS", "Rev Tone", "User Tone", "Pager", +## "Message", "D Code", "Tone/DTCS", "DTCS/Tone"]
#still need to verify 9 is correct, and add auto: look at byte 1 and 20 STEPS = [ 5.0, 9, 10.0, 12.5, 15.0, 20.0, 25.0, 50.0, 100.0 ] @@ -104,6 +237,7 @@ ("\x00" * 13) + "*" + "\x00\x00,'|\x00\x00\x00\x00" + \ ("\x00" * 64))
+DTMFCHARSET = list("0123456789ABCD*#") POWER_LEVELS = [chirp_common.PowerLevel("High", watts=1.50), chirp_common.PowerLevel("Low", watts=0.10)]
@@ -214,9 +348,8 @@ _model = "AH028" _memsize = 32587 _block_lengths = [ 10, 32577 ] - #right now this reads in 45 seconds and writes in 123 seconds - #attempts to speed it up appear unstable, more testing required - _block_size = 8 + #right now this reads in 45 seconds and writes in 41 seconds + _block_size = 64
@classmethod def get_prompts(cls): @@ -258,6 +391,7 @@ rf.memory_bounds = (1, 999) rf.can_odd_split = True rf.has_ctone = False + rf.has_settings = True return rf
def get_raw_memory(self, number): @@ -361,3 +495,399 @@
def get_bank_model(self): return VX3BankModel(self) + + def _decode_chars(self, inarr): + if CHIRP_DEBUG: + print "@_decode_chars, type: %s" % type(inarr) + print inarr + outstr = "" + for i in inarr: + if i == 0xFF: + break + outstr += CHARSET[i & 0x7F] + return outstr.rstrip() + + def _encode_chars(self, instr, length = 16): + if CHIRP_DEBUG: + print "@_encode_chars, type: %s" % type(instr) + print instr + 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") + sound = RadioSettingGroup("sound", "Sound") + dtmf = RadioSettingGroup("dtmf", "DTMF") + arts = RadioSettingGroup("arts", "ARTS") + eai = RadioSettingGroup("eai", "Emergency") + msg = RadioSettingGroup("msg", "Messages") + top = RadioSettingGroup("top", "All Settings", + basic, sound, arts, dtmf, eai, msg) + + basic.append( RadioSetting("att_wx", "Attenuation WX", + RadioSettingValueBoolean(_settings.att_wx))) + + basic.append( RadioSetting("att_marine", "Attenuation Marine", + RadioSettingValueBoolean(_settings.att_marine))) + + basic.append( RadioSetting("att_broadcast", "Attenuation Broadcast", + RadioSettingValueBoolean(_settings.att_broadcast))) + + basic.append( RadioSetting("ars", "Auto Repeater Shift", + RadioSettingValueBoolean(_settings.ars))) + + basic.append( RadioSetting("home_vfo", "Home->VFO", + RadioSettingValueBoolean(_settings.home_vfo))) + + basic.append( RadioSetting("bclo", "Busy Channel Lockout", + RadioSettingValueBoolean(_settings.bclo))) + + basic.append( RadioSetting("busyled", "Busy LED", + RadioSettingValueBoolean(_settings.busy_led))) + + basic.append( RadioSetting("fast_tone_search", "Fast Tone search", + RadioSettingValueBoolean(_settings.fast_tone_search))) + + basic.append( RadioSetting("priority_revert", "Priority Revert", + RadioSettingValueBoolean(_settings.priority_revert))) + + basic.append( RadioSetting("protect_memory", "Protect memory", + RadioSettingValueBoolean(_settings.protect_memory))) + + basic.append( RadioSetting("scan_lamp", "Scan Lamp", + RadioSettingValueBoolean(_settings.scan_lamp))) + + basic.append( RadioSetting("split_tone", "Split tone", + RadioSettingValueBoolean(_settings.split_tone))) + + basic.append( RadioSetting("tone_search_mute", "Tone search mute", + RadioSettingValueBoolean(_settings.tone_search_mute))) + + basic.append( RadioSetting("txsave", "TX save", + RadioSettingValueBoolean(_settings.txsave))) + + basic.append( RadioSetting("wx_alert", "WX Alert", + RadioSettingValueBoolean(_settings.wx_alert))) + + opts = ["Bar Int", "Bar Ext"] + basic.append( RadioSetting("am_antenna", "AM antenna", + RadioSettingValueList(opts, opts[_settings.am_antenna]))) + + opts = ["Ext Ant", "Earphone"] + basic.append( RadioSetting("fm_antenna", "FM antenna", + RadioSettingValueList(opts, opts[_settings.fm_antenna]))) + + opts = ["off"] + [ "%0.1f" % (t / 60.0) for t in range(30, 750, 30) ] + basic.append( RadioSetting("apo", "APO time (hrs)", + RadioSettingValueList(opts, opts[_settings.apo]))) + + opts = ["+/- 5 MHZ", "+/- 10 MHZ", "+/- 50 MHZ", "+/- 100 MHZ"] + basic.append( RadioSetting("channel_counter", "Channel counter", + RadioSettingValueList(opts, opts[_settings.channel_counter]))) + + opts = ["0.3", "0.5", "0.7", "1.0", "1.5"] + basic.append( RadioSetting("fw_key_timer", "FW key timer (s)", + RadioSettingValueList(opts, opts[_settings.fw_key_timer]))) + + opts = ["Home", "Reverse"] + basic.append( RadioSetting("hm_rv", "HM/RV key", + RadioSettingValueList(opts, opts[_settings.hm_rv]))) + + opts = [ "%d" % t for t in range(2, 11) ] + ["continuous", "off"] + basic.append( RadioSetting("lamp", "Lamp Timer (s)", + RadioSettingValueList(opts, opts[_settings.lamp]))) + + basic.append( RadioSetting("lock", "Lock", + RadioSettingValueBoolean(_settings.lock))) + + opts = ["key", "ptt", "key+ptt"] + basic.append( RadioSetting("lock_mode", "Lock mode", + RadioSettingValueList(opts, opts[_settings.lock_mode]))) + + opts = ["10", "20", "50", "100"] + basic.append( RadioSetting("mem_ch_step", "Memory Chan step", + RadioSettingValueList(opts, opts[_settings.mem_ch_step]))) + + opts = ["lower", "next"] + basic.append( RadioSetting("mem_storage", "Memory storage mode", + RadioSettingValueList(opts, opts[_settings.mem_storage]))) + + opts = [ "%d" % t for t in range(1, 10) ] + basic.append( RadioSetting("mic_gain", "Mic gain", + RadioSettingValueList(opts, opts[_settings.mic_gain]))) + + opts = ["monitor", "tone call"] + basic.append( RadioSetting("moni_tcall", "Moni/TCall button", + RadioSettingValueList(opts, opts[_settings.moni_tcall]))) + + opts = ["off"] + \ + [ "%02d:%02d" % (t / 60, t % 60) for t in range(10, 1450, 10) ] + basic.append( RadioSetting("on_timer", "On Timer (hrs)", + RadioSettingValueList(opts, opts[_settings.on_timer]))) + + opts2 = ["off"] + \ + [ "0.%d" % t for t in range(1, 10) ] + \ + [ "%1.1f" % (t / 10.0) for t in range(10, 105, 5) ] + basic.append( RadioSetting("priority_time", "Priority time", + RadioSettingValueList(opts2, opts2[_settings.priority_time]))) + + opts = ["off", "20", "50", "100", "200"] + basic.append( RadioSetting("ptt_delay", "PTT delay (ms)", + RadioSettingValueList(opts, opts[_settings.ptt_delay]))) + + basic.append( RadioSetting("rx_save", "RX save (s)", + RadioSettingValueList(opts2, opts2[_settings.rx_save]))) + + basic.append( RadioSetting("scan_restart", "Scan restart (s)", + RadioSettingValueList(opts2, opts2[_settings.scan_restart]))) + + opts = [ "%1.1f" % (t / 10.0) for t in range(20, 105, 5) ] + \ + ["busy", "hold"] + basic.append( RadioSetting("scan_resume", "Scan resume (s)", + RadioSettingValueList(opts, opts[_settings.scan_resume]))) + + opts = ["single", "continuous"] + basic.append( RadioSetting("smart_search", "Smart search", + RadioSettingValueList(opts, opts[_settings.smart_search]))) + + opts = ["off"] + [ "TRX %d" % t for t in range(1, 11)] + ["hold"] + \ + [ "TX %d" % t for t in range(1, 11)] + basic.append( RadioSetting("sub_rx_timer", "Sub RX timer", + RadioSettingValueList(opts, opts[_settings.sub_rx_timer]))) + + opts = ["C", "F"] + basic.append( RadioSetting("temp_unit", "Temperature unit", + RadioSettingValueList(opts, opts[_settings.temp_unit]))) + + opts = ["off"] + [ "%1.1f" % (t / 10.0) for t in range(5, 105, 5) ] + basic.append( RadioSetting("tot", "Time-out timer (mins)", + RadioSettingValueList(opts, opts[_settings.tot]))) + + opts = ["all", "band"] + basic.append( RadioSetting("vfo_mode", "VFO mode", + RadioSettingValueList(opts, opts[_settings.vfo_mode]))) + + opts = ["off"] + [ "%d" % t for t in range(5, 65, 5) ] + ["EAI"] + basic.append( RadioSetting("wake_up", "Wake up (s)", + RadioSettingValueList(opts, opts[_settings.wake_up]))) + + opts = ["hold", "3 secs"] + basic.append( RadioSetting("vol_key_mode", "Volume key mode", + RadioSettingValueList(opts, opts[_settings.vol_key_mode]))) + + # subgroup programmable keys + + opts = ["INTNET", "INT MR", "Set Mode (my key)"] + basic.append( RadioSetting("internet_key", "Internet key", + RadioSettingValueList(opts, opts[_settings.internet_key]))) + + keys = [ "Antenna AM", "Antenna FM", "Antenna Attenuator", "Auto Power Off", + "Auto Repeater Shift", "ARTS Beep", "ARTS Interval", "Busy Channel Lockout", + "Bell Ringer", "Bell Select", "Bank Name", "Band Edge Beep", "Beep Level", + "Beep Select", "Beep User", "Busy LED", "Channel Counter", "Clock Shift", + "CW ID", "CW Learning", "CW Pitch", "CW Training", "DC Voltage", + "DCS Code", "DCS Reverse", "DTMF A/M", "DTMF Delay", "DTMF Set", + "DTMF Speed", "EAI Timer", "Emergency Alarm", "Ext Menu", "FW Key", + "Half Deviation", "Home/Reverse", "Home > VFO", "INT Code", + "INT Conn Mode", "INT A/M", "INT Set", "INT Key", "INTNET", "Lamp", + "LED Light", "Lock", "Moni/T-Call", "Mic Gain", "Memory Display", + "Memory Write Mode", "Memory Channel Step", "Memory Name Write", + "Memory Protect", "Memory Skip", "Message List", "Message Reg", + "Message Set", "On Timer", "Open Message", "Pager Answer Back", + "Pager Receive Code", "Pager Transmit Code", "Pager Frequency", + "Priority Revert", "Priority Timer", "Password", "PTT Delay", + "Repeater Shift Direction", "Repeater Shift", "Receive Mode", + "Smart Search", "Save Rx", "Save Tx", "Scan Lamp", "Scan Resume", + "Scan Restart", "Speaker Out", "Squelch Level", "Squelch Type", + "Squelch S Meter", "Squelch Split Tone", "Step", "Stereo", "Sub Rx", + "Temp", "Tone Frequency", "Time Out Timer", "Tone Search Mute", + "Tone Search Speed", "VFO Band", "VFO Skip", "Volume Mode", "Wake Up", + "Weather Alert" ] + rs = RadioSetting("my_key", "My key", + RadioSettingValueList(keys, keys[_settings.my_key - 16])) + # TODO: fix keys list isnt exactly right order + # leave disabled in settings for now + # basic.append(rs) + + # sound tab + + sound.append( RadioSetting("band_edge_beep", "Band edge beep", + RadioSettingValueBoolean(_settings.band_edge_beep))) + + opts = ["off", "key+scan", "key"] + sound.append( RadioSetting("beep_mode", "Beep mode", + RadioSettingValueList(opts, opts[_settings.beep_mode]))) + + _volumes = self._memobj.volumes + + opts = map(str, range(0,33)) + sound.append( RadioSetting("speaker_vol", "Speaker volume", + RadioSettingValueList(opts, opts[_volumes.speaker]))) + + sound.append( RadioSetting("earphone_vol", "Earphone volume", + RadioSettingValueList(opts, opts[_volumes.earphone]))) + + opts = ["auto", "speaker"] + sound.append( RadioSetting("fm_speaker_out", "FM Speaker out", + RadioSettingValueList(opts, opts[_settings.fm_speaker_out]))) + + opts = ["mono", "stereo"] + sound.append( RadioSetting("fm_broadcast_mode", "FM broadcast mode", + RadioSettingValueList(opts, opts[_settings.fm_broadcast_mode]))) + + opts = map(str, range(16)) + sound.append( RadioSetting("sql_fm", "Squelch level (FM)", + RadioSettingValueList(opts, opts[_settings.sql_fm]))) + + opts = map(str, range(9)) + sound.append( RadioSetting("sql_wfm", "Squelch level (WFM)", + RadioSettingValueList(opts, opts[_settings.sql_wfm]))) + + opts = map(str, range(16)) + sound.append( RadioSetting("radio_am_sql", "Squelch level (Broadcast Radio AM)", + RadioSettingValueList(opts, opts[_settings.radio_am_sql]))) + + opts = map(str, range(9)) + sound.append( RadioSetting("radio_fm_sql", "Squelch level (Broadcast Radio FM)", + RadioSettingValueList(opts, opts[_settings.radio_fm_sql]))) + + # dtmf tab + + opts = ["manual", "auto"] + dtmf.append( RadioSetting("dtmf_autodialer", "DTMF autodialer mode", + RadioSettingValueList(opts, opts[_settings.dtmf_autodialer]))) + + opts = ["50", "250", "450", "750", "1000"] + dtmf.append( RadioSetting("dtmf_delay", "DTMF delay (ms)", + RadioSettingValueList(opts, opts[_settings.dtmf_delay]))) + + opts = ["50", "100"] + dtmf.append( RadioSetting("dtmf_speed", "DTMF speed (ms)", + RadioSettingValueList(opts, opts[_settings.dtmf_speed]))) + + opts = map(str, range(10)) + dtmf.append( RadioSetting("dtmf_chan_active", "DTMF active", + RadioSettingValueList(opts, opts[_settings.dtmf_chan_active]))) + + 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] + if CHIRP_DEBUG: + print dtmfstr + dtmfentry = RadioSettingValueString(0, 16, dtmfstr) + dtmfentry.set_charset(DTMFCHARSET + list(" ")) + rs = RadioSetting(name, name.upper(), dtmfentry) + dtmf.append(rs) + + # arts tab + arts.append( RadioSetting("arts", "ARTS", + RadioSettingValueBoolean(_settings.arts))) + + opts = ["off", "in range", "always"] + arts.append( RadioSetting("arts_beep", "ARTS beep", + RadioSettingValueList(opts, opts[_settings.arts_beep]))) + + opts = ["15", "25"] + arts.append( RadioSetting("arts_interval", "ARTS interval", + RadioSettingValueList(opts, opts[_settings.arts_interval]))) + + arts.append( RadioSetting("arts_cwid_enable", "CW ID", + RadioSettingValueBoolean(_settings.arts_cwid_enable))) + + cwid = RadioSettingValueString(0, 16, + self._decode_chars(_settings.arts_cwid.get_value())) + cwid.set_charset(CHARSET) + arts.append( RadioSetting("arts_cwid", "CW ID", cwid )) + + # EAI tab + + eai.append( RadioSetting("emergency_eai", "EAI", + RadioSettingValueBoolean(_settings.emergency_eai))) + + opts = [ "interval %dm" % t for t in range(1, 10) ] + \ + [ "interval %dm" % t for t in range(10, 55, 5) ] + \ + [ "continuous %dm" % t for t in range(1, 10) ] + \ + [ "continuous %dm" % t for t in range(10, 55, 5) ] + + eai.append( RadioSetting("emergency_eai_time", "EAI time", + RadioSettingValueList(opts, opts[_settings.emergency_eai_time]))) + + opts = ["beep", "strobe", "beep+strobe", "beam", "beep+beam", "cw", "beep+cw", "cwt"] + eai.append( RadioSetting("emergency_signal", "emergency signal", + RadioSettingValueList(opts, opts[_settings.emergency_signal]))) + + # msg tab + + opts = ["off", "dc voltage", "message"] + msg.append( RadioSetting("openmsg_mode", "Opening message mode", + RadioSettingValueList(opts, opts[_settings.openmsg_mode]))) + + openmsg = RadioSettingValueString(0, 6, + self._decode_chars(_settings.openmsg.get_value())) + openmsg.set_charset(CHARSET) + msg.append( RadioSetting("openmsg", "Opening Message", openmsg )) + + 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 + if 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) + if CHIRP_DEBUG: + print newval + idx = int(setting[-1:]) + _settings = self._memobj.dtmf[idx] + _settings.memory = newval + continue + if re.match('.*_vol$', setting): + # volume fields + voltype = re.sub('_vol$','', setting) + setattr(self._memobj.volumes, voltype, element.value) + continue + if setting == "my_key": + # my_key is memory is off by 9 from list, beware hacks! + opts = element.value.get_options() + optsidx = opts.index(element.value.get_value()) + idx = optsidx + 16 + setattr(_settings, "my_key", idx) + continue + oldval = getattr(_settings, setting) + newval = element.value + if setting == "arts_cwid": + newval = self._encode_chars(newval) + if setting == "openmsg": + newval = self._encode_chars(newval, 6) + if CHIRP_DEBUG: + print "Setting %s(%s) <= %s" % (setting, + oldval, newval) + setattr(_settings, setting, newval) + except Exception, e: + print element.get_name() + raise + \ No newline at end of file