meerk40t 0.9.7030__py2.py3-none-any.whl → 0.9.7050__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meerk40t/balormk/clone_loader.py +3 -2
- meerk40t/balormk/controller.py +38 -13
- meerk40t/balormk/cylindermod.py +1 -0
- meerk40t/balormk/device.py +13 -9
- meerk40t/balormk/driver.py +9 -2
- meerk40t/balormk/galvo_commands.py +3 -1
- meerk40t/balormk/gui/gui.py +6 -0
- meerk40t/balormk/livelightjob.py +338 -321
- meerk40t/balormk/mock_connection.py +4 -3
- meerk40t/balormk/usb_connection.py +11 -2
- meerk40t/camera/camera.py +19 -14
- meerk40t/camera/gui/camerapanel.py +6 -0
- meerk40t/core/cutplan.py +101 -78
- meerk40t/core/elements/element_treeops.py +435 -140
- meerk40t/core/elements/elements.py +100 -9
- meerk40t/core/elements/shapes.py +259 -72
- meerk40t/core/elements/tree_commands.py +10 -5
- meerk40t/core/node/blobnode.py +19 -4
- meerk40t/core/node/elem_ellipse.py +18 -8
- meerk40t/core/node/elem_image.py +51 -19
- meerk40t/core/node/elem_line.py +18 -8
- meerk40t/core/node/elem_path.py +18 -8
- meerk40t/core/node/elem_point.py +10 -4
- meerk40t/core/node/elem_polyline.py +19 -11
- meerk40t/core/node/elem_rect.py +18 -8
- meerk40t/core/node/elem_text.py +11 -5
- meerk40t/core/node/filenode.py +2 -8
- meerk40t/core/node/groupnode.py +11 -11
- meerk40t/core/node/image_processed.py +11 -5
- meerk40t/core/node/image_raster.py +11 -5
- meerk40t/core/node/node.py +64 -16
- meerk40t/core/node/refnode.py +2 -1
- meerk40t/core/planner.py +25 -11
- meerk40t/core/svg_io.py +91 -34
- meerk40t/device/dummydevice.py +7 -1
- meerk40t/extra/vtracer.py +222 -0
- meerk40t/grbl/device.py +96 -9
- meerk40t/grbl/driver.py +15 -5
- meerk40t/gui/about.py +20 -0
- meerk40t/gui/devicepanel.py +20 -16
- meerk40t/gui/gui_mixins.py +4 -0
- meerk40t/gui/icons.py +330 -253
- meerk40t/gui/laserpanel.py +27 -3
- meerk40t/gui/laserrender.py +41 -21
- meerk40t/gui/magnetoptions.py +158 -65
- meerk40t/gui/materialtest.py +569 -310
- meerk40t/gui/navigationpanels.py +229 -24
- meerk40t/gui/propertypanels/hatchproperty.py +2 -0
- meerk40t/gui/propertypanels/imageproperty.py +160 -106
- meerk40t/gui/propertypanels/wobbleproperty.py +6 -2
- meerk40t/gui/ribbon.py +6 -1
- meerk40t/gui/scenewidgets/gridwidget.py +29 -32
- meerk40t/gui/scenewidgets/rectselectwidget.py +190 -192
- meerk40t/gui/simulation.py +75 -77
- meerk40t/gui/spoolerpanel.py +27 -7
- meerk40t/gui/statusbarwidgets/defaultoperations.py +84 -48
- meerk40t/gui/statusbarwidgets/infowidget.py +2 -2
- meerk40t/gui/tips.py +15 -1
- meerk40t/gui/toolwidgets/toolpointmove.py +3 -1
- meerk40t/gui/wxmmain.py +242 -114
- meerk40t/gui/wxmscene.py +107 -24
- meerk40t/gui/wxmtree.py +4 -2
- meerk40t/gui/wxutils.py +286 -15
- meerk40t/image/imagetools.py +129 -65
- meerk40t/internal_plugins.py +4 -0
- meerk40t/kernel/kernel.py +67 -18
- meerk40t/kernel/settings.py +28 -9
- meerk40t/lihuiyu/device.py +24 -12
- meerk40t/main.py +14 -9
- meerk40t/moshi/device.py +20 -6
- meerk40t/network/console_server.py +22 -6
- meerk40t/newly/device.py +10 -3
- meerk40t/newly/gui/gui.py +10 -0
- meerk40t/ruida/device.py +22 -2
- meerk40t/ruida/loader.py +9 -4
- meerk40t/ruida/rdjob.py +48 -8
- meerk40t/tools/geomstr.py +240 -123
- meerk40t/tools/rasterplotter.py +185 -94
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/RECORD +85 -84
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/zip-safe +0 -0
meerk40t/kernel/settings.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import ast
|
2
|
-
import os
|
3
2
|
import configparser
|
3
|
+
import os
|
4
4
|
from pathlib import Path
|
5
5
|
from typing import Any, Dict, Generator, Optional, Union
|
6
6
|
|
@@ -22,7 +22,9 @@ class Settings:
|
|
22
22
|
|
23
23
|
def __init__(self, directory, filename, ignore_settings=False, create_backup=False):
|
24
24
|
if directory:
|
25
|
-
self._config_file = Path(get_safe_path(directory, create=True)).joinpath(
|
25
|
+
self._config_file = Path(get_safe_path(directory, create=True)).joinpath(
|
26
|
+
filename
|
27
|
+
)
|
26
28
|
else:
|
27
29
|
self._config_file = filename
|
28
30
|
self._config_dict = {}
|
@@ -51,13 +53,20 @@ class Settings:
|
|
51
53
|
PermissionError,
|
52
54
|
configparser.NoSectionError,
|
53
55
|
configparser.MissingSectionHeaderError,
|
56
|
+
configparser.ParsingError,
|
57
|
+
configparser.NoOptionError,
|
54
58
|
FileNotFoundError,
|
55
59
|
):
|
56
60
|
return
|
57
61
|
except UnicodeDecodeError as e:
|
58
|
-
print
|
59
|
-
|
60
|
-
|
62
|
+
print(
|
63
|
+
"The config file contained unsupported characters, please share the file with the dev team"
|
64
|
+
)
|
65
|
+
except (
|
66
|
+
configparser.DuplicateOptionError,
|
67
|
+
configparser.DuplicateSectionError,
|
68
|
+
) as e:
|
69
|
+
print(f"We had a duplication error in the config, try to recover from {e}")
|
61
70
|
for section in parser.sections():
|
62
71
|
for option in parser.options(section):
|
63
72
|
try:
|
@@ -65,7 +74,12 @@ class Settings:
|
|
65
74
|
except KeyError:
|
66
75
|
config_section = {}
|
67
76
|
self._config_dict[section] = config_section
|
68
|
-
|
77
|
+
try:
|
78
|
+
config_section[option] = parser.get(section, option)
|
79
|
+
except Exception as e:
|
80
|
+
print(
|
81
|
+
f"We had an error in the config, section {section}.{option}, try to recover from {e}"
|
82
|
+
)
|
69
83
|
|
70
84
|
def write_configuration(self, targetfile=None):
|
71
85
|
"""
|
@@ -91,8 +105,13 @@ class Settings:
|
|
91
105
|
except configparser.NoSectionError:
|
92
106
|
parser.add_section(section_key)
|
93
107
|
parser.set(section_key, key, value)
|
94
|
-
except (
|
95
|
-
|
108
|
+
except (
|
109
|
+
configparser.DuplicateOptionError,
|
110
|
+
configparser.DuplicateSectionError,
|
111
|
+
) as e:
|
112
|
+
print(
|
113
|
+
f"We had a duplication error in the config, try to recover from {e}"
|
114
|
+
)
|
96
115
|
|
97
116
|
if self.create_backup:
|
98
117
|
VERSIONS = 5
|
@@ -125,7 +144,7 @@ class Settings:
|
|
125
144
|
pass
|
126
145
|
with open(targetfile, "w", encoding="utf-8") as fp:
|
127
146
|
parser.write(fp)
|
128
|
-
except (PermissionError, FileNotFoundError):
|
147
|
+
except (PermissionError, FileNotFoundError, OSError, RuntimeError):
|
129
148
|
return
|
130
149
|
|
131
150
|
def literal_dict(self):
|
meerk40t/lihuiyu/device.py
CHANGED
@@ -5,21 +5,21 @@ Registers the Device service for M2 Nano (and family), registering the relevant
|
|
5
5
|
the given device type.
|
6
6
|
"""
|
7
7
|
|
8
|
-
from hashlib import md5
|
9
8
|
import platform
|
9
|
+
from hashlib import md5
|
10
10
|
|
11
11
|
import meerk40t.constants as mkconst
|
12
12
|
from meerk40t.core.laserjob import LaserJob
|
13
13
|
from meerk40t.core.spoolers import Spooler
|
14
|
+
from meerk40t.core.units import UNITS_PER_MIL, Length
|
14
15
|
from meerk40t.core.view import View
|
16
|
+
from meerk40t.device.devicechoices import get_effect_choices
|
17
|
+
from meerk40t.device.mixins import Status
|
15
18
|
from meerk40t.kernel import CommandSyntaxError, Service, signal_listener
|
16
19
|
|
17
|
-
from meerk40t.core.units import UNITS_PER_MIL, Length
|
18
|
-
from meerk40t.device.mixins import Status
|
19
20
|
from .controller import LihuiyuController
|
20
21
|
from .driver import LihuiyuDriver
|
21
22
|
from .tcp_connection import TCPOutput
|
22
|
-
from meerk40t.device.devicechoices import get_effect_choices
|
23
23
|
|
24
24
|
|
25
25
|
class LihuiyuDevice(Service, Status):
|
@@ -149,9 +149,7 @@ class LihuiyuDevice(Service, Status):
|
|
149
149
|
"label": _("Board"),
|
150
150
|
"style": "combosmall",
|
151
151
|
"choices": ["M2", "M3", "B2", "M", "M1", "A", "B", "B1"],
|
152
|
-
"tip": _(
|
153
|
-
"Select the board to use. This affects the speedcodes used."
|
154
|
-
),
|
152
|
+
"tip": _("Select the board to use. This affects the speedcodes used."),
|
155
153
|
"section": "_10_" + _("Configuration"),
|
156
154
|
"subsection": _("Board Setup"),
|
157
155
|
},
|
@@ -374,8 +372,13 @@ class LihuiyuDevice(Service, Status):
|
|
374
372
|
"type": bool,
|
375
373
|
"label": _("Use legacy raster method"),
|
376
374
|
"tip": (
|
377
|
-
_(
|
378
|
-
|
375
|
+
_(
|
376
|
+
"Active: Use legacy method (seems to work better at higher speeds, but has some artifacts)"
|
377
|
+
)
|
378
|
+
+ "\n"
|
379
|
+
+ _(
|
380
|
+
"Inactive: Use regular method (no artifacts but apparently more prone to stuttering at high speeds)"
|
381
|
+
)
|
379
382
|
),
|
380
383
|
"section": "_00_" + _("General Options"),
|
381
384
|
"subsection": "_20_",
|
@@ -1022,10 +1025,12 @@ class LihuiyuDevice(Service, Status):
|
|
1022
1025
|
return {
|
1023
1026
|
"split_crossover": True,
|
1024
1027
|
"unsupported_opt": (
|
1025
|
-
mkconst.RASTER_GREEDY_H,
|
1028
|
+
mkconst.RASTER_GREEDY_H,
|
1029
|
+
mkconst.RASTER_GREEDY_V,
|
1030
|
+
mkconst.RASTER_SPIRAL,
|
1026
1031
|
), # Greedy loses registration way too often to be reliable
|
1027
|
-
"gantry"
|
1028
|
-
"legacy"
|
1032
|
+
"gantry": True,
|
1033
|
+
"legacy": self.legacy_raster,
|
1029
1034
|
}
|
1030
1035
|
|
1031
1036
|
@property
|
@@ -1185,3 +1190,10 @@ class LihuiyuDevice(Service, Status):
|
|
1185
1190
|
|
1186
1191
|
def cool_helper(self, choice_dict):
|
1187
1192
|
self.kernel.root.coolant.coolant_choice_helper(self)(choice_dict)
|
1193
|
+
|
1194
|
+
def location(self):
|
1195
|
+
if self.mock:
|
1196
|
+
return "mock"
|
1197
|
+
if self.networked:
|
1198
|
+
return f"tcp {self.address}:{self.port}"
|
1199
|
+
return f"usb {'auto' if self.usb_index < 0 else self.usb_index}"
|
meerk40t/main.py
CHANGED
@@ -11,7 +11,7 @@ import os.path
|
|
11
11
|
import sys
|
12
12
|
|
13
13
|
APPLICATION_NAME = "MeerK40t"
|
14
|
-
APPLICATION_VERSION = "0.9.
|
14
|
+
APPLICATION_VERSION = "0.9.7050"
|
15
15
|
|
16
16
|
if not getattr(sys, "frozen", False):
|
17
17
|
# If .git directory does not exist we are running from a package like pypi
|
@@ -229,19 +229,24 @@ def _exe(restarted, args):
|
|
229
229
|
server_mode = False
|
230
230
|
if command:
|
231
231
|
for c in command:
|
232
|
-
server_mode = server_mode or any(
|
233
|
-
|
234
|
-
|
235
|
-
|
232
|
+
server_mode = server_mode or any(
|
233
|
+
substring in c
|
234
|
+
for substring in (
|
235
|
+
"lhyserver",
|
236
|
+
"grblserver",
|
237
|
+
"ruidacontrol",
|
238
|
+
"grblcontrol",
|
239
|
+
"webserver",
|
240
|
+
)
|
241
|
+
)
|
242
|
+
nogui = (hasattr(kernel.args, "gui_suppress") and kernel.args.gui_suppress) or (
|
243
|
+
hasattr(kernel.args, "no_gui") and kernel.args.no_gui
|
236
244
|
)
|
237
245
|
for idx, attrib in enumerate(("mktablength", "mktabpositions")):
|
238
246
|
kernel.register(f"registered_mk_svg_parameters/tabs{idx}", attrib)
|
239
247
|
|
240
248
|
require_partial_mode = False
|
241
|
-
if (
|
242
|
-
(not console or nogui) and
|
243
|
-
(auto or daemon or server_mode)
|
244
|
-
):
|
249
|
+
if (not console or nogui) and (auto or daemon or server_mode):
|
245
250
|
require_partial_mode = True
|
246
251
|
# print (f"Auto: {auto}, Command: {command}, Console: {console}, daemon: {daemon}, nogui:{nogui}, Server: {server_mode} -> {require_partial_mode}")
|
247
252
|
kernel(partial=require_partial_mode)
|
meerk40t/moshi/device.py
CHANGED
@@ -7,6 +7,7 @@ Registers relevant commands and options.
|
|
7
7
|
"""
|
8
8
|
import meerk40t.constants as mkconst
|
9
9
|
from meerk40t.core.view import View
|
10
|
+
from meerk40t.device.devicechoices import get_effect_choices
|
10
11
|
from meerk40t.kernel import CommandSyntaxError, Service, signal_listener
|
11
12
|
|
12
13
|
from ..core.laserjob import LaserJob
|
@@ -15,7 +16,6 @@ from ..core.units import Length
|
|
15
16
|
from ..device.mixins import Status
|
16
17
|
from .controller import MoshiController
|
17
18
|
from .driver import MoshiDriver
|
18
|
-
from meerk40t.device.devicechoices import get_effect_choices
|
19
19
|
|
20
20
|
|
21
21
|
class MoshiDevice(Service, Status):
|
@@ -210,8 +210,13 @@ class MoshiDevice(Service, Status):
|
|
210
210
|
"type": bool,
|
211
211
|
"label": _("Use legacy raster method"),
|
212
212
|
"tip": (
|
213
|
-
_(
|
214
|
-
|
213
|
+
_(
|
214
|
+
"Active: Use legacy method (seems to work better at higher speeds, but has some artifacts)"
|
215
|
+
)
|
216
|
+
+ "\n"
|
217
|
+
+ _(
|
218
|
+
"Inactive: Use regular method (no artifacts but apparently more prone to stuttering at high speeds)"
|
219
|
+
)
|
215
220
|
),
|
216
221
|
"section": "_20_Behaviour",
|
217
222
|
},
|
@@ -485,11 +490,20 @@ class MoshiDevice(Service, Status):
|
|
485
490
|
return {
|
486
491
|
"split_crossover": True,
|
487
492
|
"unsupported_opt": (
|
488
|
-
mkconst.RASTER_GREEDY_H,
|
493
|
+
mkconst.RASTER_GREEDY_H,
|
494
|
+
mkconst.RASTER_GREEDY_V,
|
495
|
+
mkconst.RASTER_SPIRAL,
|
489
496
|
), # Greedy loses registration way too often to be reliable
|
490
|
-
"gantry"
|
491
|
-
"legacy"
|
497
|
+
"gantry": True,
|
498
|
+
"legacy": self.legacy_raster,
|
492
499
|
}
|
493
500
|
|
494
501
|
def cool_helper(self, choice_dict):
|
495
502
|
self.kernel.root.coolant.coolant_choice_helper(self)(choice_dict)
|
503
|
+
|
504
|
+
def location(self):
|
505
|
+
return (
|
506
|
+
"mock"
|
507
|
+
if self.mock
|
508
|
+
else f"usb {'auto' if self.usb_index < 0 else self.usb_index}"
|
509
|
+
)
|
@@ -12,6 +12,13 @@ def plugin(kernel, lifecycle=None):
|
|
12
12
|
action="store_true",
|
13
13
|
help=_("do not watch server channels"),
|
14
14
|
)
|
15
|
+
@kernel.console_option(
|
16
|
+
"suppress",
|
17
|
+
"u",
|
18
|
+
type=bool,
|
19
|
+
action="store_true",
|
20
|
+
help=_("suppress input prompt '>>'"),
|
21
|
+
)
|
15
22
|
@kernel.console_option(
|
16
23
|
"quit",
|
17
24
|
"q",
|
@@ -23,8 +30,18 @@ def plugin(kernel, lifecycle=None):
|
|
23
30
|
"consoleserver", help=_("starts a console_server on port 23 (telnet)")
|
24
31
|
)
|
25
32
|
def server_console(
|
26
|
-
command,
|
33
|
+
command,
|
34
|
+
channel,
|
35
|
+
_,
|
36
|
+
port=23,
|
37
|
+
silent=False,
|
38
|
+
quit=False,
|
39
|
+
suppress=False,
|
40
|
+
**kwargs,
|
27
41
|
):
|
42
|
+
if suppress is None:
|
43
|
+
suppress = False
|
44
|
+
kernel.show_aio_prompt = not suppress
|
28
45
|
root = kernel.root
|
29
46
|
# Variable to store input
|
30
47
|
root.__console_buffer = ""
|
@@ -42,9 +59,9 @@ def plugin(kernel, lifecycle=None):
|
|
42
59
|
except (OSError, ValueError):
|
43
60
|
channel(_("Server failed on port: {port}").format(port=port))
|
44
61
|
return
|
45
|
-
|
62
|
+
|
46
63
|
def exec_command(data: str) -> None:
|
47
|
-
# We are in a different thread, so let's hand over stuff to the gui
|
64
|
+
# We are in a different thread, so let's hand over stuff to the gui
|
48
65
|
if isinstance(data, bytes):
|
49
66
|
try:
|
50
67
|
data = data.decode()
|
@@ -60,7 +77,7 @@ def plugin(kernel, lifecycle=None):
|
|
60
77
|
# No: we can split the command
|
61
78
|
quotations = data.count('"', 0, idx)
|
62
79
|
if quotations % 2 == 0:
|
63
|
-
data = data[:idx].rstrip() + "\n" + data[idx+1:].lstrip()
|
80
|
+
data = data[:idx].rstrip() + "\n" + data[idx + 1 :].lstrip()
|
64
81
|
start = idx + 1
|
65
82
|
root.__console_buffer += data
|
66
83
|
while "\n" in root.__console_buffer:
|
@@ -76,7 +93,7 @@ def plugin(kernel, lifecycle=None):
|
|
76
93
|
for result in root.find("gui/handover"):
|
77
94
|
# Do we have a thread handover routine?
|
78
95
|
if result is not None:
|
79
|
-
handover, _path, suffix_path
|
96
|
+
handover, _path, suffix_path = result
|
80
97
|
break
|
81
98
|
recv.watch(exec_command)
|
82
99
|
|
@@ -93,7 +110,6 @@ def plugin(kernel, lifecycle=None):
|
|
93
110
|
console.watch(send)
|
94
111
|
server.events_channel.watch(console)
|
95
112
|
|
96
|
-
|
97
113
|
@kernel.console_option(
|
98
114
|
"port", "p", type=int, default=2080, help=_("port to listen on.")
|
99
115
|
)
|
meerk40t/newly/device.py
CHANGED
@@ -5,10 +5,10 @@ from meerk40t.core.laserjob import LaserJob
|
|
5
5
|
from meerk40t.core.spoolers import Spooler
|
6
6
|
from meerk40t.core.units import Length
|
7
7
|
from meerk40t.core.view import View
|
8
|
+
from meerk40t.device.devicechoices import get_effect_choices
|
8
9
|
from meerk40t.device.mixins import Status
|
9
10
|
from meerk40t.kernel import CommandSyntaxError, Service, signal_listener
|
10
11
|
from meerk40t.newly.driver import NewlyDriver
|
11
|
-
from meerk40t.device.devicechoices import get_effect_choices
|
12
12
|
|
13
13
|
|
14
14
|
class NewlyDevice(Service, Status):
|
@@ -757,12 +757,16 @@ class NewlyDevice(Service, Status):
|
|
757
757
|
help=_("Sets the default file index to use"),
|
758
758
|
all_arguments_required=True,
|
759
759
|
)
|
760
|
-
def set_file_index(
|
760
|
+
def set_file_index(
|
761
|
+
command, channel, _, file_index=None, data=None, remainder=None, **kwgs
|
762
|
+
):
|
761
763
|
old_value = self.file_index
|
762
764
|
if file_index is None or file_index < 0 or file_index >= 10:
|
763
765
|
file_index = 0
|
764
766
|
self.file_index = file_index
|
765
|
-
channel(
|
767
|
+
channel(
|
768
|
+
f"File index was set to #{file_index} (previous value: {old_value})"
|
769
|
+
)
|
766
770
|
# Let propertypanels know that this value was updated
|
767
771
|
self.signal("file_index", file_index, self)
|
768
772
|
|
@@ -856,6 +860,9 @@ class NewlyDevice(Service, Status):
|
|
856
860
|
)
|
857
861
|
self.signal("view;realized")
|
858
862
|
|
863
|
+
def location(self):
|
864
|
+
return "mock" if self.mock else "usb"
|
865
|
+
|
859
866
|
@property
|
860
867
|
def current(self):
|
861
868
|
"""
|
meerk40t/newly/gui/gui.py
CHANGED
@@ -78,6 +78,7 @@ def plugin(service, lifecycle):
|
|
78
78
|
"tip": _("File {index}").format(index=0),
|
79
79
|
"help": "devicenewly",
|
80
80
|
"action": lambda v: service("select_file 0\n"),
|
81
|
+
"multi_autoexec": True,
|
81
82
|
},
|
82
83
|
{
|
83
84
|
"identifier": 1,
|
@@ -85,6 +86,7 @@ def plugin(service, lifecycle):
|
|
85
86
|
"tip": _("File {index}").format(index=1),
|
86
87
|
"help": "devicenewly",
|
87
88
|
"action": lambda v: service("select_file 1\n"),
|
89
|
+
"multi_autoexec": True,
|
88
90
|
},
|
89
91
|
{
|
90
92
|
"identifier": 2,
|
@@ -92,6 +94,7 @@ def plugin(service, lifecycle):
|
|
92
94
|
"tip": _("File {index}").format(index=2),
|
93
95
|
"help": "devicenewly",
|
94
96
|
"action": lambda v: service("select_file 2\n"),
|
97
|
+
"multi_autoexec": True,
|
95
98
|
},
|
96
99
|
{
|
97
100
|
"identifier": 3,
|
@@ -99,6 +102,7 @@ def plugin(service, lifecycle):
|
|
99
102
|
"tip": _("File {index}").format(index=3),
|
100
103
|
"help": "devicenewly",
|
101
104
|
"action": lambda v: service("select_file 3\n"),
|
105
|
+
"multi_autoexec": True,
|
102
106
|
},
|
103
107
|
{
|
104
108
|
"identifier": 4,
|
@@ -106,6 +110,7 @@ def plugin(service, lifecycle):
|
|
106
110
|
"tip": _("File {index}").format(index=4),
|
107
111
|
"help": "devicenewly",
|
108
112
|
"action": lambda v: service("select_file 4\n"),
|
113
|
+
"multi_autoexec": True,
|
109
114
|
},
|
110
115
|
{
|
111
116
|
"identifier": 5,
|
@@ -113,6 +118,7 @@ def plugin(service, lifecycle):
|
|
113
118
|
"tip": _("File {index}").format(index=5),
|
114
119
|
"help": "devicenewly",
|
115
120
|
"action": lambda v: service("select_file 5\n"),
|
121
|
+
"multi_autoexec": True,
|
116
122
|
},
|
117
123
|
{
|
118
124
|
"identifier": 6,
|
@@ -120,6 +126,7 @@ def plugin(service, lifecycle):
|
|
120
126
|
"tip": _("File {index}").format(index=6),
|
121
127
|
"help": "devicenewly",
|
122
128
|
"action": lambda v: service("select_file 6\n"),
|
129
|
+
"multi_autoexec": True,
|
123
130
|
},
|
124
131
|
{
|
125
132
|
"identifier": 7,
|
@@ -127,6 +134,7 @@ def plugin(service, lifecycle):
|
|
127
134
|
"tip": _("File {index}").format(index=7),
|
128
135
|
"help": "devicenewly",
|
129
136
|
"action": lambda v: service("select_file 7\n"),
|
137
|
+
"multi_autoexec": True,
|
130
138
|
},
|
131
139
|
{
|
132
140
|
"identifier": 8,
|
@@ -134,6 +142,7 @@ def plugin(service, lifecycle):
|
|
134
142
|
"tip": _("File {index}").format(index=8),
|
135
143
|
"help": "devicenewly",
|
136
144
|
"action": lambda v: service("select_file 8\n"),
|
145
|
+
"multi_autoexec": True,
|
137
146
|
},
|
138
147
|
{
|
139
148
|
"identifier": 9,
|
@@ -141,6 +150,7 @@ def plugin(service, lifecycle):
|
|
141
150
|
"tip": _("File {index}").format(index=9),
|
142
151
|
"help": "devicenewly",
|
143
152
|
"action": lambda v: service("select_file 9\n"),
|
153
|
+
"multi_autoexec": True,
|
144
154
|
},
|
145
155
|
],
|
146
156
|
},
|
meerk40t/ruida/device.py
CHANGED
@@ -5,6 +5,7 @@ Ruida device interfacing. We do not send or interpret ruida code, but we can emu
|
|
5
5
|
ruida files (*.rd) and turn them likewise into cutcode.
|
6
6
|
"""
|
7
7
|
from meerk40t.core.view import View
|
8
|
+
from meerk40t.device.devicechoices import get_effect_choices
|
8
9
|
from meerk40t.kernel import CommandSyntaxError, Service, signal_listener
|
9
10
|
|
10
11
|
from ..core.laserjob import LaserJob
|
@@ -16,7 +17,6 @@ from .mock_connection import MockConnection
|
|
16
17
|
from .serial_connection import SerialConnection
|
17
18
|
from .tcp_connection import TCPConnection
|
18
19
|
from .udp_connection import UDPConnection
|
19
|
-
from meerk40t.device.devicechoices import get_effect_choices
|
20
20
|
|
21
21
|
|
22
22
|
class RuidaDevice(Service):
|
@@ -264,6 +264,7 @@ class RuidaDevice(Service):
|
|
264
264
|
choice_dict["display"] = ["pyserial-not-installed"]
|
265
265
|
|
266
266
|
from platform import system
|
267
|
+
|
267
268
|
is_linux = system() == "Linux"
|
268
269
|
|
269
270
|
choices = [
|
@@ -278,7 +279,7 @@ class RuidaDevice(Service):
|
|
278
279
|
"section": "_10_Serial Interface",
|
279
280
|
"subsection": "_00_",
|
280
281
|
"dynamic": update,
|
281
|
-
"exclusive": not is_linux,
|
282
|
+
"exclusive": not is_linux,
|
282
283
|
},
|
283
284
|
{
|
284
285
|
"attr": "baud_rate",
|
@@ -581,6 +582,25 @@ class RuidaDevice(Service):
|
|
581
582
|
name = self.label.replace(" ", "-")
|
582
583
|
return name.replace("/", "-")
|
583
584
|
|
585
|
+
@property
|
586
|
+
def tcp_address(self):
|
587
|
+
return self.address
|
588
|
+
|
589
|
+
@property
|
590
|
+
def tcp_port(self):
|
591
|
+
return 5005
|
592
|
+
|
593
|
+
def location(self):
|
594
|
+
if self.interface == "mock":
|
595
|
+
return "mock"
|
596
|
+
elif self.interface == "udp":
|
597
|
+
return "udp, port 40200"
|
598
|
+
elif self.interface == "tcp":
|
599
|
+
return f"tcp {self.tcp_address}:{self.tcp_port}"
|
600
|
+
elif self.interface == "usb":
|
601
|
+
return f"usb: {self.serial_port}"
|
602
|
+
return f"undefined {self.interface}"
|
603
|
+
|
584
604
|
@property
|
585
605
|
def has_endstops(self):
|
586
606
|
return True
|
meerk40t/ruida/loader.py
CHANGED
@@ -15,9 +15,11 @@ def data_viewer(data, data_type):
|
|
15
15
|
|
16
16
|
if not data:
|
17
17
|
return ""
|
18
|
+
magic = determine_magic_via_histogram(data)
|
18
19
|
return BlobNode.hex_view(
|
19
|
-
data=decode_bytes(data,
|
20
|
+
data=decode_bytes(data, magic),
|
20
21
|
data_type=data_type,
|
22
|
+
info = f', Magic={magic} (0x{magic:02x})'
|
21
23
|
)
|
22
24
|
|
23
25
|
|
@@ -26,10 +28,13 @@ def command_viewer(data, data_type):
|
|
26
28
|
|
27
29
|
job = RDJob()
|
28
30
|
job.write_blob(data)
|
29
|
-
commands =
|
31
|
+
commands = []
|
30
32
|
job.channel = commands.append
|
31
|
-
|
32
|
-
|
33
|
+
try:
|
34
|
+
while not job.execute(None):
|
35
|
+
pass
|
36
|
+
except Exception as e:
|
37
|
+
commands.append(f"!! Error !!: {e}")
|
33
38
|
return "\n".join(commands)
|
34
39
|
|
35
40
|
|
meerk40t/ruida/rdjob.py
CHANGED
@@ -256,6 +256,8 @@ def encode_relcoord(coord):
|
|
256
256
|
|
257
257
|
|
258
258
|
def encode_color(color):
|
259
|
+
# Scewed on RDC 22.01
|
260
|
+
# Maybe 16bit color is used?
|
259
261
|
return encode32(int(color))
|
260
262
|
|
261
263
|
|
@@ -488,6 +490,7 @@ class RDJob:
|
|
488
490
|
self._stopped = True
|
489
491
|
self.enabled = True
|
490
492
|
self._estimate = 0
|
493
|
+
self.offset = 0
|
491
494
|
|
492
495
|
self.scale = UNITS_PER_uM
|
493
496
|
|
@@ -598,7 +601,8 @@ class RDJob:
|
|
598
601
|
command = self.buffer.pop(0)
|
599
602
|
try:
|
600
603
|
array = list(command)
|
601
|
-
self.process(array)
|
604
|
+
self.process(array, offset=self.offset)
|
605
|
+
self.offset += len(command)
|
602
606
|
except IndexError as e:
|
603
607
|
raise RuidaCommandError(
|
604
608
|
f"Could not process Ruida buffer, {self.buffer[:25]} with magic: {self.magic:02}"
|
@@ -701,7 +705,7 @@ class RDJob:
|
|
701
705
|
def set_color(self, color):
|
702
706
|
self.color = color
|
703
707
|
|
704
|
-
def process(self, array):
|
708
|
+
def process(self, array, offset=None):
|
705
709
|
"""
|
706
710
|
Parses an individual unswizzled ruida command, updating the emulator state.
|
707
711
|
|
@@ -976,7 +980,7 @@ class RDJob:
|
|
976
980
|
b = (c >> 16) & 0xFF
|
977
981
|
c = Color(red=r, blue=b, green=g)
|
978
982
|
self.set_color(c.hex)
|
979
|
-
desc = f"{part},
|
983
|
+
desc = f"Color Part {part}, {self.color}"
|
980
984
|
elif array[1] == 0x10:
|
981
985
|
value = array[2]
|
982
986
|
desc = f"EnExIO Start {value}"
|
@@ -1012,12 +1016,44 @@ class RDJob:
|
|
1012
1016
|
elif array[0] == 0xD8:
|
1013
1017
|
if array[1] == 0x00:
|
1014
1018
|
desc = "Start Process"
|
1015
|
-
|
1019
|
+
elif array[1] == 0x10:
|
1016
1020
|
desc = "Ref Point Mode 2, Machine Zero/Absolute Position"
|
1017
|
-
|
1021
|
+
elif array[1] == 0x11:
|
1018
1022
|
desc = "Ref Point Mode 1, Anchor Point"
|
1019
|
-
|
1023
|
+
elif array[1] == 0x12:
|
1020
1024
|
desc = "Ref Point Mode 0, Current Position"
|
1025
|
+
elif array[0] == 0xD9:
|
1026
|
+
if array[1] == 0x00:
|
1027
|
+
opts = array[2]
|
1028
|
+
value = abscoord(array[3:8])
|
1029
|
+
desc = f"Rapid move X ({value}μm)"
|
1030
|
+
elif array[1] == 0x01:
|
1031
|
+
opts = array[2]
|
1032
|
+
value = abscoord(array[3:8])
|
1033
|
+
desc = f"Rapid move Y ({value}μm)"
|
1034
|
+
elif array[1] == 0x02:
|
1035
|
+
opts = array[2]
|
1036
|
+
value = abscoord(array[3:8])
|
1037
|
+
desc = f"Rapid move Z ({value}μm)"
|
1038
|
+
elif array[1] == 0x03:
|
1039
|
+
opts = array[2]
|
1040
|
+
value = abscoord(array[3:8])
|
1041
|
+
desc = f"Rapid move U ({value}μm)"
|
1042
|
+
elif array[1] == 0x0F:
|
1043
|
+
opts = array[2]
|
1044
|
+
value = abscoord(array[3:8])
|
1045
|
+
desc = f"Rapid move Feed ({value}μm)"
|
1046
|
+
elif array[1] == 0x10:
|
1047
|
+
opts = array[2]
|
1048
|
+
x = abscoord(array[3:8])
|
1049
|
+
y = abscoord(array[8:13])
|
1050
|
+
desc = f"Rapid move XY ({x}μm, {y}μm)"
|
1051
|
+
elif array[1] == 0x30:
|
1052
|
+
opts = array[2]
|
1053
|
+
x = abscoord(array[3:7])
|
1054
|
+
y = abscoord(array[8:13])
|
1055
|
+
u = abscoord(array[13:18])
|
1056
|
+
desc = f"Rapid move XYU ({x}μm, {y}μm, {u}μm)"
|
1021
1057
|
elif array[0] == 0xDA:
|
1022
1058
|
mem = parse_mem(array[2:4])
|
1023
1059
|
if array[1] == 0x01:
|
@@ -1240,7 +1276,8 @@ class RDJob:
|
|
1240
1276
|
else:
|
1241
1277
|
desc = "Unknown Command!"
|
1242
1278
|
if self.channel:
|
1243
|
-
|
1279
|
+
prefix = f"{offset:06x}" if offset is not None else ''
|
1280
|
+
self.channel(f"{prefix}-**-> {str(bytes(array).hex())}\t({desc})")
|
1244
1281
|
|
1245
1282
|
def unswizzle(self, data):
|
1246
1283
|
return bytes([self.lut_unswizzle[b] for b in data])
|
@@ -1325,6 +1362,9 @@ class RDJob:
|
|
1325
1362
|
color = current_settings.get("line_color", 0)
|
1326
1363
|
frequency = current_settings.get("frequency")
|
1327
1364
|
|
1365
|
+
if color == 0:
|
1366
|
+
color = current_settings.get("color", color)
|
1367
|
+
|
1328
1368
|
self.speed_laser_1_part(part, speed)
|
1329
1369
|
if frequency:
|
1330
1370
|
self.frequency_part(0, part, frequency)
|
@@ -1670,7 +1710,7 @@ class RDJob:
|
|
1670
1710
|
self(LAYER_COLOR, encode_color(color), output=output)
|
1671
1711
|
|
1672
1712
|
def layer_color_part(self, part, color, output=None):
|
1673
|
-
self(
|
1713
|
+
self(LAYER_COLOR_PART, encode_part(part), encode_color(color), output=output)
|
1674
1714
|
|
1675
1715
|
def en_ex_io(self, value, output=None):
|
1676
1716
|
"""
|