Skip to content

Commit

Permalink
allow adding custom spec files as cli parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
yconst committed Jan 6, 2024
1 parent 2504b0b commit e95bacb
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 57 deletions.
3 changes: 1 addition & 2 deletions studio/Python/tests/test_dfu.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
from tinymovr import init_tee, destroy_tee
from tinymovr.config import (
get_bus_config,
create_device,
definitions
create_device
)

import unittest
Expand Down
12 changes: 10 additions & 2 deletions studio/Python/tinymovr/cli.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
"""Tinymovr Studio CLI
Usage:
tinymovr_cli [--bus=<bus>] [--chan=<chan>] [--bitrate=<bitrate>]
tinymovr_cli [--bus=<bus>] [--chan=<chan>] [--spec=<spec>] [--bitrate=<bitrate>]
tinymovr_cli -h | --help
tinymovr_cli --version
Options:
--bus=<bus> One or more interfaces to use, first available is used [default: canine,slcan_disco].
--chan=<chan> The bus device "channel".
--spec=<spec> A custom device spec to be added to the list of discoverable spec.
--bitrate=<bitrate> CAN bitrate [default: 1000000].
"""

import yaml
import can
import pkg_resources
import IPython
Expand All @@ -20,7 +22,7 @@
from tinymovr import init_tee, destroy_tee
from tinymovr.discovery import Discovery
from tinymovr.constants import app_name
from tinymovr.config import get_bus_config, configure_logging
from tinymovr.config import get_bus_config, configure_logging, add_spec

"""
Tinymovr CLI Module
Expand Down Expand Up @@ -49,6 +51,12 @@ def spawn():

logger = configure_logging()

spec_file = arguments["--spec"]
if spec_file:
with open(spec_file, 'r') as file:
spec_data = yaml.safe_load(file)
add_spec(spec_data, logger)

buses = arguments["--bus"].rsplit(sep=",")
channel = arguments["--chan"]
bitrate = int(arguments["--bitrate"])
Expand Down
3 changes: 1 addition & 2 deletions studio/Python/tinymovr/config/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from tinymovr.config.config import (
get_bus_config,
configure_logging,
definitions,
create_device,
create_device_with_hash_msg,
ProtocolVersionError,
add_spec,
)
82 changes: 38 additions & 44 deletions studio/Python/tinymovr/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,30 @@
from tinymovr.codec import DataType
from tinymovr.channel import CANChannel

definitions = {"hash_uint32": {}, "name": {}}

for yaml_file in Path(files("tinymovr").joinpath("specs/")).glob("*.yaml"):
with open(str(yaml_file)) as def_raw:
definition = yaml.safe_load(def_raw)
tmp_node = deserialize(definition)
definitions["hash_uint32"][tmp_node.hash_uint32] = definition
definitions["name"][definition["name"]] = definition


class ProtocolVersionError(Exception):
def __init__(self, dev_id, version_str, *args, **kwargs):
self.dev_id = dev_id
self.version_str = cleanup_incomplete_version(version_str)
msg = (
"Incompatible protocol versions (hash mismatch) for device {}. "
"Firmware is compatible with Studio version {}.\n\n"
"Either upgrade studio and firmware, or install a compatible Studio version like so:\n\n"
"pip3 uninstall tinymovr\npip3 install tinymovr=={}".format(
self.dev_id, self.version_str, self.version_str
)
)
super().__init__(msg, *args, **kwargs)
specs = {"hash_uint32": {}}


def init_specs_dict():
global specs
for yaml_file in Path(files("tinymovr").joinpath("specs/")).glob("*.yaml"):
with open(str(yaml_file)) as def_raw:
spec = yaml.safe_load(def_raw)
add_spec(spec)


def add_spec(spec, logger=None):
if logger is None:
logger = logging.getLogger("tinymovr")

tmp_node = deserialize(spec)
hash_value = tmp_node.hash_uint32
if hash_value in specs["hash_uint32"]:
logger.warning("Provided spec with hash {} already exists in hash/name dictionary".format(hash_value))
else:
specs["hash_uint32"][hash_value] = spec


init_specs_dict()


def get_bus_config(suggested_types=None):
Expand All @@ -70,24 +71,22 @@ def create_device(node_id):
"""
chan = CANChannel(node_id)

# Temporarily using a default definition to get the protocol_hash
# This assumes that `protocol_hash` is standard across different definitions
# Get the first definition as a temp
tmp_definition = list(definitions["hash_uint32"].values())[0]
node = deserialize(tmp_definition)
# Temporarily using a default spec to get the protocol_hash
# This assumes that `protocol_hash` is standard across different specs
# Get the first spec as a temp
tmp_spec = list(specs["hash_uint32"].values())[0]
node = deserialize(tmp_spec)
node._channel = chan

# Check for the correct definition using the remote hash
# Check for the correct spec using the remote hash
protocol_hash = node.protocol_hash
device_definition = definitions["hash_uint32"].get(protocol_hash)
device_spec = specs["hash_uint32"].get(protocol_hash)

