Skip to content

Commit 0c24664

Browse files
Merge remote-tracking branch 'origin/master' into honeybee
# Conflicts: # prusaerrors/shared/codes.py
2 parents 5f33ab8 + 5ef5a9d commit 0c24664

13 files changed

+752
-271
lines changed

.github/workflows/tests.yml

+3
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,13 @@ jobs:
3030
run: |
3131
pip install .
3232
- name: Lint with pylint
33+
id: pylint
3334
run: |
3435
python3 -m pylint --version
3536
python3 -m pylint --persistent=n --jobs 0 --max-line-length=120 prusaerrors
3637
- name: Test
38+
# Run the step even if the pylint step has failed
39+
if: success() || (failure() && steps.pylint.conclusion == 'failure')
3740
run: |
3841
export PATH="${PATH}:$(pwd)"
3942
coverage run -m unittest discover --failfast --verbose tests

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ Example: 12201
1919
* 13 `MK4` - Original Prusa MK4
2020
* 16 `iX` - AFS IX
2121
* 17 `XL` - Original Prusa XL
22+
* 21 `MK3.9` - Original Prusa MK3.9
2223
* 23 `MK3.5` - Original Prusa MK3.5
24+
* 26 `MK4S` - Original Prusa MK4S
25+
* 27 `MK3.9S` - Original Prusa MK3.9S
26+
* 28 `MK3.5S` - Original Prusa MK3.5S
27+
* 29 `M1` - Original Medical One
28+
* 31 `COREONE` - Prusa Core One
2329

2430
## Error categories
2531
1. Mechanical - XYZ motors, tower, axis range

include/button_operations.h

+1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ enum class ButtonOperations : uint8_t {
1111
Unload = 4,
1212
StopPrint = 5,
1313
DisableMMU = 6,
14+
Skip = 7,
1415
};

prusaerrors/connect/codes.py

+34-27
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# This file is part of the SL1 firmware
22
# Copyright (C) 2020 Prusa Research a.s. - www.prusa3d.com
33
# SPDX-License-Identifier: GPL-3.0-or-later
4-
54
"""
65
All printer type error/attention codes
76
@@ -12,11 +11,13 @@
1211
from typing import Optional
1312

1413
import yaml
14+
from prusaerrors.shared.codes import (Category, Code, Codes, Printer,
15+
unique_codes)
1516

16-
from prusaerrors.shared.codes import unique_codes, Codes, Printer, Code, Category
17-
18-
19-
BUDDY = ['MINI', 'MK4', 'IX', 'XL', 'MK35', 'MK39']
17+
BUDDY = [
18+
'MINI', 'MK4', 'IX', 'XL', 'MK3.5', 'MK4S', 'MK3.9', 'MK3.9S', 'MK3.5S',
19+
'COREONE'
20+
]
2021

2122

2223
class PrinterCode(Code):
@@ -26,18 +27,23 @@ class PrinterCode(Code):
2627
"""
2728

2829
# pylint: disable = too-many-arguments
30+
# pylint: disable = too-many-positional-arguments
2931
def __init__(
30-
self,
31-
printer: Printer,
32-
category: Category,
33-
error: int,
34-
title: str,
35-
message: str,
36-
approved: bool,
37-
id_: str,
32+
self,
33+
printer: Printer,
34+
category: Category,
35+
error: int,
36+
title: str,
37+
message: str,
38+
approved: bool,
39+
id_: str,
3840
):
39-
super().__init__(printer=printer, category=category, error=error,
40-
title=title, message=message, approved=approved)
41+
super().__init__(printer=printer,
42+
category=category,
43+
error=error,
44+
title=title,
45+
message=message,
46+
approved=approved)
4147
self.id = id_
4248

4349
@property
@@ -60,10 +66,9 @@ def decor(cls):
6066
data = yaml.safe_load(src_file)
6167
assert "Errors" in data
6268

63-
code_re = re.compile(
64-
r"^(?P<printer>([0-9][0-9]|XX))"
65-
r"(?P<category>[0-9])"
66-
r"(?P<error>[0-9][0-9])$")
69+
code_re = re.compile(r"^(?P<printer>([0-9][0-9]|XX))"
70+
r"(?P<category>[0-9])"
71+
r"(?P<error>[0-9][0-9])$")
6772
for entry in data["Errors"]:
6873
code_parts = code_re.match(entry["code"]).groupdict()
6974
category = Category(int(code_parts["category"]))
@@ -73,24 +78,26 @@ def decor(cls):
7378
if code_parts["printer"] == 'XX':
7479
if printers := entry.get("printers"):
7580
if 'MK4' in printers:
76-
printers.append('MK39')
81+
printers.extend(('MK4S', 'MK3.9', 'MK3.9S'))
82+
elif 'MK3.5' in printers:
83+
printers.append('MK3.5S')
7784
else: # if no printers specified code is valid for all buddy
7885
printers = BUDDY
7986

