[chirp_devel] [PATCH] [TH-D72] issue #3283 - add some settings

Angus Ainslie
Fri Feb 5 06:38:06 PST 2016


# HG changeset patch
# User Angus Ainslie <angus at akkea.ca>
# Date 1454682596 25200
#      Fri Feb 05 07:29:56 2016 -0700
# Node ID 6e6bbf77f031d2941287c3db313c25948ae5cd1b
# Parent  93e725a0c16e8a445a92e207396444ba702e5ae1
[TH-D72] issue #3283 - add some settings

Add a settings tab for the Kenwood TH-D720
- audio settings
- display settings
- battery settings

diff -r 93e725a0c16e -r 6e6bbf77f031 chirp/drivers/thd72.py
--- a/chirp/drivers/thd72.py	Sun Jan 31 10:08:41 2016 -0800
+++ b/chirp/drivers/thd72.py	Fri Feb 05 07:29:56 2016 -0700
@@ -1,4 +1,5 @@
 # Copyright 2010 Vernon Mauery <vernon at mauery.org>
+# Copyright 2016 Angus Ainslie <angus at akkea.ca>
 #
 # 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
@@ -15,6 +16,9 @@
 
 from chirp import chirp_common, errors, util, directory
 from chirp import bitwise, memmap
+from chirp.settings import RadioSettingGroup, RadioSetting, RadioSettings
+from chirp.settings import RadioSettingValueInteger, RadioSettingValueString
+from chirp.settings import RadioSettingValueList, RadioSettingValueBoolean
 import time
 import struct
 import sys
@@ -65,6 +69,24 @@
   u8   passwd[6];
 } frontmatter;
 
