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/grbl/gcodejob.py
CHANGED
@@ -1,767 +1,783 @@
|
|
1
|
-
import re
|
2
|
-
import threading
|
3
|
-
import time
|
4
|
-
|
5
|
-
from meerk40t.core.cutcode.plotcut import PlotCut
|
6
|
-
from meerk40t.core.cutcode.waitcut import WaitCut
|
7
|
-
from meerk40t.core.units import UNITS_PER_INCH, UNITS_PER_MM
|
8
|
-
from meerk40t.svgelements import Arc
|
9
|
-
|
10
|
-
CODE_RE = re.compile(r"([A-Za-z])")
|
11
|
-
FLOAT_RE = re.compile(r"[-+]?[0-9]*\.?[0-9]*")
|
12
|
-
|
13
|
-
|
14
|
-
def _tokenize_code(code_line):
|
15
|
-
pos = code_line.find("(")
|
16
|
-
while pos != -1:
|
17
|
-
end = code_line.find(")")
|
18
|
-
yield ["comment", code_line[pos + 1 : end]]
|
19
|
-
code_line = code_line[:pos] + code_line[end + 1 :]
|
20
|
-
pos = code_line.find("(")
|
21
|
-
pos = code_line.find(";")
|
22
|
-
if pos != -1:
|
23
|
-
yield ["comment", code_line[pos + 1 :]]
|
24
|
-
code_line = code_line[:pos]
|
25
|
-
|
26
|
-
code = None
|
27
|
-
for x in CODE_RE.split(code_line):
|
28
|
-
x = x.strip()
|
29
|
-
if len(x) == 0:
|
30
|
-
continue
|
31
|
-
if len(x) == 1 and x.isalpha():
|
32
|
-
if code is not None:
|
33
|
-
yield code
|
34
|
-
code = [x.lower()]
|
35
|
-
continue
|
36
|
-
if code is not None:
|
37
|
-
code.extend([float(v) for v in FLOAT_RE.findall(x) if len(v) != 0])
|
38
|
-
yield code
|
39
|
-
code = None
|
40
|
-
if code is not None:
|
41
|
-
yield code
|
42
|
-
|
43
|
-
|
44
|
-
OKAY = 0
|
45
|
-
# G-code words consist of a letter and a value. Letter was not found.
|
46
|
-
ERROR_GCODE_LETTER_NOT_FOUND = 1
|
47
|
-
# Numeric value format is not valid or missing an expected value.
|
48
|
-
ERROR_NUMERIC_VALUE_INVALID = 2
|
49
|
-
# Grbl '$' system command was not recognized or supported.
|
50
|
-
ERROR_REALTIME_NOT_SUPPORTED = 3
|
51
|
-
# Negative value received for an expected positive value.
|
52
|
-
ERROR_NEGATIVE_VALUE = 4
|
53
|
-
# Homing cycle is not enabled via settings.
|
54
|
-
ERROR_HOMING_CYCLE_DISABLED = 5
|
55
|
-
# Minimum step pulse time must be greater than 3usec
|
56
|
-
ERROR_STEP_PULSE_INVALID = 6
|
57
|
-
# EEPROM read failed. Reset and restored to default values.
|
58
|
-
ERROR_EEPROM_READ_ERROR = 7
|
59
|
-
# Grbl '$' command cannot be used unless Grbl is IDLE. Ensures smooth operation during a job.
|
60
|
-
ERROR_NOT_IDLE = 8
|
61
|
-
# G-code locked out during alarm or jog state
|
62
|
-
ERROR_ALARM_OR_JOG = 9
|
63
|
-
# Soft limits cannot be enabled without homing also enabled.
|
64
|
-
ERROR_SOFT_LIMITS = 10
|
65
|
-
# Max characters per line exceeded. Line was not processed and executed.
|
66
|
-
ERROR_MAX_CHARACTERS = 11
|
67
|
-
# (Compile Option) Grbl '$' setting value exceeds the maximum step rate supported.
|
68
|
-
ERROR_EXCEEDED_MAX_STEP = 12
|
69
|
-
# Safety door detected as opened and door state initiated.
|
70
|
-
ERROR_SAFETY_DOOR = 13
|
71
|
-
# (Grbl-Mega Only) Build info or startup line exceeded EEPROM line length limit.
|
72
|
-
ERROR_EEPROM_LINE_LIMIT = 14
|
73
|
-
# Jog target exceeds machine travel. Command ignored.
|
74
|
-
ERROR_JOG_EXCEEDS_MACHINE = 15
|
75
|
-
# Jog command with no '=' or contains prohibited g-code.
|
76
|
-
ERROR_JOG_SYNTAX = 16
|
77
|
-
# Laser mode requires PWM output.
|
78
|
-
ERROR_REQUIRED_POWER = 17
|
79
|
-
# Unsupported or invalid g-code command found in block.
|
80
|
-
ERROR_UNSUPPORTED_GCODE = 20
|
81
|
-
# More than one g-code command from same modal group found in block.
|
82
|
-
ERROR_DUPLICATE_COMMAND_MODAL = 21
|
83
|
-
# Feed rate has not yet been set or is undefined.
|
84
|
-
ERROR_FEED_RATE_UNSET = 22
|
85
|
-
# G-code command in block requires an integer value.
|
86
|
-
ERROR_NUMERIC_VALUE_MISSING = 23
|
87
|
-
# Two G-code commands that both require the use of the XYZ axis words were detected in the block.
|
88
|
-
ERROR_OVERLAPPING_GCODE = 24
|
89
|
-
# A G-code word was repeated in the block.
|
90
|
-
ERROR_DUPLICATE_COMMAND = 25
|
91
|
-
# A G-code command implicitly or explicitly requires XYZ axis words in the block, but none were detected.
|
92
|
-
ERROR_REQUIRES_COORDINATES = 26
|
93
|
-
# N line number value is not within the valid range of 1 - 9,999,999.
|
94
|
-
ERROR_INVALID_LINENUMBER = 27
|
95
|
-
# A G-code command was sent, but is missing some required P or L value words in the line.
|
96
|
-
ERROR_MISSING_REQUIRED_INFO = 28
|
97
|
-
# Grbl supports six work coordinate systems G54-G59. G59.1, G59.2, and G59.3 are not supported.
|
98
|
-
ERROR_UNSUPPORTED_WORK_COORDS = 29
|
99
|
-
# The G53 G-code command requires either a G0 seek or G1 feed motion mode to be active. A different motion was active.
|
100
|
-
ERROR_INVALID_MOVE_COMMAND = 30
|
101
|
-
# There are unused axis words in the block and G80 motion mode cancel is active.
|
102
|
-
ERROR_UNUSED_AXIS_WORDS = 31
|
103
|
-
# A G2 or G3 arc was commanded but there are no XYZ axis words in the selected plane to trace the arc.
|
104
|
-
ERROR_ARC_WITHOUT_WORDS = 32
|
105
|
-
# The motion command has an invalid target. G2, G3, and G38.2 generates this error, if the arc is impossible to generate or if the probe target is the current position.
|
106
|
-
ERROR_INVALID_TARGET = 33
|
107
|
-
# A G2 or G3 arc, traced with the radius definition, had a mathematical error when computing the arc geometry. Try either breaking up the arc into semicircles or quadrants, or redefine them with the arc offset definition.
|
108
|
-
ERROR_ARC_COMPUTATION = 34
|
109
|
-
# A G2 or G3 arc, traced with the offset definition, is missing the IJK offset word in the selected plane to trace the arc.
|
110
|
-
ERROR_ARC_OFFSET_WORDS_MISSING = 35
|
111
|
-
# There are unused, leftover G-code words that aren't used by any command in the block.
|
112
|
-
ERROR_UNUSED_WORDS = 36
|
113
|
-
# The G43.1 dynamic tool length offset command cannot apply an offset to an axis other than its configured axis. The Grbl default axis is the Z-axis.
|
114
|
-
ERROR_TOOL_LENGTH_INVALID = 37
|
115
|
-
# Tool number greater than max supported value.
|
116
|
-
ERROR_EXCEEDED_TOOL_MAX = 38
|
117
|
-
|
118
|
-
|
119
|
-
class GcodeJob:
|
120
|
-
def __init__(
|
121
|
-
self, driver=None, units_to_device_matrix=None, priority=0, channel=None
|
122
|
-
):
|
123
|
-
self.units_to_device_matrix = units_to_device_matrix
|
124
|
-
self._driver = driver
|
125
|
-
self.channel = channel
|
126
|
-
self.reply = None
|
127
|
-
self.buffer = list()
|
128
|
-
|
129
|
-
self.priority = priority
|
130
|
-
|
131
|
-
self.time_submitted = time.time()
|
132
|
-
self.time_started = None
|
133
|
-
self.runtime = 0
|
134
|
-
|
135
|
-
self._stopped = True
|
136
|
-
self.enabled = True
|
137
|
-
self._estimate = 0
|
138
|
-
|
139
|
-
# Initially assume mm mode. G21 mm DEFAULT
|
140
|
-
self.scale = UNITS_PER_MM
|
141
|
-
self.units = "mm"
|
142
|
-
|
143
|
-
self.compensation = False
|
144
|
-
self.feed_convert = None
|
145
|
-
self.feed_invert = None
|
146
|
-
self.feed_desc = None
|
147
|
-
self._interpolate = 50
|
148
|
-
self.program_mode = False
|
149
|
-
self.plotcut = None
|
150
|
-
|
151
|
-
self.speed = None
|
152
|
-
self.power = None
|
153
|
-
|
154
|
-
self.move_mode = 0
|
155
|
-
self.x = 0
|
156
|
-
self.y = 0
|
157
|
-
self.z = 0
|
158
|
-
|
159
|
-
self.lock = threading.Lock()
|
160
|
-
|
161
|
-
# G90 default.
|
162
|
-
self.relative = False
|
163
|
-
|
164
|
-
# G94 feedrate default, mm mode
|
165
|
-
self.g94_feedrate()
|
166
|
-
|
167
|
-
def __str__(self):
|
168
|
-
return f"{self.__class__.__name__}({len(self.buffer)} lines)"
|
169
|
-
|
170
|
-
@property
|
171
|
-
def status(self):
|
172
|
-
if self.is_running():
|
173
|
-
if self.time_started:
|
174
|
-
return "Running"
|
175
|
-
else:
|
176
|
-
return "Queued"
|
177
|
-
else:
|
178
|
-
if self.enabled:
|
179
|
-
return "Waiting"
|
180
|
-
else:
|
181
|
-
return "Disabled"
|
182
|
-
|
183
|
-
def get_feed_rate(self):
|
184
|
-
if self.speed is None:
|
185
|
-
return 0
|
186
|
-
return self.feed_invert(self.speed)
|
187
|
-
|
188
|
-
def get_power_rate(self):
|
189
|
-
if self.power is None:
|
190
|
-
return 0
|
191
|
-
return self.power
|
192
|
-
|
193
|
-
def inform(self, last_command):
|
194
|
-
if not hasattr(self._driver, "signal"):
|
195
|
-
return
|
196
|
-
info = (
|
197
|
-
self.relative,
|
198
|
-
self.program_mode,
|
199
|
-
self.move_mode,
|
200
|
-
self.units,
|
201
|
-
self.x / self.scale,
|
202
|
-
self.y / self.scale,
|
203
|
-
self.z / self.scale,
|
204
|
-
self.power,
|
205
|
-
self.speed,
|
206
|
-
self.feed_desc,
|
207
|
-
last_command,
|
208
|
-
)
|
209
|
-
self._driver.signal("grbl-emulator", info)
|
210
|
-
|
211
|
-
def reply_code(self, cmd):
|
212
|
-
if cmd == 0: # Execute GCode.
|
213
|
-
if self.reply:
|
214
|
-
self.reply("ok\r\n")
|
215
|
-
else:
|
216
|
-
if self.reply:
|
217
|
-
self.reply(f"error:{cmd}\r\n")
|
218
|
-
|
219
|
-
def write(self, line):
|
220
|
-
with self.lock:
|
221
|
-
self.buffer.append(line)
|
222
|
-
|
223
|
-
def write_all(self, lines):
|
224
|
-
with self.lock:
|
225
|
-
self.buffer.extend(lines)
|
226
|
-
|
227
|
-
def write_blob(self, data):
|
228
|
-
self.write_all(
|
229
|
-
[
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
"""
|
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
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
return
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
-
|
293
|
-
-
|
294
|
-
-
|
295
|
-
-
|
296
|
-
-
|
297
|
-
-
|
298
|
-
-
|
299
|
-
-
|
300
|
-
-
|
301
|
-
-
|
302
|
-
-
|
303
|
-
-
|
304
|
-
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
@
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
if
|
316
|
-
gc[g]
|
317
|
-
|
318
|
-
gc[g].append(
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
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
|
-
|
361
|
-
|
362
|
-
|
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
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
if
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
self.
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
#
|
487
|
-
|
488
|
-
elif v ==
|
489
|
-
#
|
490
|
-
pass
|
491
|
-
elif v ==
|
492
|
-
#
|
493
|
-
pass
|
494
|
-
elif v ==
|
495
|
-
#
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
#
|
501
|
-
|
502
|
-
elif v ==
|
503
|
-
#
|
504
|
-
pass
|
505
|
-
elif
|
506
|
-
#
|
507
|
-
pass
|
508
|
-
elif v ==
|
509
|
-
#
|
510
|
-
|
511
|
-
elif v ==
|
512
|
-
#
|
513
|
-
|
514
|
-
|
515
|
-
#
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
#
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
if "
|
558
|
-
for v in gc["
|
559
|
-
if v is None:
|
560
|
-
# Numeric value format is not valid or missing an expected value.
|
561
|
-
return ERROR_NUMERIC_VALUE_INVALID
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
try:
|
566
|
-
self._driver.set("
|
567
|
-
except AttributeError:
|
568
|
-
pass
|
569
|
-
self.
|
570
|
-
del gc["
|
571
|
-
if "
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
self.
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
if
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
if
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
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
|
-
|
672
|
-
|
673
|
-
self.
|
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
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
self.
|
763
|
-
self.
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
1
|
+
import re
|
2
|
+
import threading
|
3
|
+
import time
|
4
|
+
|
5
|
+
from meerk40t.core.cutcode.plotcut import PlotCut
|
6
|
+
from meerk40t.core.cutcode.waitcut import WaitCut
|
7
|
+
from meerk40t.core.units import UNITS_PER_INCH, UNITS_PER_MM
|
8
|
+
from meerk40t.svgelements import Arc
|
9
|
+
|
10
|
+
CODE_RE = re.compile(r"([A-Za-z])")
|
11
|
+
FLOAT_RE = re.compile(r"[-+]?[0-9]*\.?[0-9]*")
|
12
|
+
|
13
|
+
|
14
|
+
def _tokenize_code(code_line):
|
15
|
+
pos = code_line.find("(")
|
16
|
+
while pos != -1:
|
17
|
+
end = code_line.find(")")
|
18
|
+
yield ["comment", code_line[pos + 1 : end]]
|
19
|
+
code_line = code_line[:pos] + code_line[end + 1 :]
|
20
|
+
pos = code_line.find("(")
|
21
|
+
pos = code_line.find(";")
|
22
|
+
if pos != -1:
|
23
|
+
yield ["comment", code_line[pos + 1 :]]
|
24
|
+
code_line = code_line[:pos]
|
25
|
+
|
26
|
+
code = None
|
27
|
+
for x in CODE_RE.split(code_line):
|
28
|
+
x = x.strip()
|
29
|
+
if len(x) == 0:
|
30
|
+
continue
|
31
|
+
if len(x) == 1 and x.isalpha():
|
32
|
+
if code is not None:
|
33
|
+
yield code
|
34
|
+
code = [x.lower()]
|
35
|
+
continue
|
36
|
+
if code is not None:
|
37
|
+
code.extend([float(v) for v in FLOAT_RE.findall(x) if len(v) != 0])
|
38
|
+
yield code
|
39
|
+
code = None
|
40
|
+
if code is not None:
|
41
|
+
yield code
|
42
|
+
|
43
|
+
|
44
|
+
OKAY = 0
|
45
|
+
# G-code words consist of a letter and a value. Letter was not found.
|
46
|
+
ERROR_GCODE_LETTER_NOT_FOUND = 1
|
47
|
+
# Numeric value format is not valid or missing an expected value.
|
48
|
+
ERROR_NUMERIC_VALUE_INVALID = 2
|
49
|
+
# Grbl '$' system command was not recognized or supported.
|
50
|
+
ERROR_REALTIME_NOT_SUPPORTED = 3
|
51
|
+
# Negative value received for an expected positive value.
|
52
|
+
ERROR_NEGATIVE_VALUE = 4
|
53
|
+
# Homing cycle is not enabled via settings.
|
54
|
+
ERROR_HOMING_CYCLE_DISABLED = 5
|
55
|
+
# Minimum step pulse time must be greater than 3usec
|
56
|
+
ERROR_STEP_PULSE_INVALID = 6
|
57
|
+
# EEPROM read failed. Reset and restored to default values.
|
58
|
+
ERROR_EEPROM_READ_ERROR = 7
|
59
|
+
# Grbl '$' command cannot be used unless Grbl is IDLE. Ensures smooth operation during a job.
|
60
|
+
ERROR_NOT_IDLE = 8
|
61
|
+
# G-code locked out during alarm or jog state
|
62
|
+
ERROR_ALARM_OR_JOG = 9
|
63
|
+
# Soft limits cannot be enabled without homing also enabled.
|
64
|
+
ERROR_SOFT_LIMITS = 10
|
65
|
+
# Max characters per line exceeded. Line was not processed and executed.
|
66
|
+
ERROR_MAX_CHARACTERS = 11
|
67
|
+
# (Compile Option) Grbl '$' setting value exceeds the maximum step rate supported.
|
68
|
+
ERROR_EXCEEDED_MAX_STEP = 12
|
69
|
+
# Safety door detected as opened and door state initiated.
|
70
|
+
ERROR_SAFETY_DOOR = 13
|
71
|
+
# (Grbl-Mega Only) Build info or startup line exceeded EEPROM line length limit.
|
72
|
+
ERROR_EEPROM_LINE_LIMIT = 14
|
73
|
+
# Jog target exceeds machine travel. Command ignored.
|
74
|
+
ERROR_JOG_EXCEEDS_MACHINE = 15
|
75
|
+
# Jog command with no '=' or contains prohibited g-code.
|
76
|
+
ERROR_JOG_SYNTAX = 16
|
77
|
+
# Laser mode requires PWM output.
|
78
|
+
ERROR_REQUIRED_POWER = 17
|
79
|
+
# Unsupported or invalid g-code command found in block.
|
80
|
+
ERROR_UNSUPPORTED_GCODE = 20
|
81
|
+
# More than one g-code command from same modal group found in block.
|
82
|
+
ERROR_DUPLICATE_COMMAND_MODAL = 21
|
83
|
+
# Feed rate has not yet been set or is undefined.
|
84
|
+
ERROR_FEED_RATE_UNSET = 22
|
85
|
+
# G-code command in block requires an integer value.
|
86
|
+
ERROR_NUMERIC_VALUE_MISSING = 23
|
87
|
+
# Two G-code commands that both require the use of the XYZ axis words were detected in the block.
|
88
|
+
ERROR_OVERLAPPING_GCODE = 24
|
89
|
+
# A G-code word was repeated in the block.
|
90
|
+
ERROR_DUPLICATE_COMMAND = 25
|
91
|
+
# A G-code command implicitly or explicitly requires XYZ axis words in the block, but none were detected.
|
92
|
+
ERROR_REQUIRES_COORDINATES = 26
|
93
|
+
# N line number value is not within the valid range of 1 - 9,999,999.
|
94
|
+
ERROR_INVALID_LINENUMBER = 27
|
95
|
+
# A G-code command was sent, but is missing some required P or L value words in the line.
|
96
|
+
ERROR_MISSING_REQUIRED_INFO = 28
|
97
|
+
# Grbl supports six work coordinate systems G54-G59. G59.1, G59.2, and G59.3 are not supported.
|
98
|
+
ERROR_UNSUPPORTED_WORK_COORDS = 29
|
99
|
+
# The G53 G-code command requires either a G0 seek or G1 feed motion mode to be active. A different motion was active.
|
100
|
+
ERROR_INVALID_MOVE_COMMAND = 30
|
101
|
+
# There are unused axis words in the block and G80 motion mode cancel is active.
|
102
|
+
ERROR_UNUSED_AXIS_WORDS = 31
|
103
|
+
# A G2 or G3 arc was commanded but there are no XYZ axis words in the selected plane to trace the arc.
|
104
|
+
ERROR_ARC_WITHOUT_WORDS = 32
|
105
|
+
# The motion command has an invalid target. G2, G3, and G38.2 generates this error, if the arc is impossible to generate or if the probe target is the current position.
|
106
|
+
ERROR_INVALID_TARGET = 33
|
107
|
+
# A G2 or G3 arc, traced with the radius definition, had a mathematical error when computing the arc geometry. Try either breaking up the arc into semicircles or quadrants, or redefine them with the arc offset definition.
|
108
|
+
ERROR_ARC_COMPUTATION = 34
|
109
|
+
# A G2 or G3 arc, traced with the offset definition, is missing the IJK offset word in the selected plane to trace the arc.
|
110
|
+
ERROR_ARC_OFFSET_WORDS_MISSING = 35
|
111
|
+
# There are unused, leftover G-code words that aren't used by any command in the block.
|
112
|
+
ERROR_UNUSED_WORDS = 36
|
113
|
+
# The G43.1 dynamic tool length offset command cannot apply an offset to an axis other than its configured axis. The Grbl default axis is the Z-axis.
|
114
|
+
ERROR_TOOL_LENGTH_INVALID = 37
|
115
|
+
# Tool number greater than max supported value.
|
116
|
+
ERROR_EXCEEDED_TOOL_MAX = 38
|
117
|
+
|
118
|
+
|
119
|
+
class GcodeJob:
|
120
|
+
def __init__(
|
121
|
+
self, driver=None, units_to_device_matrix=None, priority=0, channel=None
|
122
|
+
):
|
123
|
+
self.units_to_device_matrix = units_to_device_matrix
|
124
|
+
self._driver = driver
|
125
|
+
self.channel = channel
|
126
|
+
self.reply = None
|
127
|
+
self.buffer = list()
|
128
|
+
|
129
|
+
self.priority = priority
|
130
|
+
|
131
|
+
self.time_submitted = time.time()
|
132
|
+
self.time_started = None
|
133
|
+
self.runtime = 0
|
134
|
+
|
135
|
+
self._stopped = True
|
136
|
+
self.enabled = True
|
137
|
+
self._estimate = 0
|
138
|
+
|
139
|
+
# Initially assume mm mode. G21 mm DEFAULT
|
140
|
+
self.scale = UNITS_PER_MM
|
141
|
+
self.units = "mm"
|
142
|
+
|
143
|
+
self.compensation = False
|
144
|
+
self.feed_convert = None
|
145
|
+
self.feed_invert = None
|
146
|
+
self.feed_desc = None
|
147
|
+
self._interpolate = 50
|
148
|
+
self.program_mode = False
|
149
|
+
self.plotcut = None
|
150
|
+
|
151
|
+
self.speed = None
|
152
|
+
self.power = None
|
153
|
+
|
154
|
+
self.move_mode = 0
|
155
|
+
self.x = 0
|
156
|
+
self.y = 0
|
157
|
+
self.z = 0
|
158
|
+
|
159
|
+
self.lock = threading.Lock()
|
160
|
+
|
161
|
+
# G90 default.
|
162
|
+
self.relative = False
|
163
|
+
|
164
|
+
# G94 feedrate default, mm mode
|
165
|
+
self.g94_feedrate()
|
166
|
+
|
167
|
+
def __str__(self):
|
168
|
+
return f"{self.__class__.__name__}({len(self.buffer)} lines)"
|
169
|
+
|
170
|
+
@property
|
171
|
+
def status(self):
|
172
|
+
if self.is_running():
|
173
|
+
if self.time_started:
|
174
|
+
return "Running"
|
175
|
+
else:
|
176
|
+
return "Queued"
|
177
|
+
else:
|
178
|
+
if self.enabled:
|
179
|
+
return "Waiting"
|
180
|
+
else:
|
181
|
+
return "Disabled"
|
182
|
+
|
183
|
+
def get_feed_rate(self):
|
184
|
+
if self.speed is None:
|
185
|
+
return 0
|
186
|
+
return self.feed_invert(self.speed)
|
187
|
+
|
188
|
+
def get_power_rate(self):
|
189
|
+
if self.power is None:
|
190
|
+
return 0
|
191
|
+
return self.power
|
192
|
+
|
193
|
+
def inform(self, last_command):
|
194
|
+
if not hasattr(self._driver, "signal"):
|
195
|
+
return
|
196
|
+
info = (
|
197
|
+
self.relative,
|
198
|
+
self.program_mode,
|
199
|
+
self.move_mode,
|
200
|
+
self.units,
|
201
|
+
self.x / self.scale,
|
202
|
+
self.y / self.scale,
|
203
|
+
self.z / self.scale,
|
204
|
+
self.power,
|
205
|
+
self.speed,
|
206
|
+
self.feed_desc,
|
207
|
+
last_command,
|
208
|
+
)
|
209
|
+
self._driver.signal("grbl-emulator", info)
|
210
|
+
|
211
|
+
def reply_code(self, cmd):
|
212
|
+
if cmd == 0: # Execute GCode.
|
213
|
+
if self.reply:
|
214
|
+
self.reply("ok\r\n")
|
215
|
+
else:
|
216
|
+
if self.reply:
|
217
|
+
self.reply(f"error:{cmd}\r\n")
|
218
|
+
|
219
|
+
def write(self, line):
|
220
|
+
with self.lock:
|
221
|
+
self.buffer.append(line)
|
222
|
+
|
223
|
+
def write_all(self, lines):
|
224
|
+
with self.lock:
|
225
|
+
self.buffer.extend(lines)
|
226
|
+
|
227
|
+
def write_blob(self, data):
|
228
|
+
self.write_all(
|
229
|
+
[
|
230
|
+
r
|
231
|
+
for r in re.split("[\n|\r]", data.decode("utf-8", errors="ignore"))
|
232
|
+
if r.strip()
|
233
|
+
]
|
234
|
+
)
|
235
|
+
|
236
|
+
def execute(self, driver=None):
|
237
|
+
"""
|
238
|
+
Execute calls each item in the list of items in order. This is intended to be called by the spooler thread. And
|
239
|
+
hold the spooler while these items are executing.
|
240
|
+
@return:
|
241
|
+
"""
|
242
|
+
self._stopped = False
|
243
|
+
if self.time_started is None:
|
244
|
+
self.time_started = time.time()
|
245
|
+
try:
|
246
|
+
with self.lock:
|
247
|
+
line = self.buffer.pop(0)
|
248
|
+
cmd = self._process_gcode(line)
|
249
|
+
self.reply_code(cmd)
|
250
|
+
except IndexError:
|
251
|
+
# Could not pop, list is empty. Job is done.
|
252
|
+
pass
|
253
|
+
if not self.buffer:
|
254
|
+
# Buffer is empty now. Job is complete
|
255
|
+
self.runtime += time.time() - self.time_started
|
256
|
+
self._stopped = True
|
257
|
+
return True # All steps were executed.
|
258
|
+
return False
|
259
|
+
|
260
|
+
def stop(self):
|
261
|
+
"""
|
262
|
+
Stop this current laser-job, cannot be called from the spooler thread.
|
263
|
+
@return:
|
264
|
+
"""
|
265
|
+
if not self._stopped:
|
266
|
+
self.runtime += time.time() - self.time_started
|
267
|
+
self._stopped = True
|
268
|
+
|
269
|
+
def is_running(self):
|
270
|
+
return not self._stopped
|
271
|
+
|
272
|
+
def elapsed_time(self):
|
273
|
+
"""
|
274
|
+
How long is this job already running...
|
275
|
+
"""
|
276
|
+
if self.is_running():
|
277
|
+
return time.time() - self.time_started
|
278
|
+
else:
|
279
|
+
return self.runtime
|
280
|
+
|
281
|
+
def estimate_time(self):
|
282
|
+
"""
|
283
|
+
Give laser job time estimate.
|
284
|
+
@return:
|
285
|
+
"""
|
286
|
+
return self._estimate
|
287
|
+
|
288
|
+
def _process_gcode(self, data, jog=False):
|
289
|
+
"""
|
290
|
+
Processes the gcode commands which are parsed into different dictionary objects.
|
291
|
+
List of Supported G-Codes in Grbl v1.1:
|
292
|
+
- Non-Modal Commands: G4, G10L2, G10L20, G28, G30, G28.1, G30.1, G53, G92, G92.1
|
293
|
+
- Motion Modes: G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
|
294
|
+
- Feed Rate Modes: G93, G94
|
295
|
+
- Unit Modes: G20, G21
|
296
|
+
- Distance Modes: G90, G91
|
297
|
+
- Arc IJK Distance Modes: G91.1
|
298
|
+
- Plane Select Modes: G17, G18, G19
|
299
|
+
- Tool Length Offset Modes: G43.1, G49
|
300
|
+
- Cutter Compensation Modes: G40
|
301
|
+
- Coordinate System Modes: G54, G55, G56, G57, G58, G59
|
302
|
+
- Control Modes: G61
|
303
|
+
- Program Flow: M0, M1, M2, M30*
|
304
|
+
- Coolant Control: M7*, M8, M9
|
305
|
+
- Spindle Control: M3, M4, M5
|
306
|
+
- Valid Non-Command Words: F, I, J, K, L, N, P, R, S, T, X, Y, Z
|
307
|
+
|
308
|
+
@param data: gcode line to process
|
309
|
+
@param jog: indicate this gcode line is operated as a jog.
|
310
|
+
@return:
|
311
|
+
"""
|
312
|
+
gc = {}
|
313
|
+
for c in _tokenize_code(data):
|
314
|
+
g = c[0]
|
315
|
+
if g not in gc:
|
316
|
+
gc[g] = []
|
317
|
+
if len(c) >= 2:
|
318
|
+
gc[g].append(c[1])
|
319
|
+
else:
|
320
|
+
gc[g].append(None)
|
321
|
+
# self.inform(str(gc))
|
322
|
+
if "m" in gc:
|
323
|
+
for v in gc["m"]:
|
324
|
+
if v in (0, 1):
|
325
|
+
# Program Flow: Stop or Unconditional Stop
|
326
|
+
try:
|
327
|
+
self._driver.rapid_mode()
|
328
|
+
except AttributeError:
|
329
|
+
pass
|
330
|
+
elif v == 2:
|
331
|
+
# Program Flow: Program End
|
332
|
+
try:
|
333
|
+
self._driver.plot_start()
|
334
|
+
except AttributeError:
|
335
|
+
pass
|
336
|
+
try:
|
337
|
+
self._driver.rapid_mode()
|
338
|
+
except AttributeError:
|
339
|
+
pass
|
340
|
+
return OKAY
|
341
|
+
elif v == 30:
|
342
|
+
# Program Flow: Program Stop
|
343
|
+
try:
|
344
|
+
self._driver.rapid_mode()
|
345
|
+
except AttributeError:
|
346
|
+
pass
|
347
|
+
return OKAY
|
348
|
+
elif v in (3, 4):
|
349
|
+
# Spindle Control - Spindle On - Clockwise/CCW Laser Mode
|
350
|
+
self.program_mode = True
|
351
|
+
elif v == 5:
|
352
|
+
# Spindle Control - Spindle Off - Laser Mode
|
353
|
+
if self.program_mode:
|
354
|
+
try:
|
355
|
+
self.plot_commit()
|
356
|
+
self._driver.plot_start()
|
357
|
+
except AttributeError:
|
358
|
+
pass
|
359
|
+
try:
|
360
|
+
self._driver.rapid_mode()
|
361
|
+
except AttributeError:
|
362
|
+
pass
|
363
|
+
self.program_mode = False
|
364
|
+
elif v == 7:
|
365
|
+
# Coolant Control: Mist coolant control.
|
366
|
+
try:
|
367
|
+
self._driver.service.kernel.root.coolant.coolant_on(
|
368
|
+
self._driver.service
|
369
|
+
)
|
370
|
+
except AttributeError:
|
371
|
+
# Eg in a mock connection we dont have a driver...
|
372
|
+
pass
|
373
|
+
elif v == 8:
|
374
|
+
# Coolant Control: Flood coolant On
|
375
|
+
try:
|
376
|
+
self._driver.service.kernel.root.coolant.coolant_on(
|
377
|
+
self._driver.service
|
378
|
+
)
|
379
|
+
except AttributeError:
|
380
|
+
# Eg in a mock connection we dont have a driver...
|
381
|
+
pass
|
382
|
+
elif v == 9:
|
383
|
+
# Coolant Control: Flood coolant Off
|
384
|
+
try:
|
385
|
+
self._driver.service.kernel.root.coolant.coolant_off(
|
386
|
+
self._driver.service
|
387
|
+
)
|
388
|
+
except AttributeError:
|
389
|
+
# Eg in a mock connection we dont have a driver...
|
390
|
+
pass
|
391
|
+
elif v == 56:
|
392
|
+
# Parking motion override control.
|
393
|
+
pass
|
394
|
+
else:
|
395
|
+
# Unsupported or invalid g-code command found in block.
|
396
|
+
return ERROR_UNSUPPORTED_GCODE
|
397
|
+
del gc["m"]
|
398
|
+
if "g" in gc:
|
399
|
+
for v in gc["g"]:
|
400
|
+
if v is None:
|
401
|
+
# G but no number given.
|
402
|
+
# Numeric value format is not valid or missing an expected value.
|
403
|
+
return ERROR_NUMERIC_VALUE_INVALID
|
404
|
+
elif v == 0:
|
405
|
+
# G0 Rapid Move.
|
406
|
+
self.move_mode = 0
|
407
|
+
elif v == 1:
|
408
|
+
# G1 Cut Move.
|
409
|
+
self.move_mode = 1
|
410
|
+
elif v == 2:
|
411
|
+
# G2 CW_ARC
|
412
|
+
self.move_mode = 2
|
413
|
+
elif v == 3:
|
414
|
+
# G3 CCW_ARC
|
415
|
+
self.move_mode = 3
|
416
|
+
elif v == 4:
|
417
|
+
# DWELL
|
418
|
+
t = 0
|
419
|
+
if "p" in gc:
|
420
|
+
t = float(gc["p"].pop()) / 1000.0
|
421
|
+
if len(gc["p"]) == 0:
|
422
|
+
del gc["p"]
|
423
|
+
if "s" in gc:
|
424
|
+
t = float(gc["s"].pop())
|
425
|
+
if len(gc["s"]) == 0:
|
426
|
+
del gc["s"]
|
427
|
+
if self.program_mode:
|
428
|
+
self.plot_commit()
|
429
|
+
self.plot(WaitCut(t))
|
430
|
+
else:
|
431
|
+
try:
|
432
|
+
self._driver.wait(t)
|
433
|
+
except AttributeError:
|
434
|
+
pass
|
435
|
+
elif v == 10:
|
436
|
+
l_value = gc["l"].pop(0)
|
437
|
+
if l_value is None:
|
438
|
+
# A G-code command was sent, but is missing some required P or L value words in the line.
|
439
|
+
return ERROR_MISSING_REQUIRED_INFO
|
440
|
+
elif l_value == 2:
|
441
|
+
# Set Work Coordinate Offsets
|
442
|
+
pass
|
443
|
+
elif l_value == 20:
|
444
|
+
# Set Work Coordinate Offsets
|
445
|
+
# Sets the offset values for the coordinate system. P1 = G54
|
446
|
+
p_value = gc["p"].pop(0)
|
447
|
+
if p_value is None:
|
448
|
+
# A G-code command was sent, but is missing some required P or L value words in the line.
|
449
|
+
return ERROR_MISSING_REQUIRED_INFO
|
450
|
+
else:
|
451
|
+
# Unsupported or invalid g-code command found in block.
|
452
|
+
return ERROR_UNSUPPORTED_GCODE
|
453
|
+
elif v == 17:
|
454
|
+
# Set XY coords.
|
455
|
+
pass
|
456
|
+
elif v == 18:
|
457
|
+
# Set the XZ plane for arc.
|
458
|
+
# Unsupported or invalid g-code command found in block.
|
459
|
+
return ERROR_UNSUPPORTED_GCODE
|
460
|
+
elif v == 19:
|
461
|
+
# Set the YZ plane for arc.
|
462
|
+
# Unsupported or invalid g-code command found in block.
|
463
|
+
return ERROR_UNSUPPORTED_GCODE
|
464
|
+
elif v in (20, 70):
|
465
|
+
# g20 is inch mode.
|
466
|
+
self.scale = UNITS_PER_INCH
|
467
|
+
self.units = "in"
|
468
|
+
elif v in (21, 71):
|
469
|
+
# g21 is mm mode. 39.3701 mils in a mm
|
470
|
+
self.scale = UNITS_PER_MM
|
471
|
+
self.units = "mm"
|
472
|
+
elif v == 28:
|
473
|
+
# Move to Origin (Home)
|
474
|
+
try:
|
475
|
+
self._driver.home()
|
476
|
+
except AttributeError:
|
477
|
+
pass
|
478
|
+
try:
|
479
|
+
self._driver.move_abs(0, 0)
|
480
|
+
except AttributeError:
|
481
|
+
pass
|
482
|
+
self.x = 0
|
483
|
+
self.y = 0
|
484
|
+
self.z = 0
|
485
|
+
elif v == 28.1:
|
486
|
+
# Set Pre-defined Location
|
487
|
+
pass
|
488
|
+
elif v == 30:
|
489
|
+
# Goto Pre-defined Position
|
490
|
+
pass
|
491
|
+
elif v == 30.1:
|
492
|
+
# Set Pre-defined Position
|
493
|
+
pass
|
494
|
+
elif v == 38.2:
|
495
|
+
# Probe towards workpiece, stop on contact. Signal error.
|
496
|
+
# Unsupported or invalid g-code command found in block.
|
497
|
+
return ERROR_UNSUPPORTED_GCODE
|
498
|
+
elif v == 38.3:
|
499
|
+
# Probe towards workpiece, stop on contact.
|
500
|
+
# Unsupported or invalid g-code command found in block.
|
501
|
+
return ERROR_UNSUPPORTED_GCODE
|
502
|
+
elif v == 38.4:
|
503
|
+
# Probe away from workpiece, signal error
|
504
|
+
pass
|
505
|
+
elif v == 38.5:
|
506
|
+
# Probe away from workpiece.
|
507
|
+
pass
|
508
|
+
elif v == 40.0:
|
509
|
+
# Compensation Off
|
510
|
+
self.compensation = False
|
511
|
+
elif v == 43.1:
|
512
|
+
pass # Dynamic tool Length offsets
|
513
|
+
elif v == 49:
|
514
|
+
# Cancel tool offset.
|
515
|
+
pass # Dynamic tool length offsets
|
516
|
+
elif v == 53:
|
517
|
+
# Absolute movement non-modal command.
|
518
|
+
pass
|
519
|
+
elif 54 <= v <= 59:
|
520
|
+
# Coord System Select
|
521
|
+
pass # Work Coordinate Systems
|
522
|
+
elif v == 61:
|
523
|
+
# Exact path control mode. GRBL required
|
524
|
+
pass
|
525
|
+
elif v == 80:
|
526
|
+
# Motion mode cancel. Canned cycle.
|
527
|
+
pass
|
528
|
+
elif v == 90:
|
529
|
+
# Set to Absolute Positioning
|
530
|
+
self.relative = False
|
531
|
+
elif v == 91:
|
532
|
+
# Set to Relative Positioning
|
533
|
+
self.relative = True
|
534
|
+
elif v == 92:
|
535
|
+
# Set Position.
|
536
|
+
# Change the current coords without moving.
|
537
|
+
pass # Coordinate Offset TODO: Implement
|
538
|
+
elif v == 92.1:
|
539
|
+
# Clear Coordinate offset set by 92.
|
540
|
+
pass # Clear Coordinate offset TODO: Implement
|
541
|
+
elif v == 93:
|
542
|
+
# Feed Rate Mode (Inverse Time Mode)
|
543
|
+
self.g93_feedrate()
|
544
|
+
elif v == 94:
|
545
|
+
# Feed Rate Mode (Units Per Minute)
|
546
|
+
self.g94_feedrate()
|
547
|
+
else:
|
548
|
+
# Unsupported or invalid g-code command found in block.
|
549
|
+
return ERROR_UNSUPPORTED_GCODE
|
550
|
+
del gc["g"]
|
551
|
+
|
552
|
+
if "comment" in gc:
|
553
|
+
if self.channel:
|
554
|
+
self.channel(f'Comment: {gc["comment"]}')
|
555
|
+
del gc["comment"]
|
556
|
+
|
557
|
+
if "f" in gc: # Feed_rate
|
558
|
+
for v in gc["f"]:
|
559
|
+
if v is None:
|
560
|
+
# Numeric value format is not valid or missing an expected value.
|
561
|
+
return ERROR_NUMERIC_VALUE_INVALID
|
562
|
+
feed_rate = self.feed_convert(v)
|
563
|
+
if self.speed != feed_rate:
|
564
|
+
self.speed = feed_rate
|
565
|
+
try:
|
566
|
+
self._driver.set("speed", v)
|
567
|
+
except AttributeError:
|
568
|
+
pass
|
569
|
+
self.plot_commit() # Speed change means plot change
|
570
|
+
del gc["f"]
|
571
|
+
if "s" in gc:
|
572
|
+
for v in gc["s"]:
|
573
|
+
if v is None:
|
574
|
+
# Numeric value format is not valid or missing an expected value.
|
575
|
+
return ERROR_NUMERIC_VALUE_INVALID
|
576
|
+
if 0.0 < v <= 1.0:
|
577
|
+
v *= 1000 # numbers between 0-1 are taken to be in range 0-1.
|
578
|
+
if self.power != v:
|
579
|
+
try:
|
580
|
+
self._driver.set("power", v)
|
581
|
+
except AttributeError:
|
582
|
+
pass
|
583
|
+
self.power = v
|
584
|
+
del gc["s"]
|
585
|
+
if "z" in gc:
|
586
|
+
oz = self.z
|
587
|
+
v = gc["z"].pop(0)
|
588
|
+
if v is None:
|
589
|
+
z = 0
|
590
|
+
else:
|
591
|
+
z = self.scale * v
|
592
|
+
if len(gc["z"]) == 0:
|
593
|
+
del gc["z"]
|
594
|
+
self.z = z
|
595
|
+
if oz != self.z:
|
596
|
+
try:
|
597
|
+
self.plot_commit() # We plot commit on z level change
|
598
|
+
self._driver.axis("z", self.z)
|
599
|
+
except AttributeError:
|
600
|
+
pass
|
601
|
+
|
602
|
+
if (
|
603
|
+
"x" in gc
|
604
|
+
or "y" in gc
|
605
|
+
or ("i" in gc or "j" in gc and self.move_mode in (2, 3))
|
606
|
+
):
|
607
|
+
ox = self.x
|
608
|
+
oy = self.y
|
609
|
+
if "x" in gc:
|
610
|
+
x = gc["x"].pop(0)
|
611
|
+
if x is None:
|
612
|
+
x = 0
|
613
|
+
else:
|
614
|
+
x *= self.scale
|
615
|
+
if len(gc["x"]) == 0:
|
616
|
+
del gc["x"]
|
617
|
+
else:
|
618
|
+
if self.relative:
|
619
|
+
x = 0
|
620
|
+
else:
|
621
|
+
x = self.x
|
622
|
+
if "y" in gc:
|
623
|
+
y = gc["y"].pop(0)
|
624
|
+
if y is None:
|
625
|
+
y = 0
|
626
|
+
else:
|
627
|
+
y *= self.scale
|
628
|
+
if len(gc["y"]) == 0:
|
629
|
+
del gc["y"]
|
630
|
+
else:
|
631
|
+
if self.relative:
|
632
|
+
y = 0
|
633
|
+
else:
|
634
|
+
y = self.y
|
635
|
+
|
636
|
+
if self.relative:
|
637
|
+
nx = self.x + x
|
638
|
+
ny = self.y + y
|
639
|
+
else:
|
640
|
+
nx = x
|
641
|
+
ny = y
|
642
|
+
if self.move_mode == 0:
|
643
|
+
self.plot_commit()
|
644
|
+
if self.program_mode:
|
645
|
+
self.plot_location(nx, ny, 0)
|
646
|
+
else:
|
647
|
+
try:
|
648
|
+
self._driver.move_abs(nx, ny)
|
649
|
+
self.x = nx
|
650
|
+
self.y = ny
|
651
|
+
except AttributeError:
|
652
|
+
pass
|
653
|
+
elif self.move_mode == 1:
|
654
|
+
self.plot_location(nx, ny, self.power)
|
655
|
+
elif self.move_mode in (2, 3):
|
656
|
+
# 2 = CW ARC
|
657
|
+
# 3 = CCW ARC
|
658
|
+
|
659
|
+
cx = ox
|
660
|
+
cy = oy
|
661
|
+
if "i" in gc:
|
662
|
+
ix = gc["i"].pop(0) # * self.scale
|
663
|
+
cx += ix
|
664
|
+
if "j" in gc:
|
665
|
+
jy = gc["j"].pop(0) # * self.scale
|
666
|
+
cy += jy
|
667
|
+
if "r" in gc:
|
668
|
+
# Strictly speaking this uses the R parameter, but that wasn't coded.
|
669
|
+
arc = Arc(
|
670
|
+
start=(ox, oy),
|
671
|
+
center=(cx, cy),
|
672
|
+
end=(nx, ny),
|
673
|
+
ccw=self.move_mode == 3,
|
674
|
+
)
|
675
|
+
for p in range(self._interpolate + 1):
|
676
|
+
x, y = arc.point(p / self._interpolate)
|
677
|
+
self.plot_location(x, y, self.power)
|
678
|
+
else:
|
679
|
+
arc = Arc(
|
680
|
+
start=(ox, oy),
|
681
|
+
center=(cx, cy),
|
682
|
+
end=(nx, ny),
|
683
|
+
ccw=self.move_mode == 3,
|
684
|
+
)
|
685
|
+
for p in range(self._interpolate + 1):
|
686
|
+
x, y = arc.point(p / self._interpolate)
|
687
|
+
self.plot_location(x, y, self.power)
|
688
|
+
return OKAY
|
689
|
+
|
690
|
+
def plot_location(self, x, y, power):
|
691
|
+
"""
|
692
|
+
Adds this particular location to the current plotcut.
|
693
|
+
|
694
|
+
Or, starts a new plotcut if one is not already started.
|
695
|
+
|
696
|
+
First plotcut is a 0-power move to the current position. X and Y are set to plotted location
|
697
|
+
|
698
|
+
@param x:
|
699
|
+
@param y:
|
700
|
+
@param power:
|
701
|
+
@return:
|
702
|
+
"""
|
703
|
+
matrix = self.units_to_device_matrix
|
704
|
+
if matrix is None:
|
705
|
+
# Using job for something other than point plotting
|
706
|
+
return
|
707
|
+
if power is None:
|
708
|
+
power = 1000
|
709
|
+
power = min(1000, power)
|
710
|
+
if self.plotcut is None:
|
711
|
+
ox, oy = matrix.transform_point([self.x, self.y])
|
712
|
+
self.plotcut = PlotCut(settings={"speed": self.speed})
|
713
|
+
self.plotcut.plot_init(int(round(ox)), int(round(oy)))
|
714
|
+
tx, ty = matrix.transform_point([x, y])
|
715
|
+
self.plotcut.plot_append(int(round(tx)), int(round(ty)), (power / 1000.0))
|
716
|
+
if not self.program_mode:
|
717
|
+
self.plot_commit()
|
718
|
+
self.x = x
|
719
|
+
self.y = y
|
720
|
+
|
721
|
+
def plot_commit(self):
|
722
|
+
"""
|
723
|
+
Force commits the old plotcut and unsets the current plotcut.
|
724
|
+
|
725
|
+
@return:
|
726
|
+
"""
|
727
|
+
if self.plotcut is None:
|
728
|
+
return
|
729
|
+
self.plot(self.plotcut)
|
730
|
+
self.plotcut = None
|
731
|
+
|
732
|
+
def plot(self, plot):
|
733
|
+
try:
|
734
|
+
self._driver.plot(plot)
|
735
|
+
except AttributeError:
|
736
|
+
pass
|
737
|
+
if not self.program_mode:
|
738
|
+
# If we plotted this, and we aren't in program mode execute all of these commands right away
|
739
|
+
try:
|
740
|
+
self._driver.plot_start()
|
741
|
+
except AttributeError:
|
742
|
+
pass
|
743
|
+
|
744
|
+
def g93_feedrate(self):
|
745
|
+
"""
|
746
|
+
Feed Rate in Minutes / Unit
|
747
|
+
G93 - is Inverse Time Mode. In inverse time feed rate mode, an F word means the move
|
748
|
+
should be completed in [one divided by the F number] minutes. For example, if the
|
749
|
+
F number is 2.0, the move should be completed in half a minute.
|
750
|
+
When the inverse time feed rate mode is active, an F word must appear on every line
|
751
|
+
which has a G1, G2, or G3 motion, and an F word on a line that does not have
|
752
|
+
G1, G2, or G3 is ignored. Being in inverse time feed rate mode does not
|
753
|
+
affect G0 (rapid move) motions.
|
754
|
+
@return:
|
755
|
+
"""
|
756
|
+
|
757
|
+
if self.scale == UNITS_PER_INCH:
|
758
|
+
self.feed_convert = lambda s: (60.0 * self.scale / UNITS_PER_INCH) / s
|
759
|
+
self.feed_invert = lambda s: (60.0 * UNITS_PER_INCH / self.scale) / s
|
760
|
+
self.feed_desc = "min/inch"
|
761
|
+
else:
|
762
|
+
self.feed_convert = lambda s: (60.0 * self.scale / UNITS_PER_MM) / s
|
763
|
+
self.feed_invert = lambda s: (60.0 * UNITS_PER_MM / self.scale) / s
|
764
|
+
self.feed_desc = "min/mm"
|
765
|
+
|
766
|
+
def g94_feedrate(self):
|
767
|
+
"""
|
768
|
+
Feed Rate in Units / Minute
|
769
|
+
G94 - is Units per Minute Mode. In units per minute feed mode, an F word is interpreted
|
770
|
+
to mean the controlled point should move at a certain number of inches per minute,
|
771
|
+
millimeters per minute, or degrees per minute, depending upon what length units
|
772
|
+
are being used and which axis or axes are moving.
|
773
|
+
@return:
|
774
|
+
"""
|
775
|
+
|
776
|
+
if self.scale == UNITS_PER_INCH:
|
777
|
+
self.feed_convert = lambda s: s / ((self.scale / UNITS_PER_INCH) * 60.0)
|
778
|
+
self.feed_invert = lambda s: s * ((self.scale / UNITS_PER_INCH) * 60.0)
|
779
|
+
self.feed_desc = "inch/min"
|
780
|
+
else:
|
781
|
+
self.feed_convert = lambda s: s / ((self.scale / UNITS_PER_MM) * 60.0)
|
782
|
+
self.feed_invert = lambda s: s * ((self.scale / UNITS_PER_MM) * 60.0)
|
783
|
+
self.feed_desc = "mm/min"
|