[chirp_devel] [PATCH] [RFC] Add bitwise browser when developer options are enabled

Dan Smith
Sun Mar 3 08:26:53 PST 2013


# HG changeset patch
# User Dan Smith <dsmith at danplanet.com>
# Date 1362327994 28800
# Node ID d7da2968488769d7e32321b0e03d7201662dc079
# Parent  49de55116a55bc5b35a5391aa14b3e68d182e4c7
[RFC] Add bitwise browser when developer options are enabled

This is something I've been wanting to do for a while. It provides a
graphical way to explore the memory object of a clone-mode radio. It is
roughly equivalent to doing "show raw memory" on a channel, but lets
you do the same for other areas, such as the settings, limits, etc.

I want to do more things like let you diff other areas, and perhaps
display the contents in a more formal way so that they can be tweaked
arbitrarily, but that will come later. I'm submitting this here for
comments and folks to try it out. Note that it requires dev tools to be
enabled before opening an image.

Thoughts? Comments?

diff -r 49de55116a55 -r d7da29684887 chirp/bitwise.py
--- a/chirp/bitwise.py	Thu Feb 28 18:13:55 2013 -0800
+++ b/chirp/bitwise.py	Sun Mar 03 08:26:34 2013 -0800
@@ -188,7 +188,7 @@
 
     def __str__(self):
         if isinstance(self.__items[0], charDataElement):
-            return "".join([x.get_value() for x in self.__items])
+            return repr("".join([x.get_value() for x in self.__items]))[1:-1]
         else:
             return str(self.__items)
 
@@ -612,6 +612,13 @@
             raise ValueError("Struct size mismatch during set_raw()")
         self._data[self._offset] = buffer
 