+#seekto 0x0300;
+struct {
+  char power_on_msg[8];
+  u8 unknown0[8];
+  u8 unknown1[2];
+  u8 lamp_timer;
+  u8 contrast;
+  u8 battery_saver;
+  u8 APO;
+  u8 unknown2;
+  u8 key_beep;
+  u8 unknown3[8];
+  u8 unknown4;
+  u8 balance;
+  u8 unknown5[23];
+  u8 lamp_control;
+} settings;
+
 #seekto 0x0c00;
 struct {
   u8 disabled:7,
@@ -161,7 +183,6 @@
 EXCH_R = "R\x00\x00\x00\x00"
 EXCH_W = "W\x00\x00\x00\x00"
 
-
 # Uploads result in "MCP Error" and garbage data in memory
 # Clone driver disabled in favor of error-checking live driver.
 @directory.register
@@ -176,6 +197,14 @@
     _model = ""  # FIXME: REMOVE
     _dirty_blocks = []
 
+    _LCD_CONTRAST = ["Level %d" % x for x in range(1, 16)]
+    _LAMP_CONTROL = ["Manual", "Auto"]
+    _LAMP_TIMER = ["Seconds %d" % x for x in range(2, 11)]
+    _BATTERY_SAVER = [ "OFF", "0.03 Seconds", "0.2 Seconds", "0.4 Seconds", "0.6 Seconds", "0.8 Seconds", "1 Seconds", "2 Seconds", "3 Seconds", "4 Seconds", "5 Seconds" ]
+    _APO = [ "OFF", "15 Minutes", "30 Minutes", "60 Minutes" ]
+    _AUDIO_BALANCE = [ "Center", "A +50%", "A +100%", "B +50%", "B +100%" ]
+    _KEY_BEEP = [ "OFF", "Radio & GPS", "Radio Only", "GPS Only" ]
+
     def get_features(self):
         rf = chirp_common.RadioFeatures()
         rf.memory_bounds = (0, 1031)
@@ -186,6 +215,7 @@
         rf.has_dtcs_polarity = False
         rf.has_tuning_step = False
         rf.has_bank = False
+        rf.has_settings = True
         rf.valid_tuning_steps = []
         rf.valid_modes = MODES_REV.keys()
         rf.valid_tmodes = TMODES_REV.keys()
@@ -474,6 +504,191 @@
             "\x80\xc8\xb3\x08\x00\x01\x00\x08" + \
             "\x08\x00\xc0\x27\x09\x00\x00\xff"
 
+    def _get_settings(self):
+        top = RadioSettings(self._get_display_settings(),
+                            self._get_audio_settings(),
+                            self._get_battery_settings())
+        return top
+
+    def set_settings(self, settings):
+        _mem = self._memobj
+        for element in settings:
+            if not isinstance(element, RadioSetting):
+                self.set_settings(element)
+                continue
+            if not element.changed():
+                continue
+            try:
+                if element.has_apply_callback():
+                    LOG.debug("Using apply callback")
+                    try:
+                        element.run_apply_callback()
+                    except NotImplementedError as e:
+                        LOG.error(e)
+                    continue
+
+                # Find the object containing setting.
+                obj = _mem
+                bits = element.get_name().split(".")
+                setting = bits[-1]
+                for name in bits[:-1]:
+                    if name.endswith("]"):
+                        name, index = name.split("[")
+                        index = int(index[:-1])
+                        obj = getattr(obj, name)[index]
+                    else:
+                        obj = getattr(obj, name)
+
+                try:
+                    old_val = getattr(obj, setting)
+                    LOG.debug("Setting %s(%r) <= %s" % (
+                            element.get_name(), old_val, element.value))
+                    setattr(obj, setting, element.value)
+                except AttributeError as e:
+                    LOG.error("Setting %s is not in the memory map: %s" %
+                              (element.get_name(), e))
+            except Exception, e:
+                LOG.debug(element.get_name())
+                raise
+
+    def get_settings(self):
+        try:
+            return self._get_settings()
+        except:
+            import traceback
+            LOG.error("Failed to parse settings: %s", traceback.format_exc())
+            return None
+
+    @classmethod
+    def apply_power_on_msg(cls, setting, obj):
+        message = setting.value.get_value()
+        setattr(obj, "power_on_msg", cls._add_ff_pad(message, 8))
+
+    def apply_lcd_contrast(cls, setting, obj):
+        rawval = setting.value.get_value()
+        val = cls._LCD_CONTRAST.index(rawval) + 1
+        obj.contrast = val
+
+    def apply_lamp_control(cls, setting, obj):
+        rawval = setting.value.get_value()
+        val = cls._LAMP_CONTROL.index(rawval)
+        obj.lamp_control = val
+
+    def apply_lamp_timer(cls, setting, obj):
+        rawval = setting.value.get_value()
+        val = cls._LAMP_TIMER.index(rawval) + 2
+        obj.lamp_timer = val
+
+    def _get_display_settings(self):
+        menu = RadioSettingGroup("display", "Display")
+        display_settings = self._memobj.settings
+
+        val = RadioSettingValueString(
+            0, 8, str(display_settings.power_on_msg).rstrip("\xFF"))
+        rs = RadioSetting("display.power_on_msg", "Power on message", val)
+        rs.set_apply_callback(self.apply_power_on_msg, display_settings)
+        menu.append(rs)
+        
+        val = RadioSettingValueList(
+            self._LCD_CONTRAST,
+            self._LCD_CONTRAST[display_settings.contrast - 1])
+        rs = RadioSetting("display.contrast", "LCD Contrast",
+                          val)
+        rs.set_apply_callback(self.apply_lcd_contrast, display_settings)
+        menu.append(rs)
+        
+        val = RadioSettingValueList(
+            self._LAMP_CONTROL,
+            self._LAMP_CONTROL[display_settings.lamp_control])
+        rs = RadioSetting("display.lamp_control", "Lamp Control",
+                          val)
+        rs.set_apply_callback(self.apply_lamp_control, display_settings)
+        menu.append(rs)
+
+        val = RadioSettingValueList(
+            self._LAMP_TIMER,
+            self._LAMP_TIMER[display_settings.lamp_timer - 2])
+        rs = RadioSetting("display.lamp_timer", "Lamp Timer",
+                          val)
+        rs.set_apply_callback(self.apply_lamp_timer, display_settings)
+        menu.append(rs)
+
+        return menu
+
+    def apply_battery_saver(cls, setting, obj):
+        rawval = setting.value.get_value()
+        val = cls._BATTERY_SAVER.index(rawval)
+        obj.battery_saver = val
+
+    def apply_APO(cls, setting, obj):
+        rawval = setting.value.get_value()
+        val = cls._APO.index(rawval)
+        obj.APO = val
+
+    def _get_battery_settings(self):
+        menu = RadioSettingGroup("battery", "Battery")
+        battery_settings = self._memobj.settings
+
+        val = RadioSettingValueList(
+            self._BATTERY_SAVER,
+            self._BATTERY_SAVER[battery_settings.battery_saver])
+        rs = RadioSetting("battery.battery_saver", "Battery Saver",
+                          val)
+        rs.set_apply_callback(self.apply_battery_saver, battery_settings)
+        menu.append(rs)
+
+        val = RadioSettingValueList(
+            self._APO,
+            self._APO[battery_settings.APO])
+        rs = RadioSetting("battery.APO", "Auto Power Off",
+                          val)
+        rs.set_apply_callback(self.apply_APO, battery_settings)
+        menu.append(rs)
+
+        return menu
+
+    def apply_balance(cls, setting, obj):
+        rawval = setting.value.get_value()
+        val = cls._AUDIO_BALANCE.index(rawval)
+        obj.balance = val
+
+    def apply_key_beep(cls, setting, obj):
+        rawval = setting.value.get_value()
+        val = cls._KEY_BEEP.index(rawval)
+        obj.key_beep = val
+
+    def _get_audio_settings(self):
+        menu = RadioSettingGroup("audio", "Audio")
+        audio_settings = self._memobj.settings
+
+        val = RadioSettingValueList(
+            self._AUDIO_BALANCE,
+            self._AUDIO_BALANCE[audio_settings.balance])
+        rs = RadioSetting("audio.balance", "Balance",
+                          val)
+        rs.set_apply_callback(self.apply_balance, audio_settings)
+        menu.append(rs)
+
+        val = RadioSettingValueList(
+            self._KEY_BEEP,
+            self._KEY_BEEP[audio_settings.key_beep])
+        rs = RadioSetting("audio.key_beep", "Key Beep",
+                          val)
+        rs.set_apply_callback(self.apply_key_beep, audio_settings)
+        menu.append(rs)
+
+        return menu
+
+    @staticmethod
+    def _add_ff_pad(val, length):
+        return val.ljust(length, "\xFF")[:length]
+
+    @classmethod
+    def _strip_ff_pads(cls, messages):
+        result = []
+        for msg_text in messages:
+            result.append(str(msg_text).rstrip("\xFF"))
+        return result
 
 if __name__ == "__main__":
     import sys



More information about the chirp_devel mailing list