meerk40t 0.9.3001__py2.py3-none-any.whl → 0.9.7020__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/__init__.py +1 -1
- meerk40t/balormk/balor_params.py +167 -167
- meerk40t/balormk/clone_loader.py +457 -457
- meerk40t/balormk/controller.py +1566 -1512
- meerk40t/balormk/cylindermod.py +64 -0
- meerk40t/balormk/device.py +966 -1959
- meerk40t/balormk/driver.py +778 -591
- meerk40t/balormk/galvo_commands.py +1194 -0
- meerk40t/balormk/gui/balorconfig.py +237 -111
- meerk40t/balormk/gui/balorcontroller.py +191 -184
- meerk40t/balormk/gui/baloroperationproperties.py +116 -115
- meerk40t/balormk/gui/corscene.py +845 -0
- meerk40t/balormk/gui/gui.py +179 -147
- meerk40t/balormk/livelightjob.py +466 -382
- meerk40t/balormk/mock_connection.py +131 -109
- meerk40t/balormk/plugin.py +133 -135
- meerk40t/balormk/usb_connection.py +306 -301
- meerk40t/camera/__init__.py +1 -1
- meerk40t/camera/camera.py +514 -397
- meerk40t/camera/gui/camerapanel.py +1241 -1095
- meerk40t/camera/gui/gui.py +58 -58
- meerk40t/camera/plugin.py +441 -399
- meerk40t/ch341/__init__.py +27 -27
- meerk40t/ch341/ch341device.py +628 -628
- meerk40t/ch341/libusb.py +595 -589
- meerk40t/ch341/mock.py +171 -171
- meerk40t/ch341/windriver.py +157 -157
- meerk40t/constants.py +13 -0
- meerk40t/core/__init__.py +1 -1
- meerk40t/core/bindalias.py +550 -539
- meerk40t/core/core.py +47 -47
- meerk40t/core/cutcode/cubiccut.py +73 -73
- meerk40t/core/cutcode/cutcode.py +315 -312
- meerk40t/core/cutcode/cutgroup.py +141 -137
- meerk40t/core/cutcode/cutobject.py +192 -185
- meerk40t/core/cutcode/dwellcut.py +37 -37
- meerk40t/core/cutcode/gotocut.py +29 -29
- meerk40t/core/cutcode/homecut.py +29 -29
- meerk40t/core/cutcode/inputcut.py +34 -34
- meerk40t/core/cutcode/linecut.py +33 -33
- meerk40t/core/cutcode/outputcut.py +34 -34
- meerk40t/core/cutcode/plotcut.py +335 -335
- meerk40t/core/cutcode/quadcut.py +61 -61
- meerk40t/core/cutcode/rastercut.py +168 -148
- meerk40t/core/cutcode/waitcut.py +34 -34
- meerk40t/core/cutplan.py +1843 -1316
- meerk40t/core/drivers.py +330 -329
- meerk40t/core/elements/align.py +801 -669
- meerk40t/core/elements/branches.py +1858 -1507
- meerk40t/core/elements/clipboard.py +229 -219
- meerk40t/core/elements/element_treeops.py +4595 -2837
- meerk40t/core/elements/element_types.py +125 -105
- meerk40t/core/elements/elements.py +4315 -3617
- meerk40t/core/elements/files.py +117 -64
- meerk40t/core/elements/geometry.py +473 -224
- meerk40t/core/elements/grid.py +467 -316
- meerk40t/core/elements/materials.py +158 -94
- meerk40t/core/elements/notes.py +50 -38
- meerk40t/core/elements/offset_clpr.py +934 -912
- meerk40t/core/elements/offset_mk.py +963 -955
- meerk40t/core/elements/penbox.py +339 -267
- meerk40t/core/elements/placements.py +300 -83
- meerk40t/core/elements/render.py +785 -687
- meerk40t/core/elements/shapes.py +2618 -2092
- meerk40t/core/elements/testcases.py +105 -0
- meerk40t/core/elements/trace.py +651 -563
- meerk40t/core/elements/tree_commands.py +415 -409
- meerk40t/core/elements/undo_redo.py +116 -58
- meerk40t/core/elements/wordlist.py +319 -200
- meerk40t/core/exceptions.py +9 -9
- meerk40t/core/laserjob.py +220 -220
- meerk40t/core/logging.py +63 -63
- meerk40t/core/node/blobnode.py +83 -86
- meerk40t/core/node/bootstrap.py +105 -103
- meerk40t/core/node/branch_elems.py +40 -31
- meerk40t/core/node/branch_ops.py +45 -38
- meerk40t/core/node/branch_regmark.py +48 -41
- meerk40t/core/node/cutnode.py +29 -32
- meerk40t/core/node/effect_hatch.py +375 -257
- meerk40t/core/node/effect_warp.py +398 -0
- meerk40t/core/node/effect_wobble.py +441 -309
- meerk40t/core/node/elem_ellipse.py +404 -309
- meerk40t/core/node/elem_image.py +1082 -801
- meerk40t/core/node/elem_line.py +358 -292
- meerk40t/core/node/elem_path.py +259 -201
- meerk40t/core/node/elem_point.py +129 -102
- meerk40t/core/node/elem_polyline.py +310 -246
- meerk40t/core/node/elem_rect.py +376 -286
- meerk40t/core/node/elem_text.py +445 -418
- meerk40t/core/node/filenode.py +59 -40
- meerk40t/core/node/groupnode.py +138 -74
- meerk40t/core/node/image_processed.py +777 -766
- meerk40t/core/node/image_raster.py +156 -113
- meerk40t/core/node/layernode.py +31 -31
- meerk40t/core/node/mixins.py +135 -107
- meerk40t/core/node/node.py +1427 -1304
- meerk40t/core/node/nutils.py +117 -114
- meerk40t/core/node/op_cut.py +463 -335
- meerk40t/core/node/op_dots.py +296 -251
- meerk40t/core/node/op_engrave.py +414 -311
- meerk40t/core/node/op_image.py +755 -369
- meerk40t/core/node/op_raster.py +787 -522
- meerk40t/core/node/place_current.py +37 -40
- meerk40t/core/node/place_point.py +329 -126
- meerk40t/core/node/refnode.py +58 -47
- meerk40t/core/node/rootnode.py +225 -219
- meerk40t/core/node/util_console.py +48 -48
- meerk40t/core/node/util_goto.py +84 -65
- meerk40t/core/node/util_home.py +61 -61
- meerk40t/core/node/util_input.py +102 -102
- meerk40t/core/node/util_output.py +102 -102
- meerk40t/core/node/util_wait.py +65 -65
- meerk40t/core/parameters.py +709 -707
- meerk40t/core/planner.py +875 -785
- meerk40t/core/plotplanner.py +656 -652
- meerk40t/core/space.py +120 -113
- meerk40t/core/spoolers.py +706 -705
- meerk40t/core/svg_io.py +1836 -1549
- meerk40t/core/treeop.py +534 -445
- meerk40t/core/undos.py +278 -124
- meerk40t/core/units.py +784 -680
- meerk40t/core/view.py +393 -322
- meerk40t/core/webhelp.py +62 -62
- meerk40t/core/wordlist.py +513 -504
- meerk40t/cylinder/cylinder.py +247 -0
- meerk40t/cylinder/gui/cylindersettings.py +41 -0
- meerk40t/cylinder/gui/gui.py +24 -0
- meerk40t/device/__init__.py +1 -1
- meerk40t/device/basedevice.py +322 -123
- meerk40t/device/devicechoices.py +50 -0
- meerk40t/device/dummydevice.py +163 -128
- meerk40t/device/gui/defaultactions.py +618 -602
- meerk40t/device/gui/effectspanel.py +114 -0
- meerk40t/device/gui/formatterpanel.py +253 -290
- meerk40t/device/gui/warningpanel.py +337 -260
- meerk40t/device/mixins.py +13 -13
- meerk40t/dxf/__init__.py +1 -1
- meerk40t/dxf/dxf_io.py +766 -554
- meerk40t/dxf/plugin.py +47 -35
- meerk40t/external_plugins.py +79 -79
- meerk40t/external_plugins_build.py +28 -28
- meerk40t/extra/cag.py +112 -116
- meerk40t/extra/coolant.py +403 -0
- meerk40t/extra/encode_detect.py +204 -0
- meerk40t/extra/ezd.py +1165 -1165
- meerk40t/extra/hershey.py +834 -340
- meerk40t/extra/imageactions.py +322 -316
- meerk40t/extra/inkscape.py +628 -622
- meerk40t/extra/lbrn.py +424 -424
- meerk40t/extra/outerworld.py +283 -0
- meerk40t/extra/param_functions.py +1542 -1556
- meerk40t/extra/potrace.py +257 -253
- meerk40t/extra/serial_exchange.py +118 -0
- meerk40t/extra/updater.py +602 -453
- meerk40t/extra/vectrace.py +147 -146
- meerk40t/extra/winsleep.py +83 -83
- meerk40t/extra/xcs_reader.py +597 -0
- meerk40t/fill/fills.py +781 -335
- meerk40t/fill/patternfill.py +1061 -1061
- meerk40t/fill/patterns.py +614 -567
- meerk40t/grbl/control.py +87 -87
- meerk40t/grbl/controller.py +990 -903
- meerk40t/grbl/device.py +1084 -768
- meerk40t/grbl/driver.py +989 -771
- meerk40t/grbl/emulator.py +532 -497
- meerk40t/grbl/gcodejob.py +783 -767
- meerk40t/grbl/gui/grblconfiguration.py +373 -298
- meerk40t/grbl/gui/grblcontroller.py +485 -271
- meerk40t/grbl/gui/grblhardwareconfig.py +269 -153
- meerk40t/grbl/gui/grbloperationconfig.py +105 -0
- meerk40t/grbl/gui/gui.py +147 -116
- meerk40t/grbl/interpreter.py +44 -44
- meerk40t/grbl/loader.py +22 -22
- meerk40t/grbl/mock_connection.py +56 -56
- meerk40t/grbl/plugin.py +294 -264
- meerk40t/grbl/serial_connection.py +93 -88
- meerk40t/grbl/tcp_connection.py +81 -79
- meerk40t/grbl/ws_connection.py +112 -0
- meerk40t/gui/__init__.py +1 -1
- meerk40t/gui/about.py +2042 -296
- meerk40t/gui/alignment.py +1644 -1608
- meerk40t/gui/autoexec.py +199 -0
- meerk40t/gui/basicops.py +791 -670
- meerk40t/gui/bufferview.py +77 -71
- meerk40t/gui/busy.py +232 -133
- meerk40t/gui/choicepropertypanel.py +1662 -1469
- meerk40t/gui/consolepanel.py +706 -542
- meerk40t/gui/devicepanel.py +687 -581
- meerk40t/gui/dialogoptions.py +110 -107
- meerk40t/gui/executejob.py +316 -306
- meerk40t/gui/fonts.py +90 -90
- meerk40t/gui/functionwrapper.py +252 -0
- meerk40t/gui/gui_mixins.py +729 -0
- meerk40t/gui/guicolors.py +205 -182
- meerk40t/gui/help_assets/help_assets.py +218 -201
- meerk40t/gui/helper.py +154 -0
- meerk40t/gui/hersheymanager.py +1440 -846
- meerk40t/gui/icons.py +3422 -2747
- meerk40t/gui/imagesplitter.py +555 -508
- meerk40t/gui/keymap.py +354 -344
- meerk40t/gui/laserpanel.py +897 -806
- meerk40t/gui/laserrender.py +1470 -1232
- meerk40t/gui/lasertoolpanel.py +805 -793
- meerk40t/gui/magnetoptions.py +436 -0
- meerk40t/gui/materialmanager.py +2944 -0
- meerk40t/gui/materialtest.py +1722 -1694
- meerk40t/gui/mkdebug.py +646 -359
- meerk40t/gui/mwindow.py +163 -140
- meerk40t/gui/navigationpanels.py +2605 -2467
- meerk40t/gui/notes.py +143 -142
- meerk40t/gui/opassignment.py +414 -410
- meerk40t/gui/operation_info.py +310 -299
- meerk40t/gui/plugin.py +500 -328
- meerk40t/gui/position.py +714 -669
- meerk40t/gui/preferences.py +901 -650
- meerk40t/gui/propertypanels/attributes.py +1461 -1131
- meerk40t/gui/propertypanels/blobproperty.py +117 -114
- meerk40t/gui/propertypanels/consoleproperty.py +83 -80
- meerk40t/gui/propertypanels/gotoproperty.py +77 -0
- meerk40t/gui/propertypanels/groupproperties.py +223 -217
- meerk40t/gui/propertypanels/hatchproperty.py +489 -469
- meerk40t/gui/propertypanels/imageproperty.py +2244 -1384
- meerk40t/gui/propertypanels/inputproperty.py +59 -58
- meerk40t/gui/propertypanels/opbranchproperties.py +82 -80
- meerk40t/gui/propertypanels/operationpropertymain.py +1890 -1638
- meerk40t/gui/propertypanels/outputproperty.py +59 -58
- meerk40t/gui/propertypanels/pathproperty.py +389 -380
- meerk40t/gui/propertypanels/placementproperty.py +1214 -383
- meerk40t/gui/propertypanels/pointproperty.py +140 -136
- meerk40t/gui/propertypanels/propertywindow.py +313 -181
- meerk40t/gui/propertypanels/rasterwizardpanels.py +996 -912
- meerk40t/gui/propertypanels/regbranchproperties.py +76 -0
- meerk40t/gui/propertypanels/textproperty.py +770 -755
- meerk40t/gui/propertypanels/waitproperty.py +56 -55
- meerk40t/gui/propertypanels/warpproperty.py +121 -0
- meerk40t/gui/propertypanels/wobbleproperty.py +255 -204
- meerk40t/gui/ribbon.py +2471 -2210
- meerk40t/gui/scene/scene.py +1100 -1051
- meerk40t/gui/scene/sceneconst.py +22 -22
- meerk40t/gui/scene/scenepanel.py +439 -349
- meerk40t/gui/scene/scenespacewidget.py +365 -365
- meerk40t/gui/scene/widget.py +518 -505
- meerk40t/gui/scenewidgets/affinemover.py +215 -215
- meerk40t/gui/scenewidgets/attractionwidget.py +315 -309
- meerk40t/gui/scenewidgets/bedwidget.py +120 -97
- meerk40t/gui/scenewidgets/elementswidget.py +137 -107
- meerk40t/gui/scenewidgets/gridwidget.py +785 -745
- meerk40t/gui/scenewidgets/guidewidget.py +765 -765
- meerk40t/gui/scenewidgets/laserpathwidget.py +66 -66
- meerk40t/gui/scenewidgets/machineoriginwidget.py +86 -86
- meerk40t/gui/scenewidgets/nodeselector.py +28 -28
- meerk40t/gui/scenewidgets/rectselectwidget.py +592 -346
- meerk40t/gui/scenewidgets/relocatewidget.py +33 -33
- meerk40t/gui/scenewidgets/reticlewidget.py +83 -83
- meerk40t/gui/scenewidgets/selectionwidget.py +2958 -2756
- meerk40t/gui/simpleui.py +362 -333
- meerk40t/gui/simulation.py +2451 -2094
- meerk40t/gui/snapoptions.py +208 -203
- meerk40t/gui/spoolerpanel.py +1227 -1180
- meerk40t/gui/statusbarwidgets/defaultoperations.py +480 -353
- meerk40t/gui/statusbarwidgets/infowidget.py +520 -483
- meerk40t/gui/statusbarwidgets/opassignwidget.py +356 -355
- meerk40t/gui/statusbarwidgets/selectionwidget.py +172 -171
- meerk40t/gui/statusbarwidgets/shapepropwidget.py +754 -236
- meerk40t/gui/statusbarwidgets/statusbar.py +272 -260
- meerk40t/gui/statusbarwidgets/statusbarwidget.py +268 -270
- meerk40t/gui/statusbarwidgets/strokewidget.py +267 -251
- meerk40t/gui/themes.py +200 -78
- meerk40t/gui/tips.py +590 -0
- meerk40t/gui/toolwidgets/circlebrush.py +35 -35
- meerk40t/gui/toolwidgets/toolcircle.py +248 -242
- meerk40t/gui/toolwidgets/toolcontainer.py +82 -77
- meerk40t/gui/toolwidgets/tooldraw.py +97 -90
- meerk40t/gui/toolwidgets/toolellipse.py +219 -212
- meerk40t/gui/toolwidgets/toolimagecut.py +25 -132
- meerk40t/gui/toolwidgets/toolline.py +39 -144
- meerk40t/gui/toolwidgets/toollinetext.py +79 -236
- meerk40t/gui/toolwidgets/toollinetext_inline.py +296 -0
- meerk40t/gui/toolwidgets/toolmeasure.py +163 -216
- meerk40t/gui/toolwidgets/toolnodeedit.py +2088 -2074
- meerk40t/gui/toolwidgets/toolnodemove.py +92 -94
- meerk40t/gui/toolwidgets/toolparameter.py +754 -668
- meerk40t/gui/toolwidgets/toolplacement.py +108 -108
- meerk40t/gui/toolwidgets/toolpoint.py +68 -59
- meerk40t/gui/toolwidgets/toolpointlistbuilder.py +294 -0
- meerk40t/gui/toolwidgets/toolpointmove.py +183 -0
- meerk40t/gui/toolwidgets/toolpolygon.py +288 -403
- meerk40t/gui/toolwidgets/toolpolyline.py +38 -196
- meerk40t/gui/toolwidgets/toolrect.py +211 -207
- meerk40t/gui/toolwidgets/toolrelocate.py +72 -72
- meerk40t/gui/toolwidgets/toolribbon.py +598 -113
- meerk40t/gui/toolwidgets/tooltabedit.py +546 -0
- meerk40t/gui/toolwidgets/tooltext.py +98 -89
- meerk40t/gui/toolwidgets/toolvector.py +213 -204
- meerk40t/gui/toolwidgets/toolwidget.py +39 -39
- meerk40t/gui/usbconnect.py +98 -91
- meerk40t/gui/utilitywidgets/buttonwidget.py +18 -18
- meerk40t/gui/utilitywidgets/checkboxwidget.py +90 -90
- meerk40t/gui/utilitywidgets/controlwidget.py +14 -14
- meerk40t/gui/utilitywidgets/cyclocycloidwidget.py +343 -340
- meerk40t/gui/utilitywidgets/debugwidgets.py +148 -0
- meerk40t/gui/utilitywidgets/handlewidget.py +27 -27
- meerk40t/gui/utilitywidgets/harmonograph.py +450 -447
- meerk40t/gui/utilitywidgets/openclosewidget.py +40 -40
- meerk40t/gui/utilitywidgets/rotationwidget.py +54 -54
- meerk40t/gui/utilitywidgets/scalewidget.py +75 -75
- meerk40t/gui/utilitywidgets/seekbarwidget.py +183 -183
- meerk40t/gui/utilitywidgets/togglewidget.py +142 -142
- meerk40t/gui/utilitywidgets/toolbarwidget.py +8 -8
- meerk40t/gui/wordlisteditor.py +985 -931
- meerk40t/gui/wxmeerk40t.py +1447 -1169
- meerk40t/gui/wxmmain.py +5644 -4112
- meerk40t/gui/wxmribbon.py +1591 -1076
- meerk40t/gui/wxmscene.py +1631 -1453
- meerk40t/gui/wxmtree.py +2416 -2089
- meerk40t/gui/wxutils.py +1769 -1099
- meerk40t/gui/zmatrix.py +102 -102
- meerk40t/image/__init__.py +1 -1
- meerk40t/image/dither.py +429 -0
- meerk40t/image/imagetools.py +2793 -2269
- meerk40t/internal_plugins.py +150 -130
- meerk40t/kernel/__init__.py +63 -12
- meerk40t/kernel/channel.py +259 -212
- meerk40t/kernel/context.py +538 -538
- meerk40t/kernel/exceptions.py +41 -41
- meerk40t/kernel/functions.py +463 -414
- meerk40t/kernel/jobs.py +100 -100
- meerk40t/kernel/kernel.py +3828 -3571
- meerk40t/kernel/lifecycles.py +71 -71
- meerk40t/kernel/module.py +49 -49
- meerk40t/kernel/service.py +147 -147
- meerk40t/kernel/settings.py +383 -343
- meerk40t/lihuiyu/controller.py +883 -876
- meerk40t/lihuiyu/device.py +1181 -1069
- meerk40t/lihuiyu/driver.py +1466 -1372
- meerk40t/lihuiyu/gui/gui.py +127 -106
- meerk40t/lihuiyu/gui/lhyaccelgui.py +377 -363
- meerk40t/lihuiyu/gui/lhycontrollergui.py +741 -651
- meerk40t/lihuiyu/gui/lhydrivergui.py +470 -446
- meerk40t/lihuiyu/gui/lhyoperationproperties.py +238 -237
- meerk40t/lihuiyu/gui/tcpcontroller.py +226 -190
- meerk40t/lihuiyu/interpreter.py +53 -53
- meerk40t/lihuiyu/laserspeed.py +450 -450
- meerk40t/lihuiyu/loader.py +90 -90
- meerk40t/lihuiyu/parser.py +404 -404
- meerk40t/lihuiyu/plugin.py +101 -102
- meerk40t/lihuiyu/tcp_connection.py +111 -109
- meerk40t/main.py +231 -165
- meerk40t/moshi/builder.py +788 -781
- meerk40t/moshi/controller.py +505 -499
- meerk40t/moshi/device.py +495 -442
- meerk40t/moshi/driver.py +862 -696
- meerk40t/moshi/gui/gui.py +78 -76
- meerk40t/moshi/gui/moshicontrollergui.py +538 -522
- meerk40t/moshi/gui/moshidrivergui.py +87 -75
- meerk40t/moshi/plugin.py +43 -43
- meerk40t/network/console_server.py +140 -57
- meerk40t/network/kernelserver.py +10 -9
- meerk40t/network/tcp_server.py +142 -140
- meerk40t/network/udp_server.py +103 -77
- meerk40t/network/web_server.py +404 -0
- meerk40t/newly/controller.py +1158 -1144
- meerk40t/newly/device.py +874 -732
- meerk40t/newly/driver.py +540 -412
- meerk40t/newly/gui/gui.py +219 -188
- meerk40t/newly/gui/newlyconfig.py +116 -101
- meerk40t/newly/gui/newlycontroller.py +193 -186
- meerk40t/newly/gui/operationproperties.py +51 -51
- meerk40t/newly/mock_connection.py +82 -82
- meerk40t/newly/newly_params.py +56 -56
- meerk40t/newly/plugin.py +1214 -1246
- meerk40t/newly/usb_connection.py +322 -322
- meerk40t/rotary/gui/gui.py +52 -46
- meerk40t/rotary/gui/rotarysettings.py +240 -232
- meerk40t/rotary/rotary.py +202 -98
- meerk40t/ruida/control.py +291 -91
- meerk40t/ruida/controller.py +138 -1088
- meerk40t/ruida/device.py +676 -231
- meerk40t/ruida/driver.py +534 -472
- meerk40t/ruida/emulator.py +1494 -1491
- meerk40t/ruida/exceptions.py +4 -4
- meerk40t/ruida/gui/gui.py +71 -76
- meerk40t/ruida/gui/ruidaconfig.py +239 -72
- meerk40t/ruida/gui/ruidacontroller.py +187 -184
- meerk40t/ruida/gui/ruidaoperationproperties.py +48 -47
- meerk40t/ruida/loader.py +54 -52
- meerk40t/ruida/mock_connection.py +57 -109
- meerk40t/ruida/plugin.py +124 -87
- meerk40t/ruida/rdjob.py +2084 -945
- meerk40t/ruida/serial_connection.py +116 -0
- meerk40t/ruida/tcp_connection.py +146 -0
- meerk40t/ruida/udp_connection.py +73 -0
- meerk40t/svgelements.py +9671 -9669
- meerk40t/tools/driver_to_path.py +584 -579
- meerk40t/tools/geomstr.py +5583 -4680
- meerk40t/tools/jhfparser.py +357 -292
- meerk40t/tools/kerftest.py +904 -890
- meerk40t/tools/livinghinges.py +1168 -1033
- meerk40t/tools/pathtools.py +987 -949
- meerk40t/tools/pmatrix.py +234 -0
- meerk40t/tools/pointfinder.py +942 -942
- meerk40t/tools/polybool.py +941 -940
- meerk40t/tools/rasterplotter.py +1660 -547
- meerk40t/tools/shxparser.py +1047 -901
- meerk40t/tools/ttfparser.py +726 -446
- meerk40t/tools/zinglplotter.py +595 -593
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/LICENSE +21 -21
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/METADATA +150 -139
- meerk40t-0.9.7020.dist-info/RECORD +446 -0
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/WHEEL +1 -1
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/top_level.txt +0 -1
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/zip-safe +1 -1
- meerk40t/balormk/elementlightjob.py +0 -159
- meerk40t-0.9.3001.dist-info/RECORD +0 -437
- test/bootstrap.py +0 -63
- test/test_cli.py +0 -12
- test/test_core_cutcode.py +0 -418
- test/test_core_elements.py +0 -144
- test/test_core_plotplanner.py +0 -397
- test/test_core_viewports.py +0 -312
- test/test_drivers_grbl.py +0 -108
- test/test_drivers_lihuiyu.py +0 -443
- test/test_drivers_newly.py +0 -113
- test/test_element_degenerate_points.py +0 -43
- test/test_elements_classify.py +0 -97
- test/test_elements_penbox.py +0 -22
- test/test_file_svg.py +0 -176
- test/test_fill.py +0 -155
- test/test_geomstr.py +0 -1523
- test/test_geomstr_nodes.py +0 -18
- test/test_imagetools_actualize.py +0 -306
- test/test_imagetools_wizard.py +0 -258
- test/test_kernel.py +0 -200
- test/test_laser_speeds.py +0 -3303
- test/test_length.py +0 -57
- test/test_lifecycle.py +0 -66
- test/test_operations.py +0 -251
- test/test_operations_hatch.py +0 -57
- test/test_ruida.py +0 -19
- test/test_spooler.py +0 -22
- test/test_tools_rasterplotter.py +0 -29
- test/test_wobble.py +0 -133
- test/test_zingl.py +0 -124
- {test → meerk40t/cylinder}/__init__.py +0 -0
- /meerk40t/{core/element_commands.py → cylinder/gui/__init__.py} +0 -0
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/entry_points.txt +0 -0
meerk40t/core/spoolers.py
CHANGED
@@ -1,705 +1,706 @@
|
|
1
|
-
import time
|
2
|
-
from math import isinf
|
3
|
-
from threading import Condition
|
4
|
-
|
5
|
-
from meerk40t.core.laserjob import LaserJob
|
6
|
-
from meerk40t.core.units import Length
|
7
|
-
from meerk40t.kernel import CommandSyntaxError
|
8
|
-
|
9
|
-
"""
|
10
|
-
This module defines a set of commands that usually send a single easy command to the spooler. Basic jogging, home,
|
11
|
-
unlock rail commands. And it provides the the spooler class which should be provided by each driver.
|
12
|
-
|
13
|
-
Spoolers process different jobs in order. A spooler job can be anything, but usually is a LaserJob which is a simple
|
14
|
-
list of commands.
|
15
|
-
"""
|
16
|
-
|
17
|
-
|
18
|
-
def plugin(kernel, lifecycle):
|
19
|
-
if lifecycle == "register":
|
20
|
-
_ = kernel.translation
|
21
|
-
|
22
|
-
@kernel.console_command(
|
23
|
-
"spool",
|
24
|
-
help=_("spool <command>"),
|
25
|
-
regex=True,
|
26
|
-
input_type=(None, "plan"),
|
27
|
-
output_type="spooler",
|
28
|
-
)
|
29
|
-
def spool(command, channel, _, data=None, remainder=None, **kwgs):
|
30
|
-
device = kernel.device
|
31
|
-
|
32
|
-
spooler = device.spooler
|
33
|
-
# Do we have a filename to use as label?
|
34
|
-
label = kernel.elements.basename
|
35
|
-
|
36
|
-
if data is not None:
|
37
|
-
# If plan data is in data, then we copy that and move on to next step.
|
38
|
-
data.final()
|
39
|
-
loops = 1
|
40
|
-
elements = kernel.elements
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
channel(_("
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
channel(_("
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
@kernel.
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
channel(_("
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
channel(
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
spooler
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
spooler
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
spooler
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
@kernel.
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
spooler.
|
199
|
-
spooler.
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
spooler.
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
@kernel.
|
212
|
-
@kernel.console_argument("
|
213
|
-
@kernel.
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
@kernel.
|
236
|
-
@kernel.console_argument("
|
237
|
-
@kernel.
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
spooler
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
spooler
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
spooler
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
spooler
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
yield "
|
324
|
-
yield "
|
325
|
-
yield "
|
326
|
-
yield "
|
327
|
-
yield "
|
328
|
-
yield "
|
329
|
-
yield "
|
330
|
-
yield "
|
331
|
-
yield "
|
332
|
-
|
333
|
-
yield "
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
self.
|
361
|
-
self.
|
362
|
-
self.
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
@
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
execute
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
self.
|
423
|
-
self.
|
424
|
-
|
425
|
-
|
426
|
-
self.
|
427
|
-
|
428
|
-
|
429
|
-
self.
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
self.
|
437
|
-
self.
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
@param
|
448
|
-
@
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
@param
|
458
|
-
@
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
self.
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
#
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
if
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
function(
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
function(
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
ljob.
|
594
|
-
|
595
|
-
|
596
|
-
self.
|
597
|
-
self._queue.
|
598
|
-
self.
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
ljob.
|
607
|
-
|
608
|
-
|
609
|
-
self.
|
610
|
-
self._queue.
|
611
|
-
self.
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
@param
|
620
|
-
@
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
self.
|
630
|
-
self._queue.
|
631
|
-
self.
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
"
|
654
|
-
"
|
655
|
-
"
|
656
|
-
"
|
657
|
-
"
|
658
|
-
"
|
659
|
-
"
|
660
|
-
"
|
661
|
-
"
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
"
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
self.
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
"
|
684
|
-
"
|
685
|
-
"
|
686
|
-
"
|
687
|
-
"
|
688
|
-
"
|
689
|
-
"
|
690
|
-
"
|
691
|
-
"
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
"
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
1
|
+
import time
|
2
|
+
from math import isinf
|
3
|
+
from threading import Condition
|
4
|
+
|
5
|
+
from meerk40t.core.laserjob import LaserJob
|
6
|
+
from meerk40t.core.units import Length
|
7
|
+
from meerk40t.kernel import CommandSyntaxError
|
8
|
+
|
9
|
+
"""
|
10
|
+
This module defines a set of commands that usually send a single easy command to the spooler. Basic jogging, home,
|
11
|
+
unlock rail commands. And it provides the the spooler class which should be provided by each driver.
|
12
|
+
|
13
|
+
Spoolers process different jobs in order. A spooler job can be anything, but usually is a LaserJob which is a simple
|
14
|
+
list of commands.
|
15
|
+
"""
|
16
|
+
|
17
|
+
|
18
|
+
def plugin(kernel, lifecycle):
|
19
|
+
if lifecycle == "register":
|
20
|
+
_ = kernel.translation
|
21
|
+
|
22
|
+
@kernel.console_command(
|
23
|
+
"spool",
|
24
|
+
help=_("spool <command>"),
|
25
|
+
regex=True,
|
26
|
+
input_type=(None, "plan"),
|
27
|
+
output_type="spooler",
|
28
|
+
)
|
29
|
+
def spool(command, channel, _, data=None, remainder=None, **kwgs):
|
30
|
+
device = kernel.device
|
31
|
+
|
32
|
+
spooler = device.spooler
|
33
|
+
# Do we have a filename to use as label?
|
34
|
+
label = kernel.elements.basename
|
35
|
+
|
36
|
+
if data is not None:
|
37
|
+
# If plan data is in data, then we copy that and move on to next step.
|
38
|
+
data.final()
|
39
|
+
loops = 1
|
40
|
+
elements = kernel.elements
|
41
|
+
elements("wordlist advance\n")
|
42
|
+
e = elements.op_branch
|
43
|
+
|
44
|
+
if e.loop_continuous:
|
45
|
+
loops = float("inf")
|
46
|
+
else:
|
47
|
+
if e.loop_enabled:
|
48
|
+
loops = e.loop_n
|
49
|
+
spooler.laserjob(
|
50
|
+
data.plan, loops=loops, label=label, outline=data.outline
|
51
|
+
)
|
52
|
+
channel(_("Spooled Plan."))
|
53
|
+
kernel.root.signal("plan", data.name, 6)
|
54
|
+
|
55
|
+
if remainder is None:
|
56
|
+
channel(_("----------"))
|
57
|
+
channel(_("Spoolers:"))
|
58
|
+
for d, d_name in enumerate(device.match("device", suffix=True)):
|
59
|
+
channel(f"{d}: {d_name}")
|
60
|
+
channel(_("----------"))
|
61
|
+
channel(_("Spooler on device {name}:").format(name=str(device.label)))
|
62
|
+
for s, op_name in enumerate(spooler.queue):
|
63
|
+
channel(f"{s}: {op_name}")
|
64
|
+
channel(_("----------"))
|
65
|
+
return "spooler", spooler
|
66
|
+
|
67
|
+
@kernel.console_argument("op", type=str, help=_("unlock, origin, home, etc"))
|
68
|
+
@kernel.console_command(
|
69
|
+
"send",
|
70
|
+
help=_("send a plan-command to the spooler"),
|
71
|
+
input_type="spooler",
|
72
|
+
output_type="spooler",
|
73
|
+
)
|
74
|
+
def spooler_send(
|
75
|
+
command, channel, _, data_type=None, op=None, data=None, **kwgs
|
76
|
+
):
|
77
|
+
spooler = data
|
78
|
+
if op is None:
|
79
|
+
raise CommandSyntaxError
|
80
|
+
try:
|
81
|
+
for plan_command, command_name, suffix in kernel.find("plan", op):
|
82
|
+
label = f"Send {op}"
|
83
|
+
spooler.laserjob(plan_command, label=label)
|
84
|
+
return data_type, spooler
|
85
|
+
except (KeyError, IndexError):
|
86
|
+
pass
|
87
|
+
channel(_("No plan command found."))
|
88
|
+
return data_type, spooler
|
89
|
+
|
90
|
+
@kernel.console_command(
|
91
|
+
"list",
|
92
|
+
help=_("spool<?> list"),
|
93
|
+
input_type="spooler",
|
94
|
+
output_type="spooler",
|
95
|
+
)
|
96
|
+
def spooler_list(command, channel, _, data_type=None, data=None, **kwgs):
|
97
|
+
spooler = data
|
98
|
+
channel(_("----------"))
|
99
|
+
channel(_("Spoolers:"))
|
100
|
+
for d, d_name in enumerate(kernel.match("device", suffix=True)):
|
101
|
+
channel(f"{d}: {d_name}")
|
102
|
+
channel(_("----------"))
|
103
|
+
channel(
|
104
|
+
_("Spooler on device {name}:").format(name=str(kernel.device.label))
|
105
|
+
)
|
106
|
+
for s, op_name in enumerate(spooler.queue):
|
107
|
+
channel(f"{s}: {op_name}")
|
108
|
+
channel(_("----------"))
|
109
|
+
return data_type, spooler
|
110
|
+
|
111
|
+
@kernel.console_command(
|
112
|
+
"clear",
|
113
|
+
help=_("spooler<?> clear"),
|
114
|
+
input_type="spooler",
|
115
|
+
output_type="spooler",
|
116
|
+
)
|
117
|
+
def spooler_clear(command, channel, _, data_type=None, data=None, **kwgs):
|
118
|
+
spooler = data
|
119
|
+
spooler.clear_queue()
|
120
|
+
return data_type, spooler
|
121
|
+
|
122
|
+
@kernel.console_command(
|
123
|
+
"+laser",
|
124
|
+
hidden=True,
|
125
|
+
input_type=("spooler", None),
|
126
|
+
output_type="spooler",
|
127
|
+
help=_("turn laser on in place"),
|
128
|
+
)
|
129
|
+
def plus_laser(data, **kwgs):
|
130
|
+
if data is None:
|
131
|
+
data = kernel.device.spooler
|
132
|
+
spooler = data
|
133
|
+
spooler.command("laser_on")
|
134
|
+
return "spooler", spooler
|
135
|
+
|
136
|
+
@kernel.console_command(
|
137
|
+
"-laser",
|
138
|
+
hidden=True,
|
139
|
+
input_type=("spooler", None),
|
140
|
+
output_type="spooler",
|
141
|
+
help=_("turn laser off in place"),
|
142
|
+
)
|
143
|
+
def minus_laser(data, **kwgs):
|
144
|
+
if data is None:
|
145
|
+
data = kernel.device.spooler
|
146
|
+
spooler = data
|
147
|
+
spooler.command("laser_off")
|
148
|
+
return "spooler", spooler
|
149
|
+
|
150
|
+
@kernel.console_argument(
|
151
|
+
"amount", type=Length, help=_("amount to move in the set direction.")
|
152
|
+
)
|
153
|
+
@kernel.console_command(
|
154
|
+
("left", "right", "up", "down"),
|
155
|
+
input_type=("spooler", None),
|
156
|
+
output_type="spooler",
|
157
|
+
help=_("cmd <amount>"),
|
158
|
+
)
|
159
|
+
def direction(command, channel, _, data=None, amount=None, **kwgs):
|
160
|
+
if data is None:
|
161
|
+
data = kernel.device.spooler
|
162
|
+
spooler = data
|
163
|
+
if amount is None:
|
164
|
+
amount = Length("1mm")
|
165
|
+
if not hasattr(spooler, "_dx"):
|
166
|
+
spooler._dx = Length(0)
|
167
|
+
if not hasattr(spooler, "_dy"):
|
168
|
+
spooler._dy = Length(0)
|
169
|
+
if command.endswith("right"):
|
170
|
+
spooler._dx += amount
|
171
|
+
elif command.endswith("left"):
|
172
|
+
spooler._dx -= amount
|
173
|
+
elif command.endswith("up"):
|
174
|
+
spooler._dy -= amount
|
175
|
+
elif command.endswith("down"):
|
176
|
+
spooler._dy += amount
|
177
|
+
kernel.console(".timer 1 0 spool jog\n")
|
178
|
+
return "spooler", spooler
|
179
|
+
|
180
|
+
@kernel.console_option("force", "f", type=bool, action="store_true")
|
181
|
+
@kernel.console_command(
|
182
|
+
"jog",
|
183
|
+
hidden=True,
|
184
|
+
input_type=("spooler", None),
|
185
|
+
output_type="spooler",
|
186
|
+
help=_("executes outstanding jog buffer"),
|
187
|
+
)
|
188
|
+
def jog(command, channel, _, data, force=False, **kwgs):
|
189
|
+
if data is None:
|
190
|
+
data = kernel.device.spooler
|
191
|
+
spooler = data
|
192
|
+
try:
|
193
|
+
idx = spooler._dx
|
194
|
+
idy = spooler._dy
|
195
|
+
except AttributeError:
|
196
|
+
return
|
197
|
+
if force:
|
198
|
+
spooler.command("move_rel", idx, idy)
|
199
|
+
spooler._dx = Length(0)
|
200
|
+
spooler._dy = Length(0)
|
201
|
+
else:
|
202
|
+
if spooler.is_idle:
|
203
|
+
spooler.command("move_rel", float(idx), float(idy))
|
204
|
+
channel(_("Position moved: {x} {y}").format(x=idx, y=idy))
|
205
|
+
spooler._dx = Length(0)
|
206
|
+
spooler._dy = Length(0)
|
207
|
+
else:
|
208
|
+
channel(_("Busy Error"))
|
209
|
+
return "spooler", spooler
|
210
|
+
|
211
|
+
@kernel.console_option("force", "f", type=bool, action="store_true")
|
212
|
+
@kernel.console_argument("x", type=Length, help=_("change in x"))
|
213
|
+
@kernel.console_argument("y", type=Length, help=_("change in y"))
|
214
|
+
@kernel.console_command(
|
215
|
+
("move", "move_absolute"),
|
216
|
+
input_type=("spooler", None),
|
217
|
+
output_type="spooler",
|
218
|
+
help=_("move <x> <y>: move to position."),
|
219
|
+
)
|
220
|
+
def move_absolute(channel, _, x, y, data=None, force=False, **kwgs):
|
221
|
+
if data is None:
|
222
|
+
data = kernel.device.spooler
|
223
|
+
spooler = data
|
224
|
+
if y is None:
|
225
|
+
raise CommandSyntaxError
|
226
|
+
if force:
|
227
|
+
spooler.command("move_abs", x, y)
|
228
|
+
else:
|
229
|
+
if spooler.is_idle:
|
230
|
+
spooler.command("move_abs", x, y)
|
231
|
+
else:
|
232
|
+
channel(_("Busy Error"))
|
233
|
+
return "spooler", spooler
|
234
|
+
|
235
|
+
@kernel.console_option("force", "f", type=bool, action="store_true")
|
236
|
+
@kernel.console_argument("dx", type=Length, help=_("change in x"))
|
237
|
+
@kernel.console_argument("dy", type=Length, help=_("change in y"))
|
238
|
+
@kernel.console_command(
|
239
|
+
"move_relative",
|
240
|
+
input_type=("spooler", None),
|
241
|
+
output_type="spooler",
|
242
|
+
help=_("move_relative <dx> <dy>"),
|
243
|
+
)
|
244
|
+
def move_relative(channel, _, dx, dy, data=None, force=False, **kwgs):
|
245
|
+
if data is None:
|
246
|
+
data = kernel.device.spooler
|
247
|
+
spooler = data
|
248
|
+
if dy is None:
|
249
|
+
raise CommandSyntaxError
|
250
|
+
if force:
|
251
|
+
spooler.command("move_rel", dx, dy)
|
252
|
+
else:
|
253
|
+
if spooler.is_idle:
|
254
|
+
spooler.command("move_rel", dx, dy)
|
255
|
+
else:
|
256
|
+
channel(_("Busy Error"))
|
257
|
+
return "spooler", spooler
|
258
|
+
|
259
|
+
@kernel.console_command(
|
260
|
+
"home",
|
261
|
+
input_type=("spooler", None),
|
262
|
+
output_type="spooler",
|
263
|
+
help=_("home the laser"),
|
264
|
+
)
|
265
|
+
def home(data=None, **kwgs):
|
266
|
+
if data is None:
|
267
|
+
data = kernel.device.spooler
|
268
|
+
spooler = data
|
269
|
+
spooler.command("home")
|
270
|
+
return "spooler", spooler
|
271
|
+
|
272
|
+
@kernel.console_command(
|
273
|
+
"physical_home",
|
274
|
+
input_type=("spooler", None),
|
275
|
+
output_type="spooler",
|
276
|
+
help=_("home the laser (goto endstops)"),
|
277
|
+
)
|
278
|
+
def physical_home(data=None, **kwgs):
|
279
|
+
if data is None:
|
280
|
+
data = kernel.device.spooler
|
281
|
+
spooler = data
|
282
|
+
spooler.command("physical_home")
|
283
|
+
return "spooler", spooler
|
284
|
+
|
285
|
+
@kernel.console_command(
|
286
|
+
"unlock",
|
287
|
+
input_type=("spooler", None),
|
288
|
+
output_type="spooler",
|
289
|
+
help=_("unlock the rail"),
|
290
|
+
)
|
291
|
+
def unlock(data=None, **kwgs):
|
292
|
+
if data is None:
|
293
|
+
data = kernel.device.spooler
|
294
|
+
spooler = data
|
295
|
+
spooler.command("unlock_rail")
|
296
|
+
return "spooler", spooler
|
297
|
+
|
298
|
+
@kernel.console_command(
|
299
|
+
"lock",
|
300
|
+
input_type=("spooler", None),
|
301
|
+
output_type="spooler",
|
302
|
+
help=_("lock the rail"),
|
303
|
+
)
|
304
|
+
def lock(data, **kwgs):
|
305
|
+
if data is None:
|
306
|
+
data = kernel.device.spooler
|
307
|
+
spooler = data
|
308
|
+
spooler.command("lock_rail")
|
309
|
+
return "spooler", spooler
|
310
|
+
|
311
|
+
@kernel.console_command(
|
312
|
+
"test_dot_and_home",
|
313
|
+
input_type=("spooler", None),
|
314
|
+
hidden=True,
|
315
|
+
)
|
316
|
+
def run_home_and_dot_test(data, **kwgs):
|
317
|
+
if data is None:
|
318
|
+
data = kernel.device.spooler
|
319
|
+
spooler = data
|
320
|
+
|
321
|
+
def home_dot_test():
|
322
|
+
for i in range(25):
|
323
|
+
yield "rapid_mode"
|
324
|
+
yield "home"
|
325
|
+
yield "laser_off"
|
326
|
+
yield "wait_finish"
|
327
|
+
yield "move_abs", "3in", "3in"
|
328
|
+
yield "wait_finish"
|
329
|
+
yield "laser_on"
|
330
|
+
yield "wait", 50
|
331
|
+
yield "laser_off"
|
332
|
+
yield "wait_finish"
|
333
|
+
yield "home"
|
334
|
+
yield "wait_finish"
|
335
|
+
|
336
|
+
spooler.laserjob(
|
337
|
+
list(home_dot_test()), label="Dot and Home Test", helper=True
|
338
|
+
)
|
339
|
+
return "spooler", spooler
|
340
|
+
|
341
|
+
|
342
|
+
class SpoolerJob:
|
343
|
+
"""
|
344
|
+
Example of Spooler Job.
|
345
|
+
|
346
|
+
The primary methodology of a spoolerjob is that it has an `execute` function that takes the driver as an argument
|
347
|
+
it should then perform driver-like commands on the given driver to perform whatever actions the job should
|
348
|
+
execute.
|
349
|
+
|
350
|
+
The `priority` attribute is required.
|
351
|
+
|
352
|
+
The job should be permitted to `stop()` and respond to `is_running()`, and other checks as to elapsed_time(),
|
353
|
+
estimate_time(), and status.
|
354
|
+
"""
|
355
|
+
|
356
|
+
def __init__(
|
357
|
+
self,
|
358
|
+
service,
|
359
|
+
):
|
360
|
+
self.stopped = False
|
361
|
+
self.service = service
|
362
|
+
self.runtime = 0
|
363
|
+
self.priority = 0
|
364
|
+
|
365
|
+
@property
|
366
|
+
def status(self):
|
367
|
+
"""
|
368
|
+
Status is simply a status as to the job. This will be relayed by things that check the job status of jobs
|
369
|
+
in the spooler.
|
370
|
+
|
371
|
+
@return:
|
372
|
+
"""
|
373
|
+
if self.is_running:
|
374
|
+
return "Running"
|
375
|
+
else:
|
376
|
+
return "Queued"
|
377
|
+
|
378
|
+
def execute(self, driver):
|
379
|
+
"""
|
380
|
+
This is the primary method of the SpoolerJob. In this example we call the "home()" function.
|
381
|
+
@param driver:
|
382
|
+
@return:
|
383
|
+
"""
|
384
|
+
try:
|
385
|
+
driver.home()
|
386
|
+
except AttributeError:
|
387
|
+
pass
|
388
|
+
|
389
|
+
return True
|
390
|
+
|
391
|
+
def stop(self):
|
392
|
+
self.stopped = True
|
393
|
+
|
394
|
+
def is_running(self):
|
395
|
+
return not self.stopped
|
396
|
+
|
397
|
+
def elapsed_time(self):
|
398
|
+
"""
|
399
|
+
How long is this job already running...
|
400
|
+
"""
|
401
|
+
result = 0
|
402
|
+
return result
|
403
|
+
|
404
|
+
def estimate_time(self):
|
405
|
+
return 0
|
406
|
+
|
407
|
+
|
408
|
+
class Spooler:
|
409
|
+
"""
|
410
|
+
Spoolers are threaded job processors. A series of jobs is added to the spooler and these jobs are
|
411
|
+
processed in order. The driver is checked for any holds it may have preventing new commands from being
|
412
|
+
executed. If that isn't the case, the highest priority job is executed by calling the job's required
|
413
|
+
`execute()` function passing the relevant driver as the one variable. The job itself is agnostic, and will
|
414
|
+
execute whatever it wants calling the driver-like functions that may or may not exist on the driver.
|
415
|
+
|
416
|
+
If execute() returns true then it is fully executed and will be removed. Otherwise, it will be repeatedly
|
417
|
+
called until whatever work it is doing is finished. This also means the driver itself is checked for holds
|
418
|
+
(usually pausing or busy) each cycle.
|
419
|
+
"""
|
420
|
+
|
421
|
+
def __init__(self, context, driver=None, **kwargs):
|
422
|
+
self.context = context
|
423
|
+
self.driver = driver
|
424
|
+
self._current = None
|
425
|
+
|
426
|
+
self._lock = Condition()
|
427
|
+
self._queue = []
|
428
|
+
|
429
|
+
self._shutdown = False
|
430
|
+
self._thread = None
|
431
|
+
|
432
|
+
def __repr__(self):
|
433
|
+
return f"Spooler({str(self.context)})"
|
434
|
+
|
435
|
+
def __del__(self):
|
436
|
+
self.name = None
|
437
|
+
self._lock = None
|
438
|
+
self._queue = None
|
439
|
+
|
440
|
+
def __len__(self):
|
441
|
+
return len(self._queue)
|
442
|
+
|
443
|
+
def added(self, *args, **kwargs):
|
444
|
+
"""
|
445
|
+
Device service is added to the kernel.
|
446
|
+
|
447
|
+
@param args:
|
448
|
+
@param kwargs:
|
449
|
+
@return:
|
450
|
+
"""
|
451
|
+
self.restart()
|
452
|
+
|
453
|
+
def shutdown(self, *args, **kwargs):
|
454
|
+
"""
|
455
|
+
device service is shutdown during the shutdown of the kernel or destruction of the service
|
456
|
+
|
457
|
+
@param args:
|
458
|
+
@param kwargs:
|
459
|
+
@return:
|
460
|
+
"""
|
461
|
+
self._shutdown = True
|
462
|
+
with self._lock:
|
463
|
+
self._lock.notify_all()
|
464
|
+
|
465
|
+
def restart(self):
|
466
|
+
"""
|
467
|
+
Start or restart the spooler thread.
|
468
|
+
|
469
|
+
@return:
|
470
|
+
"""
|
471
|
+
self._shutdown = False
|
472
|
+
if self._thread is None:
|
473
|
+
|
474
|
+
def clear_thread(*a):
|
475
|
+
self._shutdown = True
|
476
|
+
self._thread = None
|
477
|
+
try:
|
478
|
+
# If something is currently processing stop it.
|
479
|
+
self._current.stop()
|
480
|
+
except AttributeError:
|
481
|
+
pass
|
482
|
+
with self._lock:
|
483
|
+
self._lock.notify_all()
|
484
|
+
|
485
|
+
self._thread = self.context.threaded(
|
486
|
+
self.run,
|
487
|
+
result=clear_thread,
|
488
|
+
thread_name=f"Spooler({self.context.path})",
|
489
|
+
)
|
490
|
+
self._thread.stop = clear_thread
|
491
|
+
|
492
|
+
def run(self):
|
493
|
+
"""
|
494
|
+
Run thread for the spooler.
|
495
|
+
|
496
|
+
The thread runs while the spooler is not shutdown. This executes in the spooler thread. It waits, while
|
497
|
+
the queue is empty and is notified when items are added to the queue. Each job in the spooler is called
|
498
|
+
with execute(). If the function returns True, the job is finished and removed. We then move on to the next
|
499
|
+
spooler item. If execute() returns False the job is not finished and will be reattempted. Each spooler
|
500
|
+
cycle checks the priority and whether there's a wait/hold for jobs at that priority level.
|
501
|
+
|
502
|
+
@return:
|
503
|
+
"""
|
504
|
+
while not self._shutdown:
|
505
|
+
if self.context.kernel.is_shutdown:
|
506
|
+
return # Kernel shutdown spooler threads should die off.
|
507
|
+
is_valid = False
|
508
|
+
with self._lock:
|
509
|
+
idx = 0
|
510
|
+
while not is_valid:
|
511
|
+
try:
|
512
|
+
program = self._queue[idx]
|
513
|
+
# Not all type of jobs are regular jobs,
|
514
|
+
# so that needs to be checked...
|
515
|
+
if hasattr(program, "enabled"):
|
516
|
+
if program.enabled:
|
517
|
+
is_valid = True
|
518
|
+
break
|
519
|
+
else:
|
520
|
+
idx += 1
|
521
|
+
else:
|
522
|
+
is_valid = True
|
523
|
+
break
|
524
|
+
except IndexError:
|
525
|
+
# There is no work to do.
|
526
|
+
self._lock.wait()
|
527
|
+
break
|
528
|
+
if not is_valid:
|
529
|
+
continue
|
530
|
+
|
531
|
+
priority = program.priority
|
532
|
+
|
533
|
+
# Check if the driver holds work at this priority level.
|
534
|
+
if self.driver.hold_work(priority):
|
535
|
+
time.sleep(0.01)
|
536
|
+
continue
|
537
|
+
if program != self._current:
|
538
|
+
# A different job is loaded. If it has a job_start, we call that.
|
539
|
+
if hasattr(self.driver, "job_start"):
|
540
|
+
function = getattr(self.driver, "job_start")
|
541
|
+
function(program)
|
542
|
+
self._current = program
|
543
|
+
try:
|
544
|
+
fully_executed = program.execute(self.driver)
|
545
|
+
except ConnectionAbortedError:
|
546
|
+
# Driver could no longer connect to where it was told to send the data.
|
547
|
+
return
|
548
|
+
except ConnectionRefusedError:
|
549
|
+
# Driver connection failed but, we are not aborting the spooler thread
|
550
|
+
if self._shutdown:
|
551
|
+
return
|
552
|
+
with self._lock:
|
553
|
+
self._lock.wait()
|
554
|
+
continue
|
555
|
+
if fully_executed:
|
556
|
+
# all work finished
|
557
|
+
self.remove(program)
|
558
|
+
|
559
|
+
# If we finished this work we call job_finished.
|
560
|
+
if hasattr(self.driver, "job_finish"):
|
561
|
+
function = getattr(self.driver, "job_finish")
|
562
|
+
function(program)
|
563
|
+
|
564
|
+
@property
|
565
|
+
def is_idle(self):
|
566
|
+
return len(self._queue) == 0 or self._queue[0].priority < 0
|
567
|
+
|
568
|
+
@property
|
569
|
+
def current(self):
|
570
|
+
return self._current
|
571
|
+
|
572
|
+
@property
|
573
|
+
def queue(self):
|
574
|
+
return self._queue
|
575
|
+
|
576
|
+
def laserjob(
|
577
|
+
self, job, priority=0, loops=1, label=None, helper=False, outline=None
|
578
|
+
):
|
579
|
+
"""
|
580
|
+
send a wrapped laser job to the spooler.
|
581
|
+
"""
|
582
|
+
if label is None:
|
583
|
+
label = f"{self.__class__.__name__}:{len(job)} items"
|
584
|
+
# label = str(job)
|
585
|
+
ljob = LaserJob(
|
586
|
+
label,
|
587
|
+
list(job),
|
588
|
+
driver=self.driver,
|
589
|
+
priority=priority,
|
590
|
+
loops=loops,
|
591
|
+
outline=outline,
|
592
|
+
)
|
593
|
+
ljob.helper = helper
|
594
|
+
ljob.uid = self.context.logging.uid("job")
|
595
|
+
with self._lock:
|
596
|
+
self._stop_lower_priority_running_jobs(priority)
|
597
|
+
self._queue.append(ljob)
|
598
|
+
self._queue.sort(key=lambda e: e.priority, reverse=True)
|
599
|
+
self._lock.notify()
|
600
|
+
self.context.signal("spooler;queue", len(self._queue))
|
601
|
+
|
602
|
+
def command(self, *job, priority=0, helper=True, outline=None):
|
603
|
+
ljob = LaserJob(
|
604
|
+
str(job), [job], driver=self.driver, priority=priority, outline=outline
|
605
|
+
)
|
606
|
+
ljob.helper = helper
|
607
|
+
ljob.uid = self.context.logging.uid("job")
|
608
|
+
with self._lock:
|
609
|
+
self._stop_lower_priority_running_jobs(priority)
|
610
|
+
self._queue.append(ljob)
|
611
|
+
self._queue.sort(key=lambda e: e.priority, reverse=True)
|
612
|
+
self._lock.notify()
|
613
|
+
self.context.signal("spooler;queue", len(self._queue))
|
614
|
+
|
615
|
+
def send(self, job, prevent_duplicate=False):
|
616
|
+
"""
|
617
|
+
Send a job to the spooler queue
|
618
|
+
|
619
|
+
@param job: job to send to the spooler.
|
620
|
+
@param prevent_duplicate: prevents the same job from being added again.
|
621
|
+
@return:
|
622
|
+
"""
|
623
|
+
job.uid = self.context.logging.uid("job")
|
624
|
+
with self._lock:
|
625
|
+
if prevent_duplicate:
|
626
|
+
for q in self._queue:
|
627
|
+
if q is job:
|
628
|
+
return
|
629
|
+
self._stop_lower_priority_running_jobs(job.priority)
|
630
|
+
self._queue.append(job)
|
631
|
+
self._queue.sort(key=lambda e: e.priority, reverse=True)
|
632
|
+
self._lock.notify()
|
633
|
+
self.context.signal("spooler;queue", len(self._queue))
|
634
|
+
|
635
|
+
def _stop_lower_priority_running_jobs(self, priority):
|
636
|
+
for e in self._queue:
|
637
|
+
if e.is_running() and e.priority < priority:
|
638
|
+
e.stop()
|
639
|
+
|
640
|
+
def clear_queue(self):
|
641
|
+
with self._lock:
|
642
|
+
for element in self._queue:
|
643
|
+
loop = getattr(element, "loops_executed", 0)
|
644
|
+
total = getattr(element, "loops", 0)
|
645
|
+
if isinf(total):
|
646
|
+
status = "stopped"
|
647
|
+
elif loop < total:
|
648
|
+
status = "stopped"
|
649
|
+
else:
|
650
|
+
status = "completed"
|
651
|
+
self.context.logging.event(
|
652
|
+
{
|
653
|
+
"uid": getattr(element, "uid"),
|
654
|
+
"status": status,
|
655
|
+
"loop": getattr(element, "loops_executed", None),
|
656
|
+
"total": getattr(element, "loops", None),
|
657
|
+
"label": getattr(element, "label", None),
|
658
|
+
"start_time": getattr(element, "time_started", None),
|
659
|
+
"duration": getattr(element, "runtime", None),
|
660
|
+
"device": self.context.label,
|
661
|
+
"important": not getattr(element, "helper", False),
|
662
|
+
"estimate": element.estimate_time()
|
663
|
+
if hasattr(element, "estimate_time")
|
664
|
+
else None,
|
665
|
+
"steps_done": getattr(element, "steps_done", None),
|
666
|
+
"steps_total": getattr(element, "steps_total", None),
|
667
|
+
}
|
668
|
+
)
|
669
|
+
self.context.signal("spooler;completed")
|
670
|
+
element.stop()
|
671
|
+
self._queue.clear()
|
672
|
+
self._lock.notify()
|
673
|
+
self.context.signal("spooler;queue", len(self._queue))
|
674
|
+
|
675
|
+
def remove(self, element):
|
676
|
+
with self._lock:
|
677
|
+
status = "completed"
|
678
|
+
if element.status == "Running":
|
679
|
+
element.stop()
|
680
|
+
status = "Stopped"
|
681
|
+
self.context.logging.event(
|
682
|
+
{
|
683
|
+
"uid": getattr(element, "uid"),
|
684
|
+
"status": status,
|
685
|
+
"loop": getattr(element, "loops_executed", None),
|
686
|
+
"total": getattr(element, "loops", None),
|
687
|
+
"label": getattr(element, "label", None),
|
688
|
+
"start_time": getattr(element, "time_started", None),
|
689
|
+
"duration": getattr(element, "runtime", None),
|
690
|
+
"device": self.context.label,
|
691
|
+
"important": not getattr(element, "helper", False),
|
692
|
+
"estimate": element.estimate_time()
|
693
|
+
if hasattr(element, "estimate_time")
|
694
|
+
else None,
|
695
|
+
"steps_done": getattr(element, "steps_done", None),
|
696
|
+
"steps_total": getattr(element, "steps_total", None),
|
697
|
+
}
|
698
|
+
)
|
699
|
+
self.context.signal("spooler;completed")
|
700
|
+
element.stop()
|
701
|
+
for i in range(len(self._queue) - 1, -1, -1):
|
702
|
+
e = self._queue[i]
|
703
|
+
if e is element:
|
704
|
+
del self._queue[i]
|
705
|
+
self._lock.notify()
|
706
|
+
self.context.signal("spooler;queue", len(self._queue))
|