# HG changeset patch # User Dan Smith dsmith@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()