+    def __iter__(self):
+        for item in self._generators.values():
+            yield item
+
+    def items(self):
+        return self._generators.items()
+
 class Processor:
 
     _types = {
diff -r 49de55116a55 -r d7da29684887 chirpui/editorset.py
--- a/chirpui/editorset.py	Thu Feb 28 18:13:55 2013 -0800
+++ b/chirpui/editorset.py	Sun Mar 03 08:26:34 2013 -0800
@@ -19,7 +19,7 @@
 
 from chirp import chirp_common, directory, generic_csv, generic_xml
 from chirpui import memedit, dstaredit, bankedit, common, importdialog
-from chirpui import inputdialog, reporting, settingsedit
+from chirpui import inputdialog, reporting, settingsedit, radiobrowser, config
 
 class EditorSet(gtk.VBox):
     __gsignals__ = {
@@ -65,6 +65,7 @@
             "bank_names"   : None,
             "bank_members" : None,
             "settings"     : None,
+            "browser"      : None,
             }
 
         if isinstance(self.radio, chirp_common.IcomDstarSupport):
@@ -88,6 +89,11 @@
         if rf.has_settings:
             self.editors["settings"] = settingsedit.SettingsEditor(self.rthread)
 
+        conf = config.get()
+        if (hasattr(self.rthread.radio, '_memobj') and
+            conf.get_bool("developer", "state")):
+            self.editors["browser"] = radiobrowser.RadioBrowser(self.rthread)
+
         lab = gtk.Label(_("Memories"))
         self.tabs.append_page(self.editors["memedit"].root, lab)
         self.editors["memedit"].root.show()
@@ -115,6 +121,10 @@
             self.tabs.append_page(self.editors["settings"].root, lab)
             self.editors["settings"].root.show()
 
+        if self.editors["browser"]:
+            lab = gtk.Label(_("Browser"))
+            self.tabs.append_page(self.editors["browser"].root, lab)
+
         self.pack_start(self.tabs)
         self.tabs.show()
 
diff -r 49de55116a55 -r d7da29684887 chirpui/radiobrowser.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chirpui/radiobrowser.py	Sun Mar 03 08:26:34 2013 -0800
@@ -0,0 +1,154 @@
+import gtk
+import gobject
+import pango
+import re
+import os
+
+from chirp import bitwise
+from chirpui import common
+
+def do_insert_line_with_tags(b, line):
+    def i(text, *tags):
+        b.insert_with_tags_by_name(b.get_end_iter(), text, *tags)
+
+    def ident(name):
+        if "unknown" in name:
+            i(name, 'grey', 'bold')
+        else:
+            i(name, 'bold')
+
+    def nonzero(value):
+        i(value, 'red', 'bold')
+
+    def foo(value):
+        i(value, 'blue', 'bold')
+
+    m = re.match("^( *)([A-z0-9_]+: )(0x[A-F0-9]+) \((.*)\)$", line)
+    if m:
+        i(m.group(1))
+        ident(m.group(2))
+        if m.group(3) == '0x00':
+            i(m.group(3))
+        else:
+            nonzero(m.group(3))
+        i(' (')
+        for char in m.group(4):
+            if char == '1':
+                nonzero(char)
+            else:
+                i(char)
+        i(')')
+        return
+
+    m = re.match("^( *)([A-z0-9_]+: )(.*)$", line)
+    if m:
+        i(m.group(1))
+        ident(m.group(2))
+        i(m.group(3))
+        return
+
+    m = re.match("^(.*} )([A-z0-9_]+)( \()([0-9]+)( bytes at )(0x[A-F0-9]+)",
+                 line)
+    if m:
+        i(m.group(1))
+        ident(m.group(2))
+        i(m.group(3))
+        foo(m.group(4))
+        i(m.group(5))
+        foo(m.group(6))
+        i(")")
+        return
+
+    i(line)
+
+def do_insert_with_tags(buf, text):
+    buf.set_text('')
+    lines = text.split(os.linesep)
+    for line in lines:
+        do_insert_line_with_tags(buf, line)
+        buf.insert_with_tags_by_name(buf.get_end_iter(), os.linesep)
+
+class RadioBrowser(common.Editor):
+    def _build_ui(self):
+        self._display = gtk.TextView()
+
+        fontdesc = pango.FontDescription("Courier 10")
+        self._display.modify_font(fontdesc)
+        self._display.set_editable(False)
+        tt = self._display.get_buffer().get_tag_table()
+        for color in ["red", "green", "blue", "grey"]:
+            tag = gtk.TextTag(color)
+            tag.set_property("foreground", color)
+            tt.add(tag)
+        tag = gtk.TextTag("bold")
+        tag.set_property("weight", pango.WEIGHT_BOLD)
+        tt.add(tag)
+
+        self._store = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
+        self._tree = gtk.TreeView(self._store)
+
+        rend = gtk.CellRendererText()
+        tvc = gtk.TreeViewColumn('Element', rend, text=0)
+        self._tree.append_column(tvc)
+        self._tree.connect('button_press_event', self._tree_click)
+        self._tree.set_size_request(200, -1)
+
+        self.root = gtk.HBox(False, 3)
+        sw = gtk.ScrolledWindow()
+        sw.add(self._tree)
+        sw.show()
+        self.root.pack_start(sw, 0, 0, 0)
+        sw = gtk.ScrolledWindow()
+        sw.add(self._display)
+        sw.show()
+        self.root.pack_start(sw, 1, 1, 1)
+        self._tree.show()
+        self._display.show()
+        self.root.show()
+
+    def _fill(self, name, obj, parent=None):
+        iter = self._store.append(parent, (name, obj))
+
+        if isinstance(obj, bitwise.structDataElement):
+            for name, item in obj.items():
+                if isinstance(item, bitwise.structDataElement):
+                    self._fill(name, item, iter)
+                elif isinstance(item, bitwise.arrayDataElement):
+                    self._fill("%s[%i]" % (name, len(item)), item, iter)
+        elif isinstance(obj, bitwise.arrayDataElement):
+            i = 0
+            for item in obj:
+                self._fill("%s[%i]" % (name, i), item, iter)
+                i += 1
+
+    def _tree_click(self, view, event):
+        if event.button != 1:
+            return
+
+        pathinfo = view.get_path_at_pos(int(event.x), int(event.y))
+        path = pathinfo[0]
+        iter = self._store.get_iter(path)
+        name, obj = self._store.get(iter, 0, 1)
+
+        do_insert_with_tags(self._display.get_buffer(), repr(obj))
+
+    def __init__(self, rthread):
+        super(RadioBrowser, self).__init__()
+        self._radio = rthread.radio
+        self._build_ui()
+        self._fill('root', self._radio._memobj)
+
+if __name__ == "__main__":
+    from chirp import *
+    from chirp import directory
+    import sys
+
+    r = directory.get_radio_by_image(sys.argv[1])
+    class Foo:
+        radio = r
+    w = gtk.Window()
+    b = RadioBrowser(Foo)
+    w.set_default_size(1024, 768)
+    w.add(b.root)
+    w.show()
+    gtk.main()



More information about the chirp_devel mailing list