Skip to content

Commit

Permalink
SL1SW-2381: sla: select printer prefix according to detected model
Browse files Browse the repository at this point in the history
- yaml file moved to common `yaml` forlder
- all prefixes changed to XX and compatible printers set to both SL1 and M1 models
  • Loading branch information
filipkotoucek committed Aug 15, 2024
1 parent c71dff0 commit 34e384a
Show file tree
Hide file tree
Showing 7 changed files with 354 additions and 131 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Example: 12201
* 16 `iX` - AFS IX
* 17 `XL` - Original Prusa XL
* 23 `MK3.5` - Original Prusa MK3.5
* 29 `M1` - Original Medical One

## Error categories
1. Mechanical - XYZ motors, tower, axis range
Expand Down
1 change: 1 addition & 0 deletions prusaerrors/shared/codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Printer(IntEnum):
XL = 0x0011
MK35 = 0x0017
MK39 = 0x0015
M1 = 0x001D


@unique
Expand Down
4 changes: 4 additions & 0 deletions prusaerrors/sl1/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# pylint: disable = missing-module-docstring
from pathlib import Path

PRINTER_MODEL_PATH = Path("/run/model")
62 changes: 61 additions & 1 deletion prusaerrors/sl1/codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,75 @@

import builtins
from pathlib import Path
from re import compile as re_compile

from prusaerrors.shared.codes import unique_codes, Codes, yaml_codes
import yaml

from prusaerrors.shared.codes import Category, Code, Printer, unique_codes, Codes
from prusaerrors.sl1 import PRINTER_MODEL_PATH

if "_" not in vars(builtins):

def _(value):
return value


def yaml_codes(src_path: Path):
"""
Add code definitions from YAML source
"""

def decor(cls):
with src_path.open("r") as src_file:
data = yaml.safe_load(src_file)
assert "Errors" in data

printer = Printer.UNKNOWN
model = [x.name for x in PRINTER_MODEL_PATH.iterdir() if x.is_file()]
if len(model) != 1:
raise KeyError(f"None or multiple model files found. Check {PRINTER_MODEL_PATH} folder.")

model = model[0]
if Printer.M1.name.lower() in model:
printer = Printer.M1
elif Printer.SL1.name.lower() in model:
# this case covers both SL1 and SL1S since they have identical error codes
printer = Printer.SL1

re = re_compile(
r"^(?P<printer>([0-9][0-9]|XX))"
r"(?P<category>[0-9])"
r"(?P<error>[0-9][0-9])$"
)
for entry in data["Errors"]:
code_parts = re.match(entry["code"]).groupdict()
category = Category(int(code_parts["category"]))
error = int(code_parts["error"])
printers = entry.get("printers")
action = entry.get("action", [])

if code_parts["printer"] == 'XX':
if printer.name in printers:
setattr(
cls,
entry["id"],
Code(
printer,
category,
error,
entry["title"],
entry["text"],
entry.get("approved", False),
action
)
)
else:
raise KeyError("current code has specific prefix. It has to be XX...")
return cls

return decor


@unique_codes
@yaml_codes(Path(__file__).parent / "errors.yaml")
class Sl1Codes(Codes):
Expand Down
2 changes: 1 addition & 1 deletion prusaerrors/sl1/errors.yaml
51 changes: 43 additions & 8 deletions tests/test_sl1.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,60 @@
# This file is part of the SL1 firmware
# Copyright (C) 2020 Prusa Research a.s. - www.prusa3d.com
# SPDX-License-Identifier: GPL-3.0-or-later

# pylint: disable = missing-function-docstring
# pylint: disable = missing-class-docstring
# pylint: disable = missing-module-docstring

from pathlib import Path
from tempfile import TemporaryDirectory
import unittest

from prusaerrors.sl1.codes import Sl1Codes
from unittest.mock import MagicMock, patch
from importlib import reload
from prusaerrors.shared.codes import Code


class TestErrors(unittest.TestCase):
def _test_code(self, printer_model_file: str, code_id: str, code: str) -> Code:
# create docstring documentation for this method in google style
"""
Tests the code lookup for a given printer model.
Sl1Codes relies on the PRINTER_MODEL_PATH to find the correct model file.
Printer model file is lowercase short name of
the printer. E.g. sl1, sl1s, m1.
:param printer_model_file: name of the printer model file
:param code_id: code id defined in yaml file. E.g. "TILT_HOME_FAILED"
:param code: code string with printer prefix and leading hash. E.g. "#29101"
:raises AttributeError: generated code does not match expected code
"""
with patch("prusaerrors.sl1.PRINTER_MODEL_PATH", new_callable=MagicMock, spec=Path) as mock:
with TemporaryDirectory() as temp:
full_path = temp + "/" + printer_model_file
mock.iterdir.return_value = [Path(full_path)]

# we need to actually create a file so is_file() returns True
with open(full_path, "w+", encoding="utf-8") as _:
import prusaerrors.sl1.codes
reload(prusaerrors.sl1.codes)
from prusaerrors.sl1.codes import Sl1Codes
generated_code = getattr(Sl1Codes, code_id)
self.assertEqual(generated_code, Sl1Codes.get(code))
return generated_code

def test_str_conversion(self):
self.assertEqual("#10500", str(Sl1Codes.NONE))
code = self._test_code("sl1", "NONE", "#10500")
self.assertEqual("#10500", str(code))

def test_code_lookup_sl1(self):
self._test_code("sl1", "NONE", "#10500")

def test_code_lookup_sl1s(self):
self._test_code("sl1s", "NONE", "#10500")

def test_code_lookup(self):
self.assertEqual(Sl1Codes.NONE, Sl1Codes.get("#10500"))
def test_code_lookup_m1(self):
self._test_code("m1", "NONE", "#29500")

def test_unknown_code_lookup(self):
self.assertEqual(Sl1Codes.UNKNOWN, Sl1Codes.get("random string"))
self._test_code("sl1", "UNKNOWN", "random string")


if __name__ == "__main__":
Expand Down
Loading

0 comments on commit 34e384a

Please sign in to comment.