if not device_definition:
raise ValueError(f"No device definition found for hash {protocol_hash}.")
if not device_spec:
raise ValueError(f"No device spec found for hash {protocol_hash}.")

node = deserialize(device_definition)
node = deserialize(device_spec)
node._channel = chan
if node.hash_uint32 != protocol_hash:
raise ProtocolVersionError(node_id, "")

return node

Expand All @@ -101,17 +100,12 @@ def create_device_with_hash_msg(heartbeat_msg):
chan = CANChannel(node_id)

hash, *_ = chan.serializer.deserialize(heartbeat_msg.data[:4], DataType.UINT32)
device_definition = definitions["hash_uint32"].get(hash)
device_spec = specs["hash_uint32"].get(hash)

if not device_definition:
raise ValueError(f"No device definition found for hash {hash}.")
if not device_spec:
raise ValueError(f"No device spec found for hash {hash}.")

node = deserialize(device_definition)
if node.hash_uint32 != hash:
version_str = "".join([chr(n) for n in heartbeat_msg.data[4:]])
if not version_str.strip():
version_str = "1.3.1"
raise ProtocolVersionError(node_id, version_str)
node = deserialize(device_spec)

node._channel = chan
return node
Expand Down
4 changes: 2 additions & 2 deletions studio/Python/tinymovr/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from tinymovr.channel import ResponseError
from tinymovr.tee import get_tee
from tinymovr.constants import HEARTBEAT_BASE
from tinymovr.config import create_device_with_hash_msg, ProtocolVersionError
from tinymovr.config import create_device_with_hash_msg


class Discovery:
Expand Down Expand Up @@ -72,7 +72,7 @@ def _recv_cb(self, frame):
self._append_to_queue((node, node_id))
except ResponseError as e:
self.logger.error(e)
except ProtocolVersionError as e:
except ValueError as e:
self.logger.error(e)
self.incompatible_nodes.add(node_id)
self.pending_nodes.remove(node_id)
Expand Down
16 changes: 14 additions & 2 deletions studio/Python/tinymovr/gui/gui.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
"""Tinymovr Studio GUI
Usage:
tinymovr [--bus=<bus>] [--chan=<chan>] [--bitrate=<bitrate>] [--max-timeouts=<count>]
tinymovr [--bus=<bus>] [--chan=<chan>] [--spec=<spec>] [--bitrate=<bitrate>] [--max-timeouts=<count>]
tinymovr -h | --help
tinymovr --version
Options:
--bus=<bus> One or more interfaces to use, first available is used [default: canine,slcan_disco].
--chan=<chan> The bus device "channel".
--spec=<spec> A custom device spec to be added to the list of discoverable specs.
--bitrate=<bitrate> CAN bitrate [default: 1000000].
--max-timeouts=<count> Max timeouts before nodes are rescanned [default: 5].
"""

import sys
import yaml
import pkg_resources
from docopt import docopt
from PySide6.QtWidgets import QApplication
from tinymovr.gui import MainWindow, app_stylesheet, app_stylesheet_dark, is_dark_mode
from tinymovr.constants import app_name
from tinymovr.config import configure_logging, add_spec


"""
Expand All @@ -41,11 +44,20 @@
def spawn():
version = pkg_resources.require("tinymovr")[0].version
arguments = docopt(__doc__, version=app_name + " " + str(version))

logger = configure_logging()

spec_file = arguments["--spec"]
if spec_file:
with open(spec_file, 'r') as file:
spec_data = yaml.safe_load(file)
add_spec(spec_data, logger)

app = QApplication(sys.argv)
if is_dark_mode():
app.setStyleSheet(app_stylesheet_dark)
else:
app.setStyleSheet(app_stylesheet)
w = MainWindow(app, arguments)
w = MainWindow(app, arguments, logger)
w.show()
sys.exit(app.exec_())
10 changes: 7 additions & 3 deletions studio/Python/tinymovr/gui/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"""

import time
import logging
import pkg_resources
from functools import partial
from contextlib import suppress
Expand All @@ -42,7 +43,7 @@
import pyqtgraph as pg
from tinymovr.constants import app_name
from tinymovr.channel import ResponseError as ChannelResponseError
from tinymovr.config import get_bus_config, configure_logging
from tinymovr.config import get_bus_config
from avlos import get_registry
from avlos.json_codec import AvlosEncoder
from tinymovr.gui import (
Expand All @@ -62,14 +63,17 @@
class MainWindow(QMainWindow):
TreeItemCheckedSignal = Signal(dict)

def __init__(self, app, arguments):
def __init__(self, app, arguments, logger):
super(MainWindow, self).__init__()

# set units default format
get_registry().default_format = ".6f~"

self.start_time = time.time()
self.logger = configure_logging()
if logger is None:
self.logger = logging.getLogger("tinymovr")
else:
self.logger = logger

self.attr_widgets_by_id = {}
self.graphs_by_id = {}
Expand Down

0 comments on commit e95bacb

Please sign in to comment.