diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d6931853..8358d170 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -60,7 +60,7 @@ jobs:
- name: 'Bundle scripts'
if: ${{ !github.event.pull_request.head.repo.fork }}
run: |
- tar czpf artifacts/flipper-z-any-scripts-${SUFFIX}.tgz scripts debug
+ tar czpf artifacts/flipper-z-any-scripts-${SUFFIX}.tgz scripts
- name: 'Build the firmware'
run: |
diff --git a/.vscode/example/launch.json b/.vscode/example/launch.json
index b0bb9e24..f4b7c6e4 100644
--- a/.vscode/example/launch.json
+++ b/.vscode/example/launch.json
@@ -27,22 +27,21 @@
"type": "cortex-debug",
"servertype": "openocd",
"device": "stlink",
- "svdFile": "./debug/STM32WB55_CM4.svd",
+ "svdFile": "./scripts/debug/STM32WB55_CM4.svd",
// If you're debugging early in the boot process, before OS scheduler is running,
// you have to comment out the following line.
"rtos": "FreeRTOS",
"configFiles": [
"interface/stlink.cfg",
- "./debug/stm32wbx.cfg",
+ "./scripts/debug/stm32wbx.cfg",
],
"postAttachCommands": [
- "source debug/flipperversion.py",
+ "source scripts/debug/flipperversion.py",
"fw-version",
// "compare-sections",
- "source debug/flipperapps.py",
+ "source scripts/debug/flipperapps.py",
"fap-set-debug-elf-root build/latest/.extapps",
- // "source debug/FreeRTOS/FreeRTOS.py",
- // "svd_load debug/STM32WB55_CM4.svd"
+ // "source scripts/debug/FreeRTOS/FreeRTOS.py",
]
// "showDevDebugOutput": "raw",
},
@@ -54,16 +53,16 @@
"type": "cortex-debug",
"servertype": "external",
"gdbTarget": "${input:BLACKMAGIC}",
- "svdFile": "./debug/STM32WB55_CM4.svd",
+ "svdFile": "./scripts/debug/STM32WB55_CM4.svd",
"rtos": "FreeRTOS",
"postAttachCommands": [
"monitor swdp_scan",
"attach 1",
"set confirm off",
"set mem inaccessible-by-default off",
- "source debug/flipperversion.py",
+ "source scripts/debug/flipperversion.py",
"fw-version",
- "source debug/flipperapps.py",
+ "source scripts/debug/flipperapps.py",
"fap-set-debug-elf-root build/latest/.extapps",
// "compare-sections",
]
@@ -78,12 +77,12 @@
"servertype": "jlink",
"interface": "swd",
"device": "STM32WB55RG",
- "svdFile": "./debug/STM32WB55_CM4.svd",
+ "svdFile": "./scripts/debug/STM32WB55_CM4.svd",
"rtos": "FreeRTOS",
"postAttachCommands": [
- "source debug/flipperversion.py",
+ "source scripts/debug/flipperversion.py",
"fw-version",
- "source debug/flipperapps.py",
+ "source scripts/debug/flipperapps.py",
"fap-set-debug-elf-root build/latest/.extapps",
]
// "showDevDebugOutput": "raw",
@@ -96,16 +95,16 @@
"type": "cortex-debug",
"servertype": "openocd",
"device": "cmsis-dap",
- "svdFile": "./debug/STM32WB55_CM4.svd",
+ "svdFile": "./scripts/debug/STM32WB55_CM4.svd",
"rtos": "FreeRTOS",
"configFiles": [
"interface/cmsis-dap.cfg",
- "./debug/stm32wbx.cfg",
+ "./scripts/debug/stm32wbx.cfg",
],
"postAttachCommands": [
- "source debug/flipperversion.py",
+ "source scripts/debug/flipperversion.py",
"fw-version",
- "source debug/flipperapps.py",
+ "source scripts/debug/flipperapps.py",
"fap-set-debug-elf-root build/latest/.extapps",
],
// "showDevDebugOutput": "raw",
diff --git a/debug/PyCortexMDebug/README.md b/debug/PyCortexMDebug/README.md
deleted file mode 100644
index 32c76e76..00000000
--- a/debug/PyCortexMDebug/README.md
+++ /dev/null
@@ -1,84 +0,0 @@
-PyCortexMDebug
-==============
-
-*A set of GDB/Python-based utilities to make life debugging ARM Cortex-M processors a bit easier*
-
-It will consist of several modules which will hopefully become integrated as they evolve. Presently, there is only one:
-
-## SVD
-ARM defines an SVD (System View Description) file format in its CMSIS
-standard as a means for Cortex-M-based chip manufacturers to provide a
-common description of peripherals, registers, and register fields. You
-can download SVD files for different manufacturers
-[here](http://www.arm.com/products/processors/cortex-m/cortex-microcontroller-software-interface-standard.php).
-
-My implementation so far has only tested STM32 chips but should hold for others. If others are like those from ST,
-expect plenty of errors in the file. Like GPIOA having a register named GPIOB_OSPEEDR and lots of 16-bit registers
-that are listed as 32!
-
-The implementation consists of two components -- An xml parser module (pysvd) and a GDB file (gdb_svd).
-I haven't yet worked out a perfect workflow for this, though it's quite easy to use when
-you already tend to have a GDB initialization file for starting up OpenOCD and the like.
-However your workflow works, just make sure to, in GDB:
-
- source gdb_svd.py
- svd_load [your_svd_file].svd
-
-These files can be huge so it might take a second or two. Anyways, after that, you can do
-
- svd
-
-to list available peripherals with descriptions. Or you can do
-
- svd [some_peripheral_name]
-
-to see all of the registers (with their values) for a given peripheral. For more details, run
-
- svd [some_peripheral_name] [some_register_name]
-
-to see all of the field values with descriptions.
-
-You can add format modifiers like:
-
-* `svd/x` will display values in hex
-* `svd/o` will display values in octal
-* `svd/t` or `svd/b` will display values in binary
-* `svd/a` will display values in hex and try to resolve symbols from the values
-
-All field values are displayed at the correct lengths as provided by the SVD files.
-Also, tab completion exists for nearly everything! When in doubt, run `svd help`.
-
-### TODO
-
-Enable writing to registers and individual fields
-
-### Bugs
-
-There are probably a few. All planning, writing, and testing of this was done in an afternoon. There may be
-some oddities in working with non-STM32 parts. I'll play with this when I start working with other
-controllers again. If something's giving you trouble, describe the problem and it shall be fixed.
-
-## DWT
-The ARM Data Watchpoint and Trace Unit (DWT) offers data watchpoints and a series of gated cycle counters. For now,
-I only support the raw cycle counter but facilities are in place to make use of others. As this is independent of the
-specific device under test, commands are simple and you can configure a clock speed to get real time values from
-counters.
-
- dwt configclk 48000000
-
-will set the current core clock speed. Then
-
- dwt cyccnt reset
- dwt cyccnt enable
-
-will reset and start the cycle counter. At any point
-
- dwt cycnt
-
-will then indicate the number of cycles and amount of time that has passed.
-
-## ITM/ETM support
-
-This is not implemented yet. I want to have more complete support for some of the nicer debug and trace features
-on Cortex-M processors. Parts of this will probably be dependent on OpenOCD and possibly on specific interfaces.
-I'll try to avoid this where possible but can't make any promises.
diff --git a/debug/PyCortexMDebug/cmdebug/dwt_gdb.py b/debug/PyCortexMDebug/cmdebug/dwt_gdb.py
deleted file mode 100755
index dd7ccd20..00000000
--- a/debug/PyCortexMDebug/cmdebug/dwt_gdb.py
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/env python
-"""
-This file is part of PyCortexMDebug
-
-PyCortexMDebug is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-PyCortexMDebug is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with PyCortexMDebug. If not, see .
-"""
-
-import gdb
-import struct
-
-DWT_CTRL = 0xE0001000
-DWT_CYCCNT = 0xE0001004
-DWT_CPICNT = 0xE0001008
-DWT_EXTCNT = 0xE000100C
-DWT_SLEEPCNT = 0xE0001010
-DWT_LSUCNT = 0xE0001014
-DWT_FOLDCNT = 0xE0001018
-DWT_PCSR = 0xE000101C
-
-prefix = "dwt : "
-
-
-class DWT(gdb.Command):
- clk = None
- is_init = False
-
- def __init__(self):
- gdb.Command.__init__(self, "dwt", gdb.COMMAND_DATA)
-
- @staticmethod
- def read(address, bits=32):
- """Read from memory (using print) and return an integer"""
- value = gdb.selected_inferior().read_memory(address, bits / 8)
- return struct.unpack_from(" 1:
- if s[1][:2] == "en":
- self.cyccnt_en()
- elif s[1][0] == "r":
- self.cyccnt_reset()
- elif s[1][0] == "d":
- self.cyccnt_dis()
- gdb.write(
- prefix
- + "CYCCNT ({}): ".format("ON" if (self.read(DWT_CTRL) & 1) else "OFF")
- + self.cycles_str(self.read(DWT_CYCCNT))
- )
- elif s[0] == "reset":
- if len(s) > 1:
- if s[1] == "cyccnt":
- self.cyccnt_reset()
- gdb.write(prefix + "CYCCNT reset\n")
- if s[1] == "counters":
- self.cyccnt_reset()
- gdb.write(prefix + "CYCCNT reset\n")
- else:
- self.cyccnt_reset()
- gdb.write(prefix + "CYCCNT reset\n")
- else:
- # Reset everything
- self.cyccnt_reset()
- gdb.write(prefix + "CYCCNT reset\n")
- elif s[0] == "configclk":
- if len(s) == 2:
- try:
- self.clk = float(s[1])
- except:
- self.print_help()
- else:
- self.print_help()
- else:
- # Try to figure out what stupid went on here
- gdb.write(args)
- self.print_help()
-
- @staticmethod
- def complete(text, word):
- text = str(text).lower()
- s = text.split(" ")
-
- commands = ["configclk", "reset", "cyccnt"]
- reset_commands = ["counters", "cyccnt"]
- cyccnt_commands = ["enable", "reset", "disable"]
-
- if len(s) == 1:
- return filter(lambda x: x.startswith(s[0]), commands)
-
- if len(s) == 2:
- if s[0] == "reset":
- return filter(lambda x: x.startswith(s[1]), reset_commands)
- if s[0] == "cyccnt":
- return filter(lambda x: x.startswith(s[1]), cyccnt_commands)
-
- def cycles_str(self, cycles):
- if self.clk:
- return "%d cycles, %.3es\n" % (cycles, cycles * 1.0 / self.clk)
- else:
- return "%d cycles"
-
- def cyccnt_en(self):
- self.write(DWT_CTRL, self.read(DWT_CTRL) | 1)
-
- def cyccnt_dis(self):
- self.write(DWT_CTRL, self.read(DWT_CTRL) & 0xFFFFFFFE)
-
- def cyccnt_reset(self, value=0):
- self.write(DWT_CYCCNT, value)
-
- def cpicnt_reset(self, value=0):
- self.write(DWT_CPICNT, value & 0xFF)
-
- @staticmethod
- def print_help():
- gdb.write("Usage:\n")
- gdb.write("=========\n")
- gdb.write("dwt:\n")
- gdb.write("\tList available peripherals\n")
- gdb.write("dwt configclk [Hz]:\n")
- gdb.write("\tSet clock for rendering time values in seconds\n")
- gdb.write("dwt reset:\n")
- gdb.write("\tReset everything in DWT\n")
- gdb.write("dwt reset counters:\n")
- gdb.write("\tReset all DWT counters\n")
- gdb.write("dwt cyccnt\n")
- gdb.write("\tDisplay the cycle count\n")
- gdb.write("\td(default):decimal, x: hex, o: octal, b: binary\n")
- return
-
-
-# Registers our class to GDB when sourced:
-DWT()
diff --git a/debug/PyCortexMDebug/cmdebug/x2d.py b/debug/PyCortexMDebug/cmdebug/x2d.py
deleted file mode 100644
index fc3f185d..00000000
--- a/debug/PyCortexMDebug/cmdebug/x2d.py
+++ /dev/null
@@ -1,586 +0,0 @@
-#!/usr/bin/env python
-"Makes working with XML feel like you are working with JSON"
-
-try:
- from defusedexpat import pyexpat as expat
-except ImportError:
- from xml.parsers import expat
-
-from xml.sax.saxutils import XMLGenerator
-from xml.sax.xmlreader import AttributesImpl
-
-try: # pragma no cover
- from cStringIO import StringIO
-except ImportError: # pragma no cover
- try:
- from StringIO import StringIO
- except ImportError:
- from io import StringIO
-
-from inspect import isgenerator
-
-
-class ObjectDict(dict):
- def __getattr__(self, name):
- if name in self:
- return self[name]
- else:
- raise AttributeError("No such attribute: " + name)
-
-
-try: # pragma no cover
- _basestring = basestring
-except NameError: # pragma no cover
- _basestring = str
-try: # pragma no cover
- _unicode = unicode
-except NameError: # pragma no cover
- _unicode = str
-
-__author__ = "Martin Blech"
-__version__ = "0.12.0"
-__license__ = "MIT"
-
-
-class ParsingInterrupted(Exception):
- pass
-
-
-class _DictSAXHandler(object):
- def __init__(
- self,
- item_depth=0,
- item_callback=lambda *args: True,
- xml_attribs=True,
- attr_prefix="@",
- cdata_key="#text",
- force_cdata=False,
- cdata_separator="",
- postprocessor=None,
- dict_constructor=ObjectDict,
- strip_whitespace=True,
- namespace_separator=":",
- namespaces=None,
- force_list=None,
- comment_key="#comment",
- ):
- self.path = []
- self.stack = []
- self.data = []
- self.item = None
- self.item_depth = item_depth
- self.xml_attribs = xml_attribs
- self.item_callback = item_callback
- self.attr_prefix = attr_prefix
- self.cdata_key = cdata_key
- self.force_cdata = force_cdata
- self.cdata_separator = cdata_separator
- self.postprocessor = postprocessor
- self.dict_constructor = dict_constructor
- self.strip_whitespace = strip_whitespace
- self.namespace_separator = namespace_separator
- self.namespaces = namespaces
- self.namespace_declarations = ObjectDict()
- self.force_list = force_list
- self.comment_key = comment_key
-
- def _build_name(self, full_name):
- if self.namespaces is None:
- return full_name
- i = full_name.rfind(self.namespace_separator)
- if i == -1:
- return full_name
- namespace, name = full_name[:i], full_name[i + 1 :]
- try:
- short_namespace = self.namespaces[namespace]
- except KeyError:
- short_namespace = namespace
- if not short_namespace:
- return name
- else:
- return self.namespace_separator.join((short_namespace, name))
-
- def _attrs_to_dict(self, attrs):
- if isinstance(attrs, dict):
- return attrs
- return self.dict_constructor(zip(attrs[0::2], attrs[1::2]))
-
- def startNamespaceDecl(self, prefix, uri):
- self.namespace_declarations[prefix or ""] = uri
-
- def startElement(self, full_name, attrs):
- name = self._build_name(full_name)
- attrs = self._attrs_to_dict(attrs)
- if attrs and self.namespace_declarations:
- attrs["xmlns"] = self.namespace_declarations
- self.namespace_declarations = ObjectDict()
- self.path.append((name, attrs or None))
- if len(self.path) > self.item_depth:
- self.stack.append((self.item, self.data))
- if self.xml_attribs:
- attr_entries = []
- for key, value in attrs.items():
- key = self.attr_prefix + self._build_name(key)
- if self.postprocessor:
- entry = self.postprocessor(self.path, key, value)
- else:
- entry = (key, value)
- if entry:
- attr_entries.append(entry)
- attrs = self.dict_constructor(attr_entries)
- else:
- attrs = None
- self.item = attrs or None
- self.data = []
-
- def endElement(self, full_name):
- name = self._build_name(full_name)
- if len(self.path) == self.item_depth:
- item = self.item
- if item is None:
- item = None if not self.data else self.cdata_separator.join(self.data)
-
- should_continue = self.item_callback(self.path, item)
- if not should_continue:
- raise ParsingInterrupted()
- if len(self.stack):
- data = None if not self.data else self.cdata_separator.join(self.data)
- item = self.item
- self.item, self.data = self.stack.pop()
- if self.strip_whitespace and data:
- data = data.strip() or None
- if data and self.force_cdata and item is None:
- item = self.dict_constructor()
- if item is not None:
- if data:
- self.push_data(item, self.cdata_key, data)
- self.item = self.push_data(self.item, name, item)
- else:
- self.item = self.push_data(self.item, name, data)
- else:
- self.item = None
- self.data = []
- self.path.pop()
-
- def characters(self, data):
- if not self.data:
- self.data = [data]
- else:
- self.data.append(data)
-
- def comments(self, data):
- if self.strip_whitespace:
- data = data.strip()
- self.item = self.push_data(self.item, self.comment_key, data)
-
- def push_data(self, item, key, data):
- if self.postprocessor is not None:
- result = self.postprocessor(self.path, key, data)
- if result is None:
- return item
- key, data = result
- if item is None:
- item = self.dict_constructor()
- try:
- value = item[key]
- if isinstance(value, list):
- value.append(data)
- else:
- item[key] = [value, data]
- except KeyError:
- if self._should_force_list(key, data):
- item[key] = [data]
- else:
- item[key] = data
- return item
-
- def _should_force_list(self, key, value):
- if not self.force_list:
- return False
- if isinstance(self.force_list, bool):
- return self.force_list
- try:
- return key in self.force_list
- except TypeError:
- return self.force_list(self.path[:-1], key, value)
-
-
-def parse(
- xml_input,
- encoding=None,
- expat=expat,
- process_namespaces=False,
- namespace_separator=":",
- disable_entities=True,
- process_comments=False,
- **kwargs
-):
- """Parse the given XML input and convert it into a dictionary.
-
- `xml_input` can either be a `string`, a file-like object, or a generator of strings.
-
- If `xml_attribs` is `True`, element attributes are put in the dictionary
- among regular child elements, using `@` as a prefix to avoid collisions. If
- set to `False`, they are just ignored.
-
- Simple example::
-
- >>> import xmltodict
- >>> doc = xmltodict.parse(\"\"\"
- ...
- ... 1
- ... 2
- ...
- ... \"\"\")
- >>> doc['a']['@prop']
- u'x'
- >>> doc['a']['b']
- [u'1', u'2']
-
- If `item_depth` is `0`, the function returns a dictionary for the root
- element (default behavior). Otherwise, it calls `item_callback` every time
- an item at the specified depth is found and returns `None` in the end
- (streaming mode).
-
- The callback function receives two parameters: the `path` from the document
- root to the item (name-attribs pairs), and the `item` (dict). If the
- callback's return value is false-ish, parsing will be stopped with the
- :class:`ParsingInterrupted` exception.
-
- Streaming example::
-
- >>> def handle(path, item):
- ... print('path:%s item:%s' % (path, item))
- ... return True
- ...
- >>> xmltodict.parse(\"\"\"
- ...
- ... 1
- ... 2
- ... \"\"\", item_depth=2, item_callback=handle)
- path:[(u'a', {u'prop': u'x'}), (u'b', None)] item:1
- path:[(u'a', {u'prop': u'x'}), (u'b', None)] item:2
-
- The optional argument `postprocessor` is a function that takes `path`,
- `key` and `value` as positional arguments and returns a new `(key, value)`
- pair where both `key` and `value` may have changed. Usage example::
-
- >>> def postprocessor(path, key, value):
- ... try:
- ... return key + ':int', int(value)
- ... except (ValueError, TypeError):
- ... return key, value
- >>> xmltodict.parse('12x',
- ... postprocessor=postprocessor)
- ObjectDict([(u'a', ObjectDict([(u'b:int', [1, 2]), (u'b', u'x')]))])
-
- You can pass an alternate version of `expat` (such as `defusedexpat`) by
- using the `expat` parameter. E.g:
-
- >>> import defusedexpat
- >>> xmltodict.parse('hello', expat=defusedexpat.pyexpat)
- ObjectDict([(u'a', u'hello')])
-
- You can use the force_list argument to force lists to be created even
- when there is only a single child of a given level of hierarchy. The
- force_list argument is a tuple of keys. If the key for a given level
- of hierarchy is in the force_list argument, that level of hierarchy
- will have a list as a child (even if there is only one sub-element).
- The index_keys operation takes precedence over this. This is applied
- after any user-supplied postprocessor has already run.
-
- For example, given this input:
-
-
- host1
- Linux
-
-
- em0
- 10.0.0.1
-
-
-
-
-
- If called with force_list=('interface',), it will produce
- this dictionary:
- {'servers':
- {'server':
- {'name': 'host1',
- 'os': 'Linux'},
- 'interfaces':
- {'interface':
- [ {'name': 'em0', 'ip_address': '10.0.0.1' } ] } } }
-
- `force_list` can also be a callable that receives `path`, `key` and
- `value`. This is helpful in cases where the logic that decides whether
- a list should be forced is more complex.
-
-
- If `process_comment` is `True` then comment will be added with comment_key
- (default=`'#comment'`) to then tag which contains comment
-
- For example, given this input:
-
-
-
-
-
- 1
-
- 2
-
-
-
- If called with process_comment=True, it will produce
- this dictionary:
- 'a': {
- 'b': {
- '#comment': 'b comment',
- 'c': {
-
- '#comment': 'c comment',
- '#text': '1',
- },
- 'd': '2',
- },
- }
- """
- handler = _DictSAXHandler(namespace_separator=namespace_separator, **kwargs)
- if isinstance(xml_input, _unicode):
- if not encoding:
- encoding = "utf-8"
- xml_input = xml_input.encode(encoding)
- if not process_namespaces:
- namespace_separator = None
- parser = expat.ParserCreate(encoding, namespace_separator)
- try:
- parser.ordered_attributes = True
- except AttributeError:
- # Jython's expat does not support ordered_attributes
- pass
- parser.StartNamespaceDeclHandler = handler.startNamespaceDecl
- parser.StartElementHandler = handler.startElement
- parser.EndElementHandler = handler.endElement
- parser.CharacterDataHandler = handler.characters
- if process_comments:
- parser.CommentHandler = handler.comments
- parser.buffer_text = True
- if disable_entities:
- try:
- # Attempt to disable DTD in Jython's expat parser (Xerces-J).
- feature = "http://apache.org/xml/features/disallow-doctype-decl"
- parser._reader.setFeature(feature, True)
- except AttributeError:
- # For CPython / expat parser.
- # Anything not handled ends up here and entities aren't expanded.
- parser.DefaultHandler = lambda x: None
- # Expects an integer return; zero means failure -> expat.ExpatError.
- parser.ExternalEntityRefHandler = lambda *x: 1
- if hasattr(xml_input, "read"):
- parser.ParseFile(xml_input)
- elif isgenerator(xml_input):
- for chunk in xml_input:
- parser.Parse(chunk, False)
- parser.Parse(b"", True)
- else:
- parser.Parse(xml_input, True)
- return handler.item
-
-
-def _process_namespace(name, namespaces, ns_sep=":", attr_prefix="@"):
- if not namespaces:
- return name
- try:
- ns, name = name.rsplit(ns_sep, 1)
- except ValueError:
- pass
- else:
- ns_res = namespaces.get(ns.strip(attr_prefix))
- name = (
- "{}{}{}{}".format(
- attr_prefix if ns.startswith(attr_prefix) else "", ns_res, ns_sep, name
- )
- if ns_res
- else name
- )
- return name
-
-
-def _emit(
- key,
- value,
- content_handler,
- attr_prefix="@",
- cdata_key="#text",
- depth=0,
- preprocessor=None,
- pretty=False,
- newl="\n",
- indent="\t",
- namespace_separator=":",
- namespaces=None,
- full_document=True,
- expand_iter=None,
-):
- key = _process_namespace(key, namespaces, namespace_separator, attr_prefix)
- if preprocessor is not None:
- result = preprocessor(key, value)
- if result is None:
- return
- key, value = result
- if (
- not hasattr(value, "__iter__")
- or isinstance(value, _basestring)
- or isinstance(value, dict)
- ):
- value = [value]
- for index, v in enumerate(value):
- if full_document and depth == 0 and index > 0:
- raise ValueError("document with multiple roots")
- if v is None:
- v = ObjectDict()
- elif isinstance(v, bool):
- if v:
- v = _unicode("true")
- else:
- v = _unicode("false")
- elif not isinstance(v, dict):
- if (
- expand_iter
- and hasattr(v, "__iter__")
- and not isinstance(v, _basestring)
- ):
- v = ObjectDict(((expand_iter, v),))
- else:
- v = _unicode(v)
- if isinstance(v, _basestring):
- v = ObjectDict(((cdata_key, v),))
- cdata = None
- attrs = ObjectDict()
- children = []
- for ik, iv in v.items():
- if ik == cdata_key:
- cdata = iv
- continue
- if ik.startswith(attr_prefix):
- ik = _process_namespace(
- ik, namespaces, namespace_separator, attr_prefix
- )
- if ik == "@xmlns" and isinstance(iv, dict):
- for k, v in iv.items():
- attr = "xmlns{}".format(":{}".format(k) if k else "")
- attrs[attr] = _unicode(v)
- continue
- if not isinstance(iv, _unicode):
- iv = _unicode(iv)
- attrs[ik[len(attr_prefix) :]] = iv
- continue
- children.append((ik, iv))
- if pretty:
- content_handler.ignorableWhitespace(depth * indent)
- content_handler.startElement(key, AttributesImpl(attrs))
- if pretty and children:
- content_handler.ignorableWhitespace(newl)
- for child_key, child_value in children:
- _emit(
- child_key,
- child_value,
- content_handler,
- attr_prefix,
- cdata_key,
- depth + 1,
- preprocessor,
- pretty,
- newl,
- indent,
- namespaces=namespaces,
- namespace_separator=namespace_separator,
- expand_iter=expand_iter,
- )
- if cdata is not None:
- content_handler.characters(cdata)
- if pretty and children:
- content_handler.ignorableWhitespace(depth * indent)
- content_handler.endElement(key)
- if pretty and depth:
- content_handler.ignorableWhitespace(newl)
-
-
-def unparse(
- input_dict,
- output=None,
- encoding="utf-8",
- full_document=True,
- short_empty_elements=False,
- **kwargs
-):
- """Emit an XML document for the given `input_dict` (reverse of `parse`).
-
- The resulting XML document is returned as a string, but if `output` (a
- file-like object) is specified, it is written there instead.
-
- Dictionary keys prefixed with `attr_prefix` (default=`'@'`) are interpreted
- as XML node attributes, whereas keys equal to `cdata_key`
- (default=`'#text'`) are treated as character data.
-
- The `pretty` parameter (default=`False`) enables pretty-printing. In this
- mode, lines are terminated with `'\n'` and indented with `'\t'`, but this
- can be customized with the `newl` and `indent` parameters.
-
- """
- if full_document and len(input_dict) != 1:
- raise ValueError("Document must have exactly one root.")
- must_return = False
- if output is None:
- output = StringIO()
- must_return = True
- if short_empty_elements:
- content_handler = XMLGenerator(output, encoding, True)
- else:
- content_handler = XMLGenerator(output, encoding)
- if full_document:
- content_handler.startDocument()
- for key, value in input_dict.items():
- _emit(key, value, content_handler, full_document=full_document, **kwargs)
- if full_document:
- content_handler.endDocument()
- if must_return:
- value = output.getvalue()
- try: # pragma no cover
- value = value.decode(encoding)
- except AttributeError: # pragma no cover
- pass
- return value
-
-
-if __name__ == "__main__": # pragma: no cover
- import sys
- import marshal
-
- try:
- stdin = sys.stdin.buffer
- stdout = sys.stdout.buffer
- except AttributeError:
- stdin = sys.stdin
- stdout = sys.stdout
-
- (item_depth,) = sys.argv[1:]
- item_depth = int(item_depth)
-
- def handle_item(path, item):
- marshal.dump((path, item), stdout)
- return True
-
- try:
- root = parse(
- stdin,
- item_depth=item_depth,
- item_callback=handle_item,
- dict_constructor=dict,
- )
- if item_depth == 0:
- handle_item([], root)
- except KeyboardInterrupt:
- pass
diff --git a/debug/FreeRTOS/FreeRTOS.py b/scripts/debug/FreeRTOS/FreeRTOS.py
similarity index 99%
rename from debug/FreeRTOS/FreeRTOS.py
rename to scripts/debug/FreeRTOS/FreeRTOS.py
index 036e18f3..0eb7e5f8 100644
--- a/debug/FreeRTOS/FreeRTOS.py
+++ b/scripts/debug/FreeRTOS/FreeRTOS.py
@@ -29,7 +29,6 @@ from FreeRTOSgdb.GDBCommands import ShowQueueInfo
class Scheduler:
def __init__(self):
-
self._blocked = ListInspector("xSuspendedTaskList")
self._delayed1 = ListInspector("xDelayedTaskList1")
self._delayed2 = ListInspector("xDelayedTaskList2")
diff --git a/debug/FreeRTOS/FreeRTOSgdb/EventGroup.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/EventGroup.py
similarity index 100%
rename from debug/FreeRTOS/FreeRTOSgdb/EventGroup.py
rename to scripts/debug/FreeRTOS/FreeRTOSgdb/EventGroup.py
diff --git a/debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py
similarity index 99%
rename from debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py
rename to scripts/debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py
index ba811e3e..5564502e 100644
--- a/debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py
+++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py
@@ -61,7 +61,6 @@ class ShowQueueInfo(gdb.Command):
if maxCount == 0:
print(outputFmt % (q.GetName(), q.GetQueueMessagesWaiting(), "", ""))
else:
-
for i in range(0, maxCount):
txName = ""
if i < len(sendList):
diff --git a/debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py
similarity index 99%
rename from debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py
rename to scripts/debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py
index 1682c917..c1345701 100644
--- a/debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py
+++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py
@@ -48,7 +48,6 @@ class HandleRegistry:
print("%d: %3s %16s" % (i, h, name))
def FilterBy(self, qMode):
-
"""Retrieve a List of Mutex Queue Handles"""
resp = []
for i in range(self._minIndex, self._maxIndex):
diff --git a/debug/FreeRTOS/FreeRTOSgdb/List.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/List.py
similarity index 99%
rename from debug/FreeRTOS/FreeRTOSgdb/List.py
rename to scripts/debug/FreeRTOS/FreeRTOSgdb/List.py
index 62aa9dc9..575bdc52 100644
--- a/debug/FreeRTOS/FreeRTOSgdb/List.py
+++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/List.py
@@ -56,7 +56,6 @@ class ListInspector:
of some of the TCB Task lists.
"""
if self._list != None:
-
CastType = None
if CastTypeStr != None:
if type(CastTypeStr) == str:
@@ -73,7 +72,6 @@ class ListInspector:
index = self._list["pxIndex"]
if numElems > 0 and numElems < 200:
-
if startElem == 0:
curr = index
else:
diff --git a/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py
similarity index 99%
rename from debug/FreeRTOS/FreeRTOSgdb/QueueTools.py
rename to scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py
index 49a780db..a35f0894 100644
--- a/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py
+++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py
@@ -47,7 +47,6 @@ QueueMode.Map = QueueMap
class QueueInspector:
-
QueueType = gdb.lookup_type("Queue_t")
def __init__(self, handle):
diff --git a/debug/FreeRTOS/FreeRTOSgdb/Task.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/Task.py
similarity index 99%
rename from debug/FreeRTOS/FreeRTOSgdb/Task.py
rename to scripts/debug/FreeRTOS/FreeRTOSgdb/Task.py
index 04da3bbc..d3078fdc 100644
--- a/debug/FreeRTOS/FreeRTOSgdb/Task.py
+++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/Task.py
@@ -11,7 +11,6 @@ import gdb
class TaskInspector:
-
TCBType = gdb.lookup_type("TCB_t")
def __init__(self, handle):
diff --git a/debug/FreeRTOS/FreeRTOSgdb/Types.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/Types.py
similarity index 100%
rename from debug/FreeRTOS/FreeRTOSgdb/Types.py
rename to scripts/debug/FreeRTOS/FreeRTOSgdb/Types.py
diff --git a/debug/FreeRTOS/FreeRTOSgdb/__init__.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/__init__.py
similarity index 100%
rename from debug/FreeRTOS/FreeRTOSgdb/__init__.py
rename to scripts/debug/FreeRTOS/FreeRTOSgdb/__init__.py
diff --git a/debug/FreeRTOS/LICENSE b/scripts/debug/FreeRTOS/LICENSE
similarity index 100%
rename from debug/FreeRTOS/LICENSE
rename to scripts/debug/FreeRTOS/LICENSE
diff --git a/debug/FreeRTOS/README.md b/scripts/debug/FreeRTOS/README.md
similarity index 100%
rename from debug/FreeRTOS/README.md
rename to scripts/debug/FreeRTOS/README.md
diff --git a/debug/PyCortexMDebug/LICENSE b/scripts/debug/PyCortexMDebug/LICENSE
similarity index 100%
rename from debug/PyCortexMDebug/LICENSE
rename to scripts/debug/PyCortexMDebug/LICENSE
diff --git a/debug/PyCortexMDebug/PyCortexMDebug.py b/scripts/debug/PyCortexMDebug/PyCortexMDebug.py
similarity index 96%
rename from debug/PyCortexMDebug/PyCortexMDebug.py
rename to scripts/debug/PyCortexMDebug/PyCortexMDebug.py
index 6533535c..fd322b5a 100644
--- a/debug/PyCortexMDebug/PyCortexMDebug.py
+++ b/scripts/debug/PyCortexMDebug/PyCortexMDebug.py
@@ -28,7 +28,5 @@ directory = path.abspath(directory)
sys.path.append(directory)
from cmdebug.svd_gdb import LoadSVD
-from cmdebug.dwt_gdb import DWT
-DWT()
LoadSVD()
diff --git a/scripts/debug/PyCortexMDebug/README.md b/scripts/debug/PyCortexMDebug/README.md
new file mode 100644
index 00000000..0a5764b0
--- /dev/null
+++ b/scripts/debug/PyCortexMDebug/README.md
@@ -0,0 +1,35 @@
+PyCortexMDebug
+==============
+
+## SVD
+
+ARM defines an SVD (System View Description) file format in its CMSIS standard as a means for Cortex-M-based chip manufacturers to provide a common description of peripherals, registers, and register fields. You can download SVD files for different manufacturers [here](http://www.arm.com/products/processors/cortex-m/cortex-microcontroller-software-interface-standard.php).
+
+The implementation consists of two components -- An lxml-based parser module (pysvd) and a GDB file (gdb_svd). I haven't yet worked out a perfect workflow for this, though it's quite easy to use when you already tend to have a GDB initialization file for starting up OpenOCD and the like. However your workflow works, just make sure to, in GDB:
+
+ source gdb_svd.py
+ svd_load [your_svd_file].svd
+
+These files can be huge so it might take a second or two. Anyways, after that, you can do
+
+ svd
+
+to list available peripherals with descriptions. Or you can do
+
+ svd [some_peripheral_name]
+
+to see all of the registers (with their values) for a given peripheral. For more details, run
+
+ svd [some_peripheral_name] [some_register_name]
+
+to see all of the field values with descriptions.
+
+You can add format modifiers like:
+
+* `svd/x` will display values in hex
+* `svd/o` will display values in octal
+* `svd/t` or `svd/b` will display values in binary
+* `svd/a` will display values in hex and try to resolve symbols from the values
+
+All field values are displayed at the correct lengths as provided by the SVD files.
+Also, tab completion exists for nearly everything! When in doubt, run `svd help`.
diff --git a/debug/PyCortexMDebug/cmdebug/__init__.py b/scripts/debug/PyCortexMDebug/cmdebug/__init__.py
similarity index 100%
rename from debug/PyCortexMDebug/cmdebug/__init__.py
rename to scripts/debug/PyCortexMDebug/cmdebug/__init__.py
diff --git a/debug/PyCortexMDebug/cmdebug/svd.py b/scripts/debug/PyCortexMDebug/cmdebug/svd.py
similarity index 89%
rename from debug/PyCortexMDebug/cmdebug/svd.py
rename to scripts/debug/PyCortexMDebug/cmdebug/svd.py
index f4a884bb..a25e69bf 100755
--- a/debug/PyCortexMDebug/cmdebug/svd.py
+++ b/scripts/debug/PyCortexMDebug/cmdebug/svd.py
@@ -16,15 +16,14 @@ You should have received a copy of the GNU General Public License
along with PyCortexMDebug. If not, see .
"""
-from collections import OrderedDict
-from . import x2d
-
-import traceback
-import warnings
-import pickle
+import lxml.objectify as objectify
import sys
+from collections import OrderedDict
import os
+import pickle
+import traceback
import re
+import warnings
class SmartDict:
@@ -127,31 +126,26 @@ class SVDFile:
def __init__(self, fname):
"""
+
Args:
fname: Filename for the SVD file
"""
+ f = objectify.parse(os.path.expanduser(fname))
+ root = f.getroot()
+ periph = root.peripherals.getchildren()
self.peripherals = SmartDict()
self.base_address = 0
- xml_file_name = os.path.expanduser(fname)
- pickle_file_name = xml_file_name + ".pickle"
- root = None
- if os.path.exists(pickle_file_name):
- print("Loading pickled SVD")
- root = pickle.load(open(pickle_file_name, "rb"))
- else:
- print("Loading XML SVD and pickling it")
- root = x2d.parse(open(xml_file_name, "rb"))
- pickle.dump(root, open(pickle_file_name, "wb"), pickle.HIGHEST_PROTOCOL)
- print("Processing SVD tree")
# XML elements
- for p in root["device"]["peripherals"]["peripheral"]:
+ for p in periph:
try:
- self.peripherals[p["name"]] = SVDPeripheral(p, self)
+ if p.tag == "peripheral":
+ self.peripherals[str(p.name)] = SVDPeripheral(p, self)
+ else:
+ # This is some other tag
+ pass
except SVDNonFatalError as e:
- # print(e)
- pass
- print("SVD Ready")
+ print(e)
def add_register(parent, node):
@@ -271,11 +265,11 @@ class SVDPeripheral:
self.parent_base_address = parent.base_address
# Look for a base address, as it is required
- if "baseAddress" not in svd_elem:
+ if not hasattr(svd_elem, "baseAddress"):
raise SVDNonFatalError("Periph without base address")
self.base_address = int(str(svd_elem.baseAddress), 0)
- if "@derivedFrom" in svd_elem:
- derived_from = svd_elem["@derivedFrom"]
+ if "derivedFrom" in svd_elem.attrib:
+ derived_from = svd_elem.attrib["derivedFrom"]
try:
self.name = str(svd_elem.name)
except AttributeError:
@@ -301,14 +295,16 @@ class SVDPeripheral:
self.clusters = SmartDict()
if hasattr(svd_elem, "registers"):
- if "register" in svd_elem.registers:
- for r in svd_elem.registers.register:
- if isinstance(r, x2d.ObjectDict):
- add_register(self, r)
- if "cluster" in svd_elem.registers:
- for c in svd_elem.registers.cluster:
- if isinstance(c, x2d.ObjectDict):
- add_cluster(self, c)
+ registers = [
+ r
+ for r in svd_elem.registers.getchildren()
+ if r.tag in ["cluster", "register"]
+ ]
+ for r in registers:
+ if r.tag == "cluster":
+ add_cluster(self, r)
+ elif r.tag == "register":
+ add_register(self, r)
def refactor_parent(self, parent):
self.parent_base_address = parent.base_address
@@ -342,11 +338,11 @@ class SVDPeripheralRegister:
else:
self.size = 0x20
self.fields = SmartDict()
- if "fields" in svd_elem:
+ if hasattr(svd_elem, "fields"):
# Filter fields to only consider those of tag "field"
- for f in svd_elem.fields.field:
- if isinstance(f, x2d.ObjectDict):
- self.fields[str(f.name)] = SVDPeripheralRegisterField(f, self)
+ fields = [f for f in svd_elem.fields.getchildren() if f.tag == "field"]
+ for f in fields:
+ self.fields[str(f.name)] = SVDPeripheralRegisterField(f, self)
def refactor_parent(self, parent):
self.parent_base_address = parent.base_address
diff --git a/debug/PyCortexMDebug/cmdebug/svd_gdb.py b/scripts/debug/PyCortexMDebug/cmdebug/svd_gdb.py
similarity index 100%
rename from debug/PyCortexMDebug/cmdebug/svd_gdb.py
rename to scripts/debug/PyCortexMDebug/cmdebug/svd_gdb.py
diff --git a/debug/STM32WB55_CM4.svd b/scripts/debug/STM32WB55_CM4.svd
similarity index 100%
rename from debug/STM32WB55_CM4.svd
rename to scripts/debug/STM32WB55_CM4.svd
diff --git a/debug/flipperapps.py b/scripts/debug/flipperapps.py
similarity index 100%
rename from debug/flipperapps.py
rename to scripts/debug/flipperapps.py
diff --git a/debug/flipperversion.py b/scripts/debug/flipperversion.py
similarity index 100%
rename from debug/flipperversion.py
rename to scripts/debug/flipperversion.py
diff --git a/debug/fw.jflash b/scripts/debug/fw.jflash
similarity index 100%
rename from debug/fw.jflash
rename to scripts/debug/fw.jflash
diff --git a/debug/gdbinit b/scripts/debug/gdbinit
similarity index 100%
rename from debug/gdbinit
rename to scripts/debug/gdbinit
diff --git a/debug/stm32wbx.cfg b/scripts/debug/stm32wbx.cfg
similarity index 100%
rename from debug/stm32wbx.cfg
rename to scripts/debug/stm32wbx.cfg
diff --git a/scripts/fbt_tools/fbt_debugopts.py b/scripts/fbt_tools/fbt_debugopts.py
index 58e73e9c..d46ecd8f 100644
--- a/scripts/fbt_tools/fbt_debugopts.py
+++ b/scripts/fbt_tools/fbt_debugopts.py
@@ -18,7 +18,7 @@ def GetDevices(env):
def generate(env, **kw):
env.AddMethod(GetDevices)
env.SetDefault(
- FBT_DEBUG_DIR="${ROOT_DIR}/debug",
+ FBT_DEBUG_DIR="${FBT_SCRIPT_DIR}/debug",
)
if (adapter_serial := env.subst("$OPENOCD_ADAPTER_SERIAL")) != "auto":
diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py
index 1657feab..d2d1d2f4 100644
--- a/scripts/sconsdist.py
+++ b/scripts/sconsdist.py
@@ -170,7 +170,6 @@ class Main(App):
"update.dir",
"sdk_headers.dir",
"lib.dir",
- "debug.dir",
"scripts.dir",
)
diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct
index 3f623ebc..4dd1fb5b 100644
--- a/scripts/ufbt/SConstruct
+++ b/scripts/ufbt/SConstruct
@@ -186,6 +186,33 @@ dist_env.PhonyTarget(
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(dist_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
)
+# Debug alien elf
+debug_other_opts = [
+ "-ex",
+ "source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py",
+ "-ex",
+ "source ${FBT_DEBUG_DIR}/flipperversion.py",
+ "-ex",
+ "fw-version",
+]
+
+dist_env.PhonyTarget(
+ "debug_other",
+ "${GDBPYCOM}",
+ GDBOPTS="${GDBOPTS_BASE}",
+ GDBREMOTE="${OPENOCD_GDB_PIPE}",
+ GDBPYOPTS=debug_other_opts,
+)
+
+dist_env.PhonyTarget(
+ "debug_other_blackmagic",
+ "${GDBPYCOM}",
+ GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
+ GDBREMOTE="${BLACKMAGIC_ADDR}",
+ GDBPYOPTS=debug_other_opts,
+)
+
+
dist_env.PhonyTarget(
"flash_blackmagic",
"$GDB $GDBOPTS $SOURCES $GDBFLASH",
diff --git a/scripts/ufbt/site_tools/ufbt_state.py b/scripts/ufbt/site_tools/ufbt_state.py
index 47f4afec..0038b66a 100644
--- a/scripts/ufbt/site_tools/ufbt_state.py
+++ b/scripts/ufbt/site_tools/ufbt_state.py
@@ -78,10 +78,8 @@ def generate(env, **kw):
env.SetDefault(
# Paths
SDK_DEFINITION=env.File(sdk_data["sdk_symbols"]),
- FBT_DEBUG_DIR=pathlib.Path(
- sdk_current_sdk_dir_node.Dir(sdk_components["debug.dir"]).abspath
- ).as_posix(),
FBT_SCRIPT_DIR=scripts_dir,
+ FBT_DEBUG_DIR=scripts_dir.Dir("debug"),
LIBPATH=sdk_current_sdk_dir_node.Dir(sdk_components["lib.dir"]),
FW_ELF=sdk_current_sdk_dir_node.File(sdk_components["firmware.elf"]),
FW_BIN=sdk_current_sdk_dir_node.File(sdk_components["full.bin"]),