8087
for printer in printers:
8188
printer = Printer[printer.upper().replace(".", "")]
82-
code = PrinterCode(
83-
printer, category, error, entry["title"],
84-
entry["text"], entry.get("approved", False),
85-
entry["id"])
89+
code = PrinterCode(printer, category, error,
90+
entry["title"], entry["text"],
91+
entry.get("approved",
92+
False), entry["id"])
8693
setattr(cls, str(code), code)
8794

8895
# code contains printer number
8996
else:
9097
printer = Printer(int(code_parts["printer"]))
91-
code = PrinterCode(printer, category, error, entry["title"],
92-
entry["text"], entry.get("approved", False),
93-
entry["id"])
98+
code = PrinterCode(printer, category, error,
99+
entry["title"], entry["text"],
100+
entry.get("approved", False), entry["id"])
94101
setattr(cls, str(code), code)
95102
return cls
96103

prusaerrors/shared/codes.py

+75-31
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
# This file is part of the Prusa firmware
22
# Copyright (C) 2020 Prusa Research a.s. - www.prusa3d.com
33
# SPDX-License-Identifier: GPL-3.0-or-later
4-
54
"""
65
Base classes for SL1 errors and warnings
76
"""
87

98
import functools
109
import json
1110
import re
12-
from enum import unique, IntEnum
11+
from enum import IntEnum, unique
1312
from pathlib import Path
14-
from typing import List, TextIO, Dict
13+
from typing import Dict, List, TextIO, Optional
1514

1615
import yaml
1716

@@ -31,17 +30,23 @@ class Printer(IntEnum):
3130
MK4 = 0x000D
3231
IX = 0x0010
3332
XL = 0x0011
34-
MK35 = 0x0017
3533
MK39 = 0x0015
36-
NEXT = 0x0019
34+
MK35 = 0x0017
35+
HONEYBEE = 0x0019
36+
MK4S = 0x001A
37+
MK39S = 0x001B
38+
MK35S = 0x001C
39+
M1 = 0x001D
40+
COREONE = 0x001F
3741

3842

3943
@unique
4044
class Category(IntEnum):
4145
"""
4246
Prusa error category codes
4347
44-
This mapping is taken from general Prusa guidelines on errors, do not modify.
48+
This mapping is taken from general Prusa guidelines on errors, do not
49+
modify.
4550
"""
4651

4752
MECHANICAL = 1 # Mechanical failures, engines XYZ, tower
@@ -62,16 +67,15 @@ class Code:
6267
"""
6368

6469
# pylint: disable = too-many-arguments
65-
def __init__(
66-
self,
67-
printer: Printer,
68-
category: Category,
69-
error: int,
70-
title: str,
71-
message: str,
72-
approved: bool,
73-
action: List[str] = None
74-
):
70+
# pylint: disable = too-many-positional-arguments
71+
def __init__(self,
72+
printer: Printer,
73+
category: Category,
74+
error: int,
75+
title: str,
76+
message: str,
77+
approved: bool,
78+
action: Optional[List[str]] = None):
7579
if printer.value < 0 or printer.value > 99:
7680
raise ValueError(f"Printer class {printer} out of range")
7781
if category.value < 0 or category.value > 9:
@@ -165,8 +169,9 @@ def approved(self):
165169
"""
166170
Whenever the message text was approved for use in production system
167171
168-
Unapproved tests are not supposed to be translated. This is planed to raise warnings and prevent the resulting
169-
build from being used in production.
172+
Unapproved tests are not supposed to be translated. This is planed
173+
to raise warnings and prevent the resulting build from being used in
174+
production.
170175
"""
171176
return self._approved
172177

@@ -212,7 +217,10 @@ def get_codes(cls) -> Dict[str, Code]:
212217
213218
:return: Member code dict
214219
"""
215-
return {item: var for item, var in vars(cls).items() if isinstance(var, Code)}
220+
return {
221+
item: var
222+
for item, var in vars(cls).items() if isinstance(var, Code)
223+
}
216224

217225
@classmethod
218226
def get(cls, code: str):
@@ -225,7 +233,10 @@ def get(cls, code: str):
225233
:return: Code instance
226234
"""
227235
if not cls._code_map:
228-
cls._code_map = {code.code: code for code in cls.get_codes().values()}
236+
cls._code_map = {
237+
code.code: code
238+
for code in cls.get_codes().values()
239+
}
229240
return cls._code_map[code]
230241

231242
@classmethod
@@ -236,7 +247,13 @@ def dump_json(cls, file: TextIO) -> None:
236247
:param file: Where to dump
237248
:return: None
238249
"""
239-
obj = {name.lower(): {"code": code.code, "message": code.message} for name, code in cls.get_codes().items()}
250+
obj = {
251+
name.lower(): {
252+
"code": code.code,
253+
"message": code.message
254+
}
255+
for name, code in cls.get_codes().items()
256+
}
240257
return json.dump(obj, file, indent=True)
241258

