# HG changeset patch
# User Richard Birch <n7uoa.birch@gmail.com>
# 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 <http://www.gnu.org/licenses/>.
+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. <b>After clicking OK</b>, 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