242259
@classmethod
@@ -284,7 +301,9 @@ def dump_qml_dictionary(cls, file: TextIO):
284301
:return: None
285302
"""
286303
file.write("import QtQuick 2.10\n")
287-
file.write("/* Generated by sla-errors. Your edits to this file will be lost. */\n")
304+
file.write(
305+
"/* Generated by sla-errors. Your edits to this file will be lost. */\n"
306+
)
288307
file.write("pragma Singleton\n")
289308
file.write("Item {\n")
290309
file.write("\treadonly property var messages:{\n")
@@ -304,7 +323,9 @@ def dump_cpp_ts(cls, file: TextIO):
304323
:param file: Where to dump
305324
:return: None
306325
"""
307-
file.write("// Generated translation string definitions for all defined error messages\n")
326+
file.write(
327+
"// Generated translation string definitions for all defined error messages\n"
328+
)
308329
for code in cls.get_codes().values():
309330
if code.message:
310331
file.write(f"QT_TR_NOOP({code.raw_message});\n")
@@ -329,7 +350,9 @@ def dump_google_docs(cls, file: TextIO) -> None:
329350
for name, code in cls.get_codes().items():
330351
message = code.message if code.message else ""
331352
category = f"{c2docs[code.category]}\t{code.category.value}"
332-
file.write(f'SL1\t10\t{category}\t{code.error}\t"{name}"\t"{message}"\t{code.code}\n')
353+
file.write(
354+
f'SL1\t10\t{category}\t{code.error}\t"{name}"\t"{message}"\t{code.code}\n'
355+
)
333356

334357
@classmethod
335358
def dump_yaml(cls, file: TextIO) -> None:
@@ -342,9 +365,13 @@ def dump_yaml(cls, file: TextIO) -> None:
342365
codes = []
343366

344367
for name, code in cls.get_codes().items():
345-
codes.append(
346-
{"code": code.raw_code, "title": name, "text": code.message, "id": name, "approved": code.approved, }
347-
)
368+
codes.append({
369+
"code": code.raw_code,
370+
"title": name,
371+
"text": code.message,
372+
"id": name,
373+
"approved": code.approved,
374+
})
348375

349376
yaml.dump({"Errors": codes}, file, sort_keys=False)
350377

@@ -359,7 +386,8 @@ def unique_codes(cls):
359386
used = set()
360387
for name, code in cls.get_codes().items():
361388
if code.code in used:
362-
raise ValueError(f"Code {name} with value {code.code} is duplicate!")
389+
raise ValueError(
390+
f"Code {name} with value {code.code} is duplicate!")
363391
used.add(code.code)
364392

365393
return cls
@@ -375,7 +403,8 @@ def unique_titles(cls):
375403
used = set()
376404
for name, code in cls.get_codes().items():
377405
if code.title in used:
378-
raise ValueError(f"Code {name} with title {code.title} is duplicate!")
406+
raise ValueError(
407+
f"Code {name} with title {code.title} is duplicate!")
379408
used.add(code.title)
380409

381410
return cls
@@ -407,8 +436,23 @@ def yaml_codes(src_path: Path):
407436
"""
408437

409438
def decor(cls):
410-
for identifier, code in decode_yaml(src_path):
411-
setattr(cls, identifier, code)
439+
with src_path.open("r") as src_file:
440+
data = yaml.safe_load(src_file)
441+
assert "Errors" in data
442+
443+
code_re = re.compile(
444+
r"^(?P<printer>[0-9][0-9])(?P<category>[0-9])(?P<error>[0-9][0-9])$"
445+
)
446+
for entry in data["Errors"]:
447+
code_parts = code_re.match(entry["code"]).groupdict()
448+
printer = Printer(int(code_parts["printer"]))
449+
category = Category(int(code_parts["category"]))
450+
error = int(code_parts["error"])
451+
action = entry.get("action", [])
452+
setattr(
453+
cls, entry["id"],
454+
Code(printer, category, error, entry["title"], entry["text"],
455+
entry["approved"], action))
412456
return cls
413457

414458
return decor

prusaerrors/sl1/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# pylint: disable = missing-module-docstring
2+
from pathlib import Path
3+
4+
PRINTER_MODEL_PATH = Path("/run/model")

0 commit comments

Comments
 (0)