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/lihuiyu/driver.py
CHANGED
@@ -1,1372 +1,1466 @@
|
|
1
|
-
"""
|
2
|
-
Lihuiyu Driver
|
3
|
-
|
4
|
-
Governs the generic commands issued by laserjob and spooler and converts that into regular LHYMicro-GL output.
|
5
|
-
|
6
|
-
This generated data is then sent to the controller, which could be a network connection, usb, or mock depending on the
|
7
|
-
selected output.
|
8
|
-
"""
|
9
|
-
|
10
|
-
import math
|
11
|
-
import time
|
12
|
-
|
13
|
-
from meerk40t.tools.zinglplotter import ZinglPlotter
|
14
|
-
|
15
|
-
from ..core.cutcode.dwellcut import DwellCut
|
16
|
-
from ..core.cutcode.gotocut import GotoCut
|
17
|
-
from ..core.cutcode.homecut import HomeCut
|
18
|
-
from ..core.cutcode.inputcut import InputCut
|
19
|
-
from ..core.cutcode.outputcut import OutputCut
|
20
|
-
from ..core.cutcode.plotcut import PlotCut
|
21
|
-
from ..core.cutcode.waitcut import WaitCut
|
22
|
-
from ..core.parameters import Parameters
|
23
|
-
from ..core.plotplanner import PlotPlanner, grouped
|
24
|
-
from ..device.basedevice import (
|
25
|
-
DRIVER_STATE_FINISH,
|
26
|
-
DRIVER_STATE_MODECHANGE,
|
27
|
-
DRIVER_STATE_PROGRAM,
|
28
|
-
DRIVER_STATE_RAPID,
|
29
|
-
DRIVER_STATE_RASTER,
|
30
|
-
PLOT_AXIS,
|
31
|
-
PLOT_DIRECTION,
|
32
|
-
PLOT_FINISH,
|
33
|
-
PLOT_JOG,
|
34
|
-
PLOT_RAPID,
|
35
|
-
PLOT_SETTING,
|
36
|
-
)
|
37
|
-
from .
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
b"
|
42
|
-
b"
|
43
|
-
b"
|
44
|
-
b"
|
45
|
-
b"
|
46
|
-
b"
|
47
|
-
b"
|
48
|
-
b"
|
49
|
-
b"
|
50
|
-
b"
|
51
|
-
b"
|
52
|
-
b"
|
53
|
-
b"
|
54
|
-
b"
|
55
|
-
b"
|
56
|
-
b"
|
57
|
-
b"
|
58
|
-
b"
|
59
|
-
b"
|
60
|
-
b"
|
61
|
-
b"
|
62
|
-
b"
|
63
|
-
b"
|
64
|
-
b"
|
65
|
-
b"
|
66
|
-
b"
|
67
|
-
b"|
|
68
|
-
b"|
|
69
|
-
b"|
|
70
|
-
b"|
|
71
|
-
b"|
|
72
|
-
b"|
|
73
|
-
b"|
|
74
|
-
b"|
|
75
|
-
b"|
|
76
|
-
b"|
|
77
|
-
b"|
|
78
|
-
b"|
|
79
|
-
b"|
|
80
|
-
b"|
|
81
|
-
b"|
|
82
|
-
b"|
|
83
|
-
b"|
|
84
|
-
b"|
|
85
|
-
b"|
|
86
|
-
b"|
|
87
|
-
b"|
|
88
|
-
b"|
|
89
|
-
b"|
|
90
|
-
b"|
|
91
|
-
b"|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
v
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
self.
|
118
|
-
self.
|
119
|
-
self.
|
120
|
-
self.
|
121
|
-
self.
|
122
|
-
self.
|
123
|
-
|
124
|
-
|
125
|
-
self.
|
126
|
-
self.
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
self.
|
132
|
-
self.
|
133
|
-
self.
|
134
|
-
|
135
|
-
|
136
|
-
self.
|
137
|
-
|
138
|
-
|
139
|
-
self.
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
self.
|
144
|
-
self.
|
145
|
-
|
146
|
-
self.
|
147
|
-
self.
|
148
|
-
self.
|
149
|
-
self.
|
150
|
-
|
151
|
-
self.
|
152
|
-
self.
|
153
|
-
|
154
|
-
self.
|
155
|
-
self.
|
156
|
-
self.
|
157
|
-
self.
|
158
|
-
|
159
|
-
self.
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
self.
|
196
|
-
|
197
|
-
def
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
if
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
@param
|
244
|
-
@
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
self.
|
261
|
-
elif key == "
|
262
|
-
self.
|
263
|
-
|
264
|
-
self.
|
265
|
-
|
266
|
-
|
267
|
-
""
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
state_major = "
|
287
|
-
state_minor = "
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
self.
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
self(
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
""
|
323
|
-
self.
|
324
|
-
self.
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
self(
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
@param
|
357
|
-
@
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
def
|
364
|
-
"""
|
365
|
-
Requests laser move
|
366
|
-
|
367
|
-
@param
|
368
|
-
@param
|
369
|
-
@return:
|
370
|
-
"""
|
371
|
-
|
372
|
-
self.rapid_mode()
|
373
|
-
self.
|
374
|
-
|
375
|
-
def
|
376
|
-
"""
|
377
|
-
Requests
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
@
|
382
|
-
|
383
|
-
|
384
|
-
self.rapid_mode()
|
385
|
-
self.
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
@return:
|
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
|
-
|
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
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
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
|
-
self.
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
self.
|
521
|
-
self.
|
522
|
-
if self.
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
speed_code =
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
self.
|
584
|
-
|
585
|
-
|
586
|
-
self.
|
587
|
-
self.
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
speed_code =
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
self.
|
607
|
-
|
608
|
-
|
609
|
-
""
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
""
|
615
|
-
if self.
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
)
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
self.
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
"""
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
"""
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
self.
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
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
|
-
|
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
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
def
|
770
|
-
"""
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
@
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
"""
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
self.
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
self.
|
998
|
-
self.
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
if self.
|
1036
|
-
self.
|
1037
|
-
|
1038
|
-
self.
|
1039
|
-
|
1040
|
-
def
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
self.
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
self.
|
1098
|
-
if dy
|
1099
|
-
self.
|
1100
|
-
|
1101
|
-
|
1102
|
-
self
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
self.
|
1108
|
-
|
1109
|
-
def
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
)
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
self.
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
if
|
1210
|
-
self
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
self.
|
1269
|
-
self.
|
1270
|
-
self.
|
1271
|
-
|
1272
|
-
def
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
self(
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
self.
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
self.
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
self.
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1
|
+
"""
|
2
|
+
Lihuiyu Driver
|
3
|
+
|
4
|
+
Governs the generic commands issued by laserjob and spooler and converts that into regular LHYMicro-GL output.
|
5
|
+
|
6
|
+
This generated data is then sent to the controller, which could be a network connection, usb, or mock depending on the
|
7
|
+
selected output.
|
8
|
+
"""
|
9
|
+
|
10
|
+
import math
|
11
|
+
import time
|
12
|
+
|
13
|
+
from meerk40t.tools.zinglplotter import ZinglPlotter
|
14
|
+
|
15
|
+
from ..core.cutcode.dwellcut import DwellCut
|
16
|
+
from ..core.cutcode.gotocut import GotoCut
|
17
|
+
from ..core.cutcode.homecut import HomeCut
|
18
|
+
from ..core.cutcode.inputcut import InputCut
|
19
|
+
from ..core.cutcode.outputcut import OutputCut
|
20
|
+
from ..core.cutcode.plotcut import PlotCut
|
21
|
+
from ..core.cutcode.waitcut import WaitCut
|
22
|
+
from ..core.parameters import Parameters
|
23
|
+
from ..core.plotplanner import PlotPlanner, grouped
|
24
|
+
from ..device.basedevice import (
|
25
|
+
DRIVER_STATE_FINISH,
|
26
|
+
DRIVER_STATE_MODECHANGE,
|
27
|
+
DRIVER_STATE_PROGRAM,
|
28
|
+
DRIVER_STATE_RAPID,
|
29
|
+
DRIVER_STATE_RASTER,
|
30
|
+
PLOT_AXIS,
|
31
|
+
PLOT_DIRECTION,
|
32
|
+
PLOT_FINISH,
|
33
|
+
PLOT_JOG,
|
34
|
+
PLOT_RAPID,
|
35
|
+
PLOT_SETTING,
|
36
|
+
)
|
37
|
+
from ..tools.geomstr import Geomstr
|
38
|
+
from .laserspeed import LaserSpeed
|
39
|
+
|
40
|
+
distance_lookup = [
|
41
|
+
b"",
|
42
|
+
b"a",
|
43
|
+
b"b",
|
44
|
+
b"c",
|
45
|
+
b"d",
|
46
|
+
b"e",
|
47
|
+
b"f",
|
48
|
+
b"g",
|
49
|
+
b"h",
|
50
|
+
b"i",
|
51
|
+
b"j",
|
52
|
+
b"k",
|
53
|
+
b"l",
|
54
|
+
b"m",
|
55
|
+
b"n",
|
56
|
+
b"o",
|
57
|
+
b"p",
|
58
|
+
b"q",
|
59
|
+
b"r",
|
60
|
+
b"s",
|
61
|
+
b"t",
|
62
|
+
b"u",
|
63
|
+
b"v",
|
64
|
+
b"w",
|
65
|
+
b"x",
|
66
|
+
b"y",
|
67
|
+
b"|a",
|
68
|
+
b"|b",
|
69
|
+
b"|c",
|
70
|
+
b"|d",
|
71
|
+
b"|e",
|
72
|
+
b"|f",
|
73
|
+
b"|g",
|
74
|
+
b"|h",
|
75
|
+
b"|i",
|
76
|
+
b"|j",
|
77
|
+
b"|k",
|
78
|
+
b"|l",
|
79
|
+
b"|m",
|
80
|
+
b"|n",
|
81
|
+
b"|o",
|
82
|
+
b"|p",
|
83
|
+
b"|q",
|
84
|
+
b"|r",
|
85
|
+
b"|s",
|
86
|
+
b"|t",
|
87
|
+
b"|u",
|
88
|
+
b"|v",
|
89
|
+
b"|w",
|
90
|
+
b"|x",
|
91
|
+
b"|y",
|
92
|
+
b"|z",
|
93
|
+
]
|
94
|
+
|
95
|
+
|
96
|
+
def lhymicro_distance(v):
|
97
|
+
if v < 0:
|
98
|
+
raise ValueError("Cannot permit negative values.")
|
99
|
+
dist = b""
|
100
|
+
if v >= 255:
|
101
|
+
zs = int(v / 255)
|
102
|
+
v %= 255
|
103
|
+
dist += b"z" * zs
|
104
|
+
if v >= 52:
|
105
|
+
return dist + b"%03d" % v
|
106
|
+
return dist + distance_lookup[v]
|
107
|
+
|
108
|
+
|
109
|
+
class LihuiyuDriver(Parameters):
|
110
|
+
"""
|
111
|
+
LihuiyuDriver provides Lihuiyu specific coding for elements and sends it to the backend
|
112
|
+
to write to the usb.
|
113
|
+
"""
|
114
|
+
|
115
|
+
def __init__(self, service, *args, **kwargs):
|
116
|
+
super().__init__()
|
117
|
+
self.service = service
|
118
|
+
self.name = str(self.service)
|
119
|
+
self._topward = False
|
120
|
+
self._leftward = False
|
121
|
+
self._x_engaged = False
|
122
|
+
self._y_engaged = False
|
123
|
+
self._horizontal_major = False
|
124
|
+
|
125
|
+
self._request_leftward = None
|
126
|
+
self._request_topward = None
|
127
|
+
self._request_horizontal_major = None
|
128
|
+
|
129
|
+
self.out_pipe = None
|
130
|
+
|
131
|
+
self.process_item = None
|
132
|
+
self.spooled_item = None
|
133
|
+
self.holds = []
|
134
|
+
self.temp_holds = []
|
135
|
+
|
136
|
+
self.native_x = 0
|
137
|
+
self.native_y = 0
|
138
|
+
|
139
|
+
self.plot_planner = PlotPlanner(self.settings)
|
140
|
+
self.plot_attribute_update()
|
141
|
+
|
142
|
+
self.plot_data = None
|
143
|
+
self._queue_current = 0
|
144
|
+
self._queue_total = 0
|
145
|
+
|
146
|
+
self.state = DRIVER_STATE_RAPID
|
147
|
+
self.properties = 0
|
148
|
+
self.is_relative = False
|
149
|
+
self.laser = False
|
150
|
+
self._thread = None
|
151
|
+
self._shutdown = False
|
152
|
+
self.last_fetch = None
|
153
|
+
|
154
|
+
self.CODE_RIGHT = b"B"
|
155
|
+
self.CODE_LEFT = b"T"
|
156
|
+
self.CODE_TOP = b"L"
|
157
|
+
self.CODE_BOTTOM = b"R"
|
158
|
+
self.CODE_ANGLE = b"M"
|
159
|
+
self.CODE_LASER_ON = b"D"
|
160
|
+
self.CODE_LASER_OFF = b"U"
|
161
|
+
|
162
|
+
self._signal_updates = self.service.setting(bool, "signal_updates", True)
|
163
|
+
|
164
|
+
self.paused = False
|
165
|
+
|
166
|
+
def primary_hold():
|
167
|
+
if self.out_pipe is None:
|
168
|
+
return True
|
169
|
+
if hasattr(self.out_pipe, "is_shutdown") and self.out_pipe.is_shutdown:
|
170
|
+
raise ConnectionAbortedError("Cannot hold for a shutdown pipe.")
|
171
|
+
try:
|
172
|
+
buffer = len(self.out_pipe)
|
173
|
+
except TypeError:
|
174
|
+
buffer = 0
|
175
|
+
return self.service.buffer_limit and buffer > self.service.buffer_max
|
176
|
+
|
177
|
+
self.holds.append(primary_hold)
|
178
|
+
|
179
|
+
# Step amount expected of the current operation
|
180
|
+
self._raster_step_float = 0
|
181
|
+
|
182
|
+
# Step amount is the current correctly set step amount in the controller.
|
183
|
+
self._raster_step_g_value = 0
|
184
|
+
|
185
|
+
# Step index of the current step taken for unidirectional
|
186
|
+
self._raster_step_swing_index = 0
|
187
|
+
|
188
|
+
# Step total the count for fractional step amounts
|
189
|
+
self._raster_step_fractional_remainder = 0.0
|
190
|
+
|
191
|
+
def __repr__(self):
|
192
|
+
return f"LihuiyuDriver({self.name})"
|
193
|
+
|
194
|
+
def __call__(self, e):
|
195
|
+
self.out_pipe.write(e)
|
196
|
+
|
197
|
+
def get_internal_queue_status(self):
|
198
|
+
return self._queue_current, self._queue_total
|
199
|
+
|
200
|
+
def _set_queue_status(self, current, total):
|
201
|
+
self._queue_current = current
|
202
|
+
self._queue_total = total
|
203
|
+
|
204
|
+
def plot_attribute_update(self):
|
205
|
+
self.plot_planner.force_shift = self.service.plot_shift
|
206
|
+
self.plot_planner.phase_type = self.service.plot_phase_type
|
207
|
+
self.plot_planner.phase_value = self.service.plot_phase_value
|
208
|
+
|
209
|
+
def hold_work(self, priority):
|
210
|
+
"""
|
211
|
+
Holds are criteria to use to pause the data interpretation. These halt the production of new data until the
|
212
|
+
criteria is met. A hold is constant and will always halt the data while true. A temp_hold will be removed
|
213
|
+
as soon as it does not hold the data.
|
214
|
+
|
215
|
+
@return: Whether data interpretation should hold.
|
216
|
+
"""
|
217
|
+
if priority > 0:
|
218
|
+
# Don't hold realtime work.
|
219
|
+
return False
|
220
|
+
|
221
|
+
temp_hold = False
|
222
|
+
fail_hold = False
|
223
|
+
for i, hold in enumerate(self.temp_holds):
|
224
|
+
if not hold():
|
225
|
+
self.temp_holds[i] = None
|
226
|
+
fail_hold = True
|
227
|
+
else:
|
228
|
+
temp_hold = True
|
229
|
+
if fail_hold:
|
230
|
+
self.temp_holds = [hold for hold in self.temp_holds if hold is not None]
|
231
|
+
if temp_hold:
|
232
|
+
return True
|
233
|
+
for hold in self.holds:
|
234
|
+
if hold():
|
235
|
+
return True
|
236
|
+
return False
|
237
|
+
|
238
|
+
def get(self, key, default=None):
|
239
|
+
"""
|
240
|
+
Required.
|
241
|
+
|
242
|
+
@param key: Key to get.
|
243
|
+
@param default: Default value to use.
|
244
|
+
@return:
|
245
|
+
"""
|
246
|
+
return self.settings.get(key, default=default)
|
247
|
+
|
248
|
+
def set(self, key, value):
|
249
|
+
"""
|
250
|
+
Required.
|
251
|
+
|
252
|
+
Sets a laser parameter this could be speed, power, wobble, number_of_unicorns, or any unknown parameters for
|
253
|
+
yet to be written drivers.
|
254
|
+
|
255
|
+
@param key:
|
256
|
+
@param value:
|
257
|
+
@return:
|
258
|
+
"""
|
259
|
+
if key == "power":
|
260
|
+
self._set_power(value)
|
261
|
+
elif key == "ppi":
|
262
|
+
self._set_power(value)
|
263
|
+
elif key == "pwm":
|
264
|
+
self._set_power(value)
|
265
|
+
elif key == "overscan":
|
266
|
+
self._set_overscan(value)
|
267
|
+
elif key == "acceleration":
|
268
|
+
self._set_acceleration(value)
|
269
|
+
elif key == "relative":
|
270
|
+
self.is_relative = value
|
271
|
+
elif key == "d_ratio":
|
272
|
+
self._set_d_ratio(value)
|
273
|
+
elif key == "step":
|
274
|
+
self._set_step(*value)
|
275
|
+
else:
|
276
|
+
self.settings[key] = value
|
277
|
+
|
278
|
+
def status(self):
|
279
|
+
"""
|
280
|
+
Wants a status report of what the driver is doing.
|
281
|
+
@return:
|
282
|
+
"""
|
283
|
+
state_major = "idle"
|
284
|
+
state_minor = "idle"
|
285
|
+
if self.state == DRIVER_STATE_RAPID:
|
286
|
+
state_major = "idle"
|
287
|
+
state_minor = "idle"
|
288
|
+
elif self.state == DRIVER_STATE_FINISH:
|
289
|
+
state_major = "idle"
|
290
|
+
state_minor = "finished"
|
291
|
+
elif self.state == DRIVER_STATE_PROGRAM:
|
292
|
+
state_major = "busy"
|
293
|
+
state_minor = "program"
|
294
|
+
elif self.state == DRIVER_STATE_RASTER:
|
295
|
+
state_major = "busy"
|
296
|
+
state_minor = "raster"
|
297
|
+
elif self.state == DRIVER_STATE_MODECHANGE:
|
298
|
+
state_major = "busy"
|
299
|
+
state_minor = "changing"
|
300
|
+
return (self.native_x, self.native_y), state_major, state_minor
|
301
|
+
|
302
|
+
def pause(self, *values):
|
303
|
+
"""
|
304
|
+
Asks that the laser be paused.
|
305
|
+
|
306
|
+
@return:
|
307
|
+
"""
|
308
|
+
self(b"~PN!\n~")
|
309
|
+
self.paused = True
|
310
|
+
self.service.signal("pause")
|
311
|
+
|
312
|
+
def resume(self, *values):
|
313
|
+
"""
|
314
|
+
Asks that the laser be resumed.
|
315
|
+
|
316
|
+
To work this command should usually be put into the realtime work queue for the laser, without that it will
|
317
|
+
be paused and unable to process the resume.
|
318
|
+
|
319
|
+
@param values:
|
320
|
+
@return:
|
321
|
+
"""
|
322
|
+
self(b"~PN&\n~")
|
323
|
+
self.paused = False
|
324
|
+
self.service.signal("pause")
|
325
|
+
|
326
|
+
def reset(self):
|
327
|
+
"""
|
328
|
+
This command asks that this device be emergency stopped and reset. Usually that queue data from the spooler be
|
329
|
+
deleted.
|
330
|
+
|
331
|
+
Asks that the device resets, and clears all current work.
|
332
|
+
|
333
|
+
@return:
|
334
|
+
"""
|
335
|
+
self.service.spooler.clear_queue()
|
336
|
+
self.plot_planner.clear()
|
337
|
+
self.spooled_item = None
|
338
|
+
self.temp_holds.clear()
|
339
|
+
|
340
|
+
self.service.signal("pipe;buffer", 0)
|
341
|
+
self(b"~I*\n~")
|
342
|
+
self._reset_modes()
|
343
|
+
self.state = DRIVER_STATE_RAPID
|
344
|
+
self.paused = False
|
345
|
+
self.service.signal("pause")
|
346
|
+
|
347
|
+
def abort(self):
|
348
|
+
self(b"I\n")
|
349
|
+
|
350
|
+
def blob(self, blob_type, data):
|
351
|
+
"""
|
352
|
+
Blob sends a data blob. This is native code data of the give type. For example in a ruida device it might be a
|
353
|
+
bunch of .rd code, or Lihuiyu device it could be .egv code. It's a method of sending pre-chewed data to the
|
354
|
+
device.
|
355
|
+
|
356
|
+
@param blob_type:
|
357
|
+
@param data:
|
358
|
+
@return:
|
359
|
+
"""
|
360
|
+
if blob_type == "egv":
|
361
|
+
self(data)
|
362
|
+
|
363
|
+
def move_abs(self, x, y):
|
364
|
+
"""
|
365
|
+
Requests laser move to absolute position x, y in physical units
|
366
|
+
|
367
|
+
@param x:
|
368
|
+
@param y:
|
369
|
+
@return:
|
370
|
+
"""
|
371
|
+
x, y = self.service.view.position(x, y)
|
372
|
+
self.rapid_mode()
|
373
|
+
self._move_absolute(int(round(x)), int(round(y)))
|
374
|
+
|
375
|
+
def move_rel(self, dx, dy):
|
376
|
+
"""
|
377
|
+
Requests laser move relative position dx, dy in physical units
|
378
|
+
|
379
|
+
@param dx:
|
380
|
+
@param dy:
|
381
|
+
@return:
|
382
|
+
"""
|
383
|
+
unit_dx, unit_dy = self.service.view.position(dx, dy, vector=True)
|
384
|
+
self.rapid_mode()
|
385
|
+
self._move_relative(unit_dx, unit_dy)
|
386
|
+
|
387
|
+
def dwell(self, time_in_ms):
|
388
|
+
"""
|
389
|
+
Requests that the laser fire in place for the given time period. This could be done in a series of commands,
|
390
|
+
move to a location, turn laser on, wait, turn laser off. However, some drivers have specific laser-in-place
|
391
|
+
commands so calling dwell is preferred.
|
392
|
+
|
393
|
+
@param time_in_ms:
|
394
|
+
@return:
|
395
|
+
"""
|
396
|
+
self.rapid_mode()
|
397
|
+
self.wait_finish()
|
398
|
+
self.laser_on() # This can't be sent early since these are timed operations.
|
399
|
+
self.wait(time_in_ms)
|
400
|
+
self.laser_off()
|
401
|
+
|
402
|
+
def laser_off(self):
|
403
|
+
"""
|
404
|
+
Turn laser off in place.
|
405
|
+
|
406
|
+
@return:
|
407
|
+
"""
|
408
|
+
if not self.laser:
|
409
|
+
return False
|
410
|
+
if self.state == DRIVER_STATE_RAPID:
|
411
|
+
self(b"I")
|
412
|
+
self(self.CODE_LASER_OFF)
|
413
|
+
self(b"S1P\n")
|
414
|
+
if not self.service.autolock:
|
415
|
+
self(b"IS2P\n")
|
416
|
+
elif self.state in (DRIVER_STATE_PROGRAM, DRIVER_STATE_RASTER):
|
417
|
+
self(self.CODE_LASER_OFF)
|
418
|
+
elif self.state == DRIVER_STATE_FINISH:
|
419
|
+
self(self.CODE_LASER_OFF)
|
420
|
+
self(b"N")
|
421
|
+
self.laser = False
|
422
|
+
return True
|
423
|
+
|
424
|
+
def laser_on(self):
|
425
|
+
"""
|
426
|
+
Turn laser on in place.
|
427
|
+
|
428
|
+
@return:
|
429
|
+
"""
|
430
|
+
if self.laser:
|
431
|
+
return False
|
432
|
+
if self.state == DRIVER_STATE_RAPID:
|
433
|
+
self(b"I")
|
434
|
+
self(self.CODE_LASER_ON)
|
435
|
+
self(b"S1P\n")
|
436
|
+
if not self.service.autolock:
|
437
|
+
self(b"IS2P\n")
|
438
|
+
elif self.state in (DRIVER_STATE_PROGRAM, DRIVER_STATE_RASTER):
|
439
|
+
self(self.CODE_LASER_ON)
|
440
|
+
elif self.state == DRIVER_STATE_FINISH:
|
441
|
+
self(self.CODE_LASER_ON)
|
442
|
+
self(b"N")
|
443
|
+
self.laser = True
|
444
|
+
return True
|
445
|
+
|
446
|
+
def rapid_mode(self, *values):
|
447
|
+
"""
|
448
|
+
Rapid mode sets the laser to rapid state. This is usually moving the laser around without it executing a large
|
449
|
+
batch of commands.
|
450
|
+
|
451
|
+
@param values:
|
452
|
+
@return:
|
453
|
+
"""
|
454
|
+
if self.state == DRIVER_STATE_RAPID:
|
455
|
+
return
|
456
|
+
if self.state == DRIVER_STATE_FINISH:
|
457
|
+
self(b"S1P\n")
|
458
|
+
if not self.service.autolock:
|
459
|
+
self(b"IS2P\n")
|
460
|
+
elif self.state in (
|
461
|
+
DRIVER_STATE_PROGRAM,
|
462
|
+
DRIVER_STATE_RASTER,
|
463
|
+
DRIVER_STATE_MODECHANGE,
|
464
|
+
):
|
465
|
+
self(b"FNSE-\n")
|
466
|
+
self.laser = False
|
467
|
+
self.state = DRIVER_STATE_RAPID
|
468
|
+
|
469
|
+
def finished_mode(self, *values):
|
470
|
+
"""
|
471
|
+
Finished mode is after a large batch of jobs is done. A transition to finished may require the laser process
|
472
|
+
all the data in the buffer.
|
473
|
+
|
474
|
+
@param values:
|
475
|
+
@return:
|
476
|
+
"""
|
477
|
+
if self.state == DRIVER_STATE_FINISH:
|
478
|
+
return
|
479
|
+
if self.state in (
|
480
|
+
DRIVER_STATE_PROGRAM,
|
481
|
+
DRIVER_STATE_RASTER,
|
482
|
+
DRIVER_STATE_MODECHANGE,
|
483
|
+
):
|
484
|
+
self(b"@NSE")
|
485
|
+
self.laser = False
|
486
|
+
elif self.state == DRIVER_STATE_RAPID:
|
487
|
+
self(b"I")
|
488
|
+
self.state = DRIVER_STATE_FINISH
|
489
|
+
|
490
|
+
def raster_mode(self, *values, dx=0, dy=0):
|
491
|
+
"""
|
492
|
+
Raster mode runs in either `G0xx` stepping mode. It is only intended to move horizontal or
|
493
|
+
vertical rastering, usually at a high speed. Accel twitches are required for this mode.
|
494
|
+
|
495
|
+
@param values:
|
496
|
+
@param dx: movement during raster mode switch
|
497
|
+
@param dy: movement during raster mode switch
|
498
|
+
@return:
|
499
|
+
"""
|
500
|
+
if self.raster_step_y == 0 and self.raster_step_x == 0:
|
501
|
+
# This is not properly set raster mode.
|
502
|
+
self.program_mode(*values, dx=dx, dy=dy)
|
503
|
+
return
|
504
|
+
if self.state == DRIVER_STATE_RASTER:
|
505
|
+
return
|
506
|
+
self.finished_mode()
|
507
|
+
|
508
|
+
horizontal = self.raster_step_y != 0
|
509
|
+
self._request_horizontal_major = horizontal
|
510
|
+
|
511
|
+
self._raster_step_swing_index = 0
|
512
|
+
self._raster_step_float = (
|
513
|
+
self.raster_step_y if horizontal else self.raster_step_x
|
514
|
+
)
|
515
|
+
if self._raster_step_float is None:
|
516
|
+
self._raster_step_float = 1
|
517
|
+
self._raster_step_g_value = int(math.floor(self._raster_step_float))
|
518
|
+
|
519
|
+
if self._request_leftward is not None:
|
520
|
+
self._leftward = self._request_leftward
|
521
|
+
self._request_leftward = None
|
522
|
+
if self._request_topward is not None:
|
523
|
+
self._topward = self._request_topward
|
524
|
+
self._request_topward = None
|
525
|
+
if self._request_horizontal_major is not None:
|
526
|
+
self._horizontal_major = self._request_horizontal_major
|
527
|
+
self._request_horizontal_major = None
|
528
|
+
|
529
|
+
if self.service.strict:
|
530
|
+
# Override requested or current values only use core initial values.
|
531
|
+
self._leftward = False
|
532
|
+
self._topward = False
|
533
|
+
self._horizontal_major = False
|
534
|
+
if self.bidirectional:
|
535
|
+
# Bidirectional (step on forward/back swing - rasters both directions)
|
536
|
+
raster_step_value = self._raster_step_g_value
|
537
|
+
else:
|
538
|
+
# Unidirectional (step on forward swing - rasters only going forward)
|
539
|
+
raster_step_value = self._raster_step_g_value, 0
|
540
|
+
speed_code = LaserSpeed(
|
541
|
+
self.service.board,
|
542
|
+
self.speed,
|
543
|
+
raster_step=raster_step_value,
|
544
|
+
d_ratio=self.implicit_d_ratio,
|
545
|
+
acceleration=self.implicit_accel,
|
546
|
+
fix_limit=True,
|
547
|
+
fix_lows=True,
|
548
|
+
suffix_c=False,
|
549
|
+
fix_speeds=self.service.fix_speeds,
|
550
|
+
raster_horizontal=horizontal,
|
551
|
+
).speedcode
|
552
|
+
speed_code = bytes(speed_code, "utf8")
|
553
|
+
self(speed_code)
|
554
|
+
self._goto_xy(dx, dy)
|
555
|
+
self(b"N")
|
556
|
+
self(self._code_declare_directions())
|
557
|
+
self(b"S1E")
|
558
|
+
self.state = DRIVER_STATE_RASTER
|
559
|
+
|
560
|
+
def program_mode(self, *values, dx=0, dy=0):
|
561
|
+
"""
|
562
|
+
Vector Mode implies but doesn't discount rastering. Twitches are used if twitches is set to True.
|
563
|
+
|
564
|
+
@param values: passed information from the driver command
|
565
|
+
@param dx: change in dx that should be made while switching to program mode.
|
566
|
+
@param dy: change in dy that should be made while switching to program mode.
|
567
|
+
@return:
|
568
|
+
"""
|
569
|
+
if self.state == DRIVER_STATE_PROGRAM:
|
570
|
+
return
|
571
|
+
self.finished_mode()
|
572
|
+
|
573
|
+
self._raster_step_swing_index = 0
|
574
|
+
self._raster_step_float = 0
|
575
|
+
self._raster_step_g_value = 0
|
576
|
+
|
577
|
+
suffix_c = None
|
578
|
+
if (
|
579
|
+
not self.service.twitches or self.settings.get("_force_twitchless", False)
|
580
|
+
) and not self._raster_step_float:
|
581
|
+
suffix_c = True
|
582
|
+
if self._request_leftward is not None:
|
583
|
+
self._leftward = self._request_leftward
|
584
|
+
self._request_leftward = None
|
585
|
+
if self._request_topward is not None:
|
586
|
+
self._topward = self._request_topward
|
587
|
+
self._request_topward = None
|
588
|
+
if self._request_horizontal_major is not None:
|
589
|
+
self._horizontal_major = self._request_horizontal_major
|
590
|
+
self._request_horizontal_major = None
|
591
|
+
if self.service.strict:
|
592
|
+
# Override requested or current values only use core initial values.
|
593
|
+
self._leftward = False
|
594
|
+
self._topward = False
|
595
|
+
self._horizontal_major = False
|
596
|
+
|
597
|
+
speed_code = LaserSpeed(
|
598
|
+
self.service.board,
|
599
|
+
self.speed,
|
600
|
+
raster_step=0,
|
601
|
+
d_ratio=self.implicit_d_ratio,
|
602
|
+
acceleration=self.implicit_accel,
|
603
|
+
fix_limit=True,
|
604
|
+
fix_lows=True,
|
605
|
+
suffix_c=suffix_c,
|
606
|
+
fix_speeds=self.service.fix_speeds,
|
607
|
+
raster_horizontal=self._horizontal_major,
|
608
|
+
).speedcode
|
609
|
+
speed_code = bytes(speed_code, "utf8")
|
610
|
+
self(speed_code)
|
611
|
+
self._goto_xy(dx, dy)
|
612
|
+
self(b"N")
|
613
|
+
self(self._code_declare_directions())
|
614
|
+
self(b"S1E")
|
615
|
+
if self._raster_step_float:
|
616
|
+
self.state = DRIVER_STATE_RASTER
|
617
|
+
else:
|
618
|
+
self.state = DRIVER_STATE_PROGRAM
|
619
|
+
|
620
|
+
def home(self, *values):
|
621
|
+
"""
|
622
|
+
Home the laser.
|
623
|
+
|
624
|
+
@param values:
|
625
|
+
@return:
|
626
|
+
"""
|
627
|
+
if self.service.rotary.active and self.service.rotary.suppress_home:
|
628
|
+
return
|
629
|
+
self.rapid_mode()
|
630
|
+
self(b"IPP\n")
|
631
|
+
old_current = self.service.current
|
632
|
+
self.native_x = 0
|
633
|
+
self.native_y = 0
|
634
|
+
self._reset_modes()
|
635
|
+
self.state = DRIVER_STATE_RAPID
|
636
|
+
|
637
|
+
new_current = self.service.current
|
638
|
+
if self._signal_updates:
|
639
|
+
self.service.signal(
|
640
|
+
"driver;position",
|
641
|
+
(old_current[0], old_current[1], new_current[0], new_current[1]),
|
642
|
+
)
|
643
|
+
|
644
|
+
def physical_home(self):
|
645
|
+
""" "
|
646
|
+
This would be the command to go to a real physical home position (i.e. hitting endstops)
|
647
|
+
"""
|
648
|
+
self.home()
|
649
|
+
|
650
|
+
def lock_rail(self):
|
651
|
+
"""
|
652
|
+
For plotter-style lasers this should prevent the laser bar from moving.
|
653
|
+
|
654
|
+
@return:
|
655
|
+
"""
|
656
|
+
self.rapid_mode()
|
657
|
+
self(b"IS1P\n")
|
658
|
+
|
659
|
+
def unlock_rail(self, abort=False):
|
660
|
+
"""
|
661
|
+
For plotter-style jobs this should free the laser head to be movable by the user.
|
662
|
+
|
663
|
+
@return:
|
664
|
+
"""
|
665
|
+
self.rapid_mode()
|
666
|
+
self(b"IS2P\n")
|
667
|
+
|
668
|
+
def laser_disable(self, *values):
|
669
|
+
self.laser_enabled = False
|
670
|
+
|
671
|
+
def laser_enable(self, *values):
|
672
|
+
self.laser_enabled = True
|
673
|
+
|
674
|
+
def geometry(self, geom):
|
675
|
+
"""
|
676
|
+
Driver command to deal with `geometry` driver call.
|
677
|
+
|
678
|
+
@return:
|
679
|
+
"""
|
680
|
+
for segment_type, start, c1, c2, end, sets in geom.as_lines():
|
681
|
+
if segment_type == "line":
|
682
|
+
self.plot_planner.push(plot)
|
683
|
+
elif segment_type == "end":
|
684
|
+
pass
|
685
|
+
elif segment_type == "quad":
|
686
|
+
self.plot_planner.push(plot)
|
687
|
+
elif segment_type == "cubic":
|
688
|
+
self.plot_planner.push(plot)
|
689
|
+
elif segment_type == "arc":
|
690
|
+
interp = 50
|
691
|
+
g = Geomstr()
|
692
|
+
g.clear()
|
693
|
+
g.arc(start, c1, end)
|
694
|
+
last = start
|
695
|
+
for p in list(g.as_equal_interpolated_points(distance=interp))[1:]:
|
696
|
+
self.plot_planner.push((last, p))
|
697
|
+
last = p
|
698
|
+
elif segment_type == "point":
|
699
|
+
function = sets.get("function")
|
700
|
+
if function == "dwell":
|
701
|
+
self.plot_start()
|
702
|
+
self.rapid_mode()
|
703
|
+
self._move_absolute(start.real, start.imag)
|
704
|
+
self.wait_finish()
|
705
|
+
self.dwell(sets.get("dwell_time"))
|
706
|
+
elif function == "wait":
|
707
|
+
self.plot_start()
|
708
|
+
self.wait_finish()
|
709
|
+
self.wait(sets.get("dwell_time"))
|
710
|
+
elif function == "home":
|
711
|
+
self.plot_start()
|
712
|
+
self.wait_finish()
|
713
|
+
self.home()
|
714
|
+
elif function == "goto":
|
715
|
+
self.plot_start()
|
716
|
+
self.wait_finish()
|
717
|
+
self._move_absolute(start.real, start.imag)
|
718
|
+
elif function == "input":
|
719
|
+
self.plot_start()
|
720
|
+
self.wait_finish()
|
721
|
+
elif function == "output":
|
722
|
+
self.plot_start()
|
723
|
+
self.wait_finish()
|
724
|
+
if self.plot_data is None:
|
725
|
+
self.plot_data = self.plot_planner.gen()
|
726
|
+
self._plotplanner_process()
|
727
|
+
|
728
|
+
def plot(self, plot):
|
729
|
+
"""
|
730
|
+
Gives the driver cutcode that should be plotted/performed.
|
731
|
+
|
732
|
+
@param plot:
|
733
|
+
@return:
|
734
|
+
"""
|
735
|
+
if isinstance(plot, InputCut):
|
736
|
+
self.plot_start()
|
737
|
+
self.wait_finish()
|
738
|
+
# We do not have any GPIO-output abilities
|
739
|
+
elif isinstance(plot, OutputCut):
|
740
|
+
self.plot_start()
|
741
|
+
self.wait_finish()
|
742
|
+
# We do not have any GPIO-input abilities
|
743
|
+
elif isinstance(plot, DwellCut):
|
744
|
+
self.plot_start()
|
745
|
+
self.rapid_mode()
|
746
|
+
start = plot.start
|
747
|
+
self._move_absolute(start[0], start[1])
|
748
|
+
self.wait_finish()
|
749
|
+
self.dwell(plot.dwell_time)
|
750
|
+
elif isinstance(plot, WaitCut):
|
751
|
+
self.plot_start()
|
752
|
+
self.wait_finish()
|
753
|
+
self.wait(plot.dwell_time)
|
754
|
+
elif isinstance(plot, HomeCut):
|
755
|
+
self.plot_start()
|
756
|
+
self.wait_finish()
|
757
|
+
self.home()
|
758
|
+
elif isinstance(plot, GotoCut):
|
759
|
+
self.plot_start()
|
760
|
+
start = plot.start
|
761
|
+
self.wait_finish()
|
762
|
+
self._move_absolute(start[0], start[1])
|
763
|
+
else:
|
764
|
+
# LineCut, QuadCut, CubicCut, PlotCut, RasterCut
|
765
|
+
if isinstance(plot, PlotCut):
|
766
|
+
plot.check_if_rasterable()
|
767
|
+
self.plot_planner.push(plot)
|
768
|
+
|
769
|
+
def plot_start(self):
|
770
|
+
"""
|
771
|
+
Called at the end of plot commands to ensure the driver can deal with them all cutcode as a group, if this
|
772
|
+
is needed by the driver.
|
773
|
+
|
774
|
+
@return:
|
775
|
+
"""
|
776
|
+
if self.plot_data is None:
|
777
|
+
self.plot_data = self.plot_planner.gen()
|
778
|
+
self._plotplanner_process()
|
779
|
+
|
780
|
+
def wait(self, time_in_ms):
|
781
|
+
"""
|
782
|
+
Wait asks that the work be stalled or current process held for the time time_in_ms in ms. If wait_finished is
|
783
|
+
called first this will attempt to stall the machine while performing no work. If the driver in question permits
|
784
|
+
waits to be placed within code this should insert waits into the current job. Returning instantly rather than
|
785
|
+
holding the processes.
|
786
|
+
|
787
|
+
@param time_in_ms:
|
788
|
+
@return:
|
789
|
+
"""
|
790
|
+
self.wait_finish()
|
791
|
+
while self.hold_work(0):
|
792
|
+
time.sleep(0.05)
|
793
|
+
time.sleep(time_in_ms / 1000.0)
|
794
|
+
|
795
|
+
def wait_finish(self, *values):
|
796
|
+
"""
|
797
|
+
Wait finish should ensure that no additional commands be processed until the current buffer is completed. This
|
798
|
+
does not necessarily imply a change in mode as "finished_mode" would require. Just that the buffer be completed
|
799
|
+
before moving on.
|
800
|
+
|
801
|
+
@param values:
|
802
|
+
@return:
|
803
|
+
"""
|
804
|
+
|
805
|
+
def temp_hold():
|
806
|
+
try:
|
807
|
+
return (
|
808
|
+
len(self.out_pipe) != 0 or self.service.controller.state == "wait"
|
809
|
+
)
|
810
|
+
except TypeError:
|
811
|
+
return False
|
812
|
+
|
813
|
+
self.temp_holds.append(temp_hold)
|
814
|
+
|
815
|
+
def function(self, function):
|
816
|
+
"""
|
817
|
+
This command asks that this function be executed at the appropriate time within the spooled cycle.
|
818
|
+
|
819
|
+
@param function:
|
820
|
+
@return:
|
821
|
+
"""
|
822
|
+
self.wait_finish()
|
823
|
+
while self.hold_work(0):
|
824
|
+
time.sleep(0.05)
|
825
|
+
function()
|
826
|
+
|
827
|
+
def beep(self):
|
828
|
+
"""
|
829
|
+
This command asks that a beep be executed at the appropriate time within the spooled cycle.
|
830
|
+
|
831
|
+
@return:
|
832
|
+
"""
|
833
|
+
self.wait_finish()
|
834
|
+
while self.hold_work(0):
|
835
|
+
time.sleep(0.05)
|
836
|
+
self.service("beep\n")
|
837
|
+
|
838
|
+
def console(self, value):
|
839
|
+
"""
|
840
|
+
This asks that the console command be executed at the appropriate time within the spooled cycle.
|
841
|
+
|
842
|
+
@param value: console command
|
843
|
+
@return:
|
844
|
+
"""
|
845
|
+
self.wait_finish()
|
846
|
+
while self.hold_work(0):
|
847
|
+
time.sleep(0.05)
|
848
|
+
self.service(value)
|
849
|
+
|
850
|
+
def signal(self, signal, *args):
|
851
|
+
"""
|
852
|
+
This asks that this signal be broadcast.
|
853
|
+
|
854
|
+
@param signal:
|
855
|
+
@param args:
|
856
|
+
@return:
|
857
|
+
"""
|
858
|
+
self.wait_finish()
|
859
|
+
while self.hold_work(0):
|
860
|
+
time.sleep(0.05)
|
861
|
+
self.service.signal(signal, *args)
|
862
|
+
|
863
|
+
######################
|
864
|
+
# Property IO
|
865
|
+
######################
|
866
|
+
|
867
|
+
@property
|
868
|
+
def is_left(self):
|
869
|
+
return self._x_engaged and not self._y_engaged and self._leftward
|
870
|
+
|
871
|
+
@property
|
872
|
+
def is_right(self):
|
873
|
+
return self._x_engaged and not self._y_engaged and not self._leftward
|
874
|
+
|
875
|
+
@property
|
876
|
+
def is_top(self):
|
877
|
+
return not self._x_engaged and self._y_engaged and self._topward
|
878
|
+
|
879
|
+
@property
|
880
|
+
def is_bottom(self):
|
881
|
+
return not self._x_engaged and self._y_engaged and not self._topward
|
882
|
+
|
883
|
+
@property
|
884
|
+
def is_angle(self):
|
885
|
+
return self._y_engaged and self._x_engaged
|
886
|
+
|
887
|
+
def set_prop(self, mask):
|
888
|
+
self.properties |= mask
|
889
|
+
|
890
|
+
def unset_prop(self, mask):
|
891
|
+
self.properties &= ~mask
|
892
|
+
|
893
|
+
def is_prop(self, mask):
|
894
|
+
return bool(self.properties & mask)
|
895
|
+
|
896
|
+
def toggle_prop(self, mask):
|
897
|
+
if self.is_prop(mask):
|
898
|
+
self.unset_prop(mask)
|
899
|
+
else:
|
900
|
+
self.set_prop(mask)
|
901
|
+
|
902
|
+
######################
|
903
|
+
# PROTECTED DRIVER CODE
|
904
|
+
######################
|
905
|
+
|
906
|
+
def _plotplanner_process(self):
|
907
|
+
"""
|
908
|
+
Processes any data in the plot planner. Getting all relevant (x,y,on) plot values and performing the cardinal
|
909
|
+
movements. Or updating the laser state based on the settings of the cutcode.
|
910
|
+
|
911
|
+
@return:
|
912
|
+
"""
|
913
|
+
if self.plot_data is None:
|
914
|
+
return False
|
915
|
+
# We don't know the length of a generator object
|
916
|
+
total = 0
|
917
|
+
current = 0
|
918
|
+
for x, y, on in self.plot_data:
|
919
|
+
current += 1
|
920
|
+
total = current
|
921
|
+
self._set_queue_status(current, total)
|
922
|
+
while self.hold_work(0):
|
923
|
+
time.sleep(0.05)
|
924
|
+
sx = self.native_x
|
925
|
+
sy = self.native_y
|
926
|
+
# print("x: %s, y: %s -- c: %s, %s" % (str(x), str(y), str(sx), str(sy)))
|
927
|
+
on = int(on)
|
928
|
+
if on > 1:
|
929
|
+
# Special Command.
|
930
|
+
if on & PLOT_FINISH: # Plot planner is ending.
|
931
|
+
self.rapid_mode()
|
932
|
+
break
|
933
|
+
elif on & PLOT_SETTING: # Plot planner settings have changed.
|
934
|
+
p_set = Parameters(self.plot_planner.settings)
|
935
|
+
if p_set.power != self.power:
|
936
|
+
self._set_power(p_set.power)
|
937
|
+
if (
|
938
|
+
p_set.raster_step_x != self.raster_step_x
|
939
|
+
or p_set.raster_step_y != self.raster_step_y
|
940
|
+
or p_set.speed != self.speed
|
941
|
+
or self.implicit_d_ratio != p_set.implicit_d_ratio
|
942
|
+
or self.implicit_accel != p_set.implicit_accel
|
943
|
+
):
|
944
|
+
self._set_speed(p_set.speed)
|
945
|
+
self._set_step(p_set.raster_step_x, p_set.raster_step_y)
|
946
|
+
self._set_acceleration(p_set.implicit_accel)
|
947
|
+
self._set_d_ratio(p_set.implicit_d_ratio)
|
948
|
+
self.settings.update(p_set.settings)
|
949
|
+
elif on & PLOT_AXIS: # Major Axis.
|
950
|
+
# 0 means X Major / Horizontal.
|
951
|
+
# 1 means Y Major / Vertical
|
952
|
+
self._request_horizontal_major = bool(x == 0)
|
953
|
+
elif on & PLOT_DIRECTION:
|
954
|
+
# -1: Moving Left -x
|
955
|
+
# 1: Moving Right. +x
|
956
|
+
self._request_leftward = bool(x != 1)
|
957
|
+
# -1: Moving Bottom +y
|
958
|
+
# 1: Moving Top. -y
|
959
|
+
self._request_topward = bool(y != 1)
|
960
|
+
elif on & (
|
961
|
+
PLOT_RAPID | PLOT_JOG
|
962
|
+
): # Plot planner requests position change.
|
963
|
+
if (
|
964
|
+
on & PLOT_RAPID
|
965
|
+
or self.state != DRIVER_STATE_PROGRAM
|
966
|
+
or self.service.rapid_override
|
967
|
+
):
|
968
|
+
# Perform a rapid position change. Always perform this for raster moves.
|
969
|
+
# DRIVER_STATE_RASTER should call this code as well.
|
970
|
+
self.rapid_mode()
|
971
|
+
self._move_absolute(x, y)
|
972
|
+
else:
|
973
|
+
# Jog is performable and requested. # We have not flagged our direction or state.
|
974
|
+
self._jog_absolute(x, y, mode=self.service.opt_jog_mode)
|
975
|
+
continue
|
976
|
+
dx = x - sx
|
977
|
+
dy = y - sy
|
978
|
+
step_x = self.raster_step_x
|
979
|
+
step_y = self.raster_step_y
|
980
|
+
if step_x == 0 and step_y == 0:
|
981
|
+
# vector mode
|
982
|
+
self.program_mode()
|
983
|
+
else:
|
984
|
+
self.raster_mode()
|
985
|
+
if self._horizontal_major:
|
986
|
+
# Horizontal Rastering.
|
987
|
+
if dy != 0:
|
988
|
+
self._h_switch_g(dy)
|
989
|
+
else:
|
990
|
+
# Vertical Rastering.
|
991
|
+
if dx != 0:
|
992
|
+
self._v_switch_g(dx)
|
993
|
+
# Update dx, dy (if changed by switches)
|
994
|
+
dx = x - self.native_x
|
995
|
+
dy = y - self.native_y
|
996
|
+
self._goto_octent(dx, dy, on & 1)
|
997
|
+
self.plot_data = None
|
998
|
+
self._set_queue_status(0, 0)
|
999
|
+
return False
|
1000
|
+
|
1001
|
+
def _set_speed(self, speed=None):
|
1002
|
+
if self.speed != speed:
|
1003
|
+
self.speed = speed
|
1004
|
+
if self.state in (DRIVER_STATE_PROGRAM, DRIVER_STATE_RASTER):
|
1005
|
+
self.state = DRIVER_STATE_MODECHANGE
|
1006
|
+
|
1007
|
+
def _set_d_ratio(self, d_ratio=None):
|
1008
|
+
if self.dratio != d_ratio:
|
1009
|
+
self.dratio = d_ratio
|
1010
|
+
if self.state in (DRIVER_STATE_PROGRAM, DRIVER_STATE_RASTER):
|
1011
|
+
self.state = DRIVER_STATE_MODECHANGE
|
1012
|
+
|
1013
|
+
def _set_acceleration(self, accel=None):
|
1014
|
+
if self.acceleration != accel:
|
1015
|
+
self.acceleration = accel
|
1016
|
+
if self.state in (DRIVER_STATE_PROGRAM, DRIVER_STATE_RASTER):
|
1017
|
+
self.state = DRIVER_STATE_MODECHANGE
|
1018
|
+
|
1019
|
+
def _set_step(self, step_x=None, step_y=None):
|
1020
|
+
if self.raster_step_x != step_x or self.raster_step_y != step_y:
|
1021
|
+
self.raster_step_x = step_x
|
1022
|
+
self.raster_step_y = step_y
|
1023
|
+
if self.state in (DRIVER_STATE_PROGRAM, DRIVER_STATE_RASTER):
|
1024
|
+
self.state = DRIVER_STATE_MODECHANGE
|
1025
|
+
|
1026
|
+
def _set_power(self, power=1000.0):
|
1027
|
+
self.power = power
|
1028
|
+
if self.power > 1000.0:
|
1029
|
+
self.power = 1000.0
|
1030
|
+
if self.power <= 0:
|
1031
|
+
self.power = 0.0
|
1032
|
+
|
1033
|
+
def _set_ppi(self, power=1000.0):
|
1034
|
+
self.power = power
|
1035
|
+
if self.power > 1000.0:
|
1036
|
+
self.power = 1000.0
|
1037
|
+
if self.power <= 0:
|
1038
|
+
self.power = 0.0
|
1039
|
+
|
1040
|
+
def _set_pwm(self, power=1000.0):
|
1041
|
+
self.power = power
|
1042
|
+
if self.power > 1000.0:
|
1043
|
+
self.power = 1000.0
|
1044
|
+
if self.power <= 0:
|
1045
|
+
self.power = 0.0
|
1046
|
+
|
1047
|
+
def _set_overscan(self, overscan=None):
|
1048
|
+
self.overscan = overscan
|
1049
|
+
|
1050
|
+
def _cut(self, x, y):
|
1051
|
+
self._goto(x, y, True)
|
1052
|
+
|
1053
|
+
def _jog(self, x, y, **kwargs):
|
1054
|
+
if self.is_relative:
|
1055
|
+
self._jog_relative(x, y, **kwargs)
|
1056
|
+
else:
|
1057
|
+
self._jog_absolute(x, y, **kwargs)
|
1058
|
+
|
1059
|
+
def _jog_absolute(self, x, y, **kwargs):
|
1060
|
+
self._jog_relative(x - self.native_x, y - self.native_y, **kwargs)
|
1061
|
+
|
1062
|
+
def _jog_relative(self, dx, dy, mode=0):
|
1063
|
+
self.laser_off()
|
1064
|
+
dx = int(round(dx))
|
1065
|
+
dy = int(round(dy))
|
1066
|
+
if mode == 0:
|
1067
|
+
self._nse_jog_event(dx, dy)
|
1068
|
+
elif mode == 1:
|
1069
|
+
self._mode_shift_on_the_fly(dx, dy)
|
1070
|
+
else:
|
1071
|
+
# Finish-out Jog
|
1072
|
+
self.rapid_mode()
|
1073
|
+
self._move_relative(dx, dy)
|
1074
|
+
self.program_mode()
|
1075
|
+
|
1076
|
+
def _nse_jog_event(self, dx=0, dy=0, speed=None):
|
1077
|
+
"""
|
1078
|
+
NSE Jog events are performed from program or raster mode and skip out to rapid mode to perform
|
1079
|
+
a single jog command. This jog effect varies based on the horizontal vertical major setting and
|
1080
|
+
needs to counteract the jogged head according to those settings.
|
1081
|
+
|
1082
|
+
NSE jogs will not change the underlying mode even though they temporarily switch into
|
1083
|
+
rapid mode. nse jogs are not done in raster mode.
|
1084
|
+
"""
|
1085
|
+
dx = int(round(dx))
|
1086
|
+
dy = int(round(dy))
|
1087
|
+
original_state = self.state
|
1088
|
+
self.state = DRIVER_STATE_RAPID
|
1089
|
+
self.laser = False
|
1090
|
+
if self._horizontal_major:
|
1091
|
+
if not self.is_left and dx >= 0:
|
1092
|
+
self(self.CODE_LEFT)
|
1093
|
+
if not self.is_right and dx <= 0:
|
1094
|
+
self(self.CODE_RIGHT)
|
1095
|
+
else:
|
1096
|
+
if not self.is_top and dy >= 0:
|
1097
|
+
self(self.CODE_TOP)
|
1098
|
+
if not self.is_bottom and dy <= 0:
|
1099
|
+
self(self.CODE_BOTTOM)
|
1100
|
+
self(b"N")
|
1101
|
+
self._goto_xy(dx, dy)
|
1102
|
+
self(b"SE")
|
1103
|
+
self(self._code_declare_directions())
|
1104
|
+
self.state = original_state
|
1105
|
+
|
1106
|
+
def _move(self, x, y):
|
1107
|
+
self._goto(x, y, False)
|
1108
|
+
|
1109
|
+
def _move_absolute(self, x, y):
|
1110
|
+
self._goto_absolute(x, y, False)
|
1111
|
+
|
1112
|
+
def _move_relative(self, x, y):
|
1113
|
+
self._goto_relative(x, y, False)
|
1114
|
+
|
1115
|
+
def _goto(self, x, y, cut):
|
1116
|
+
"""
|
1117
|
+
Goto a position within a cut.
|
1118
|
+
|
1119
|
+
This depends on whether is_relative is set.
|
1120
|
+
|
1121
|
+
@param x:
|
1122
|
+
@param y:
|
1123
|
+
@param cut:
|
1124
|
+
@return:
|
1125
|
+
"""
|
1126
|
+
if self.is_relative:
|
1127
|
+
self._goto_relative(x, y, cut)
|
1128
|
+
else:
|
1129
|
+
self._goto_absolute(x, y, cut)
|
1130
|
+
|
1131
|
+
def _goto_absolute(self, x, y, cut):
|
1132
|
+
"""
|
1133
|
+
Goto absolute x and y. With cut set or not set.
|
1134
|
+
|
1135
|
+
@param x:
|
1136
|
+
@param y:
|
1137
|
+
@param cut:
|
1138
|
+
@return:
|
1139
|
+
"""
|
1140
|
+
self._goto_relative(x - self.native_x, y - self.native_y, cut)
|
1141
|
+
|
1142
|
+
def _move_override_speed(self, dx, dy, x_speed, y_speed=None):
|
1143
|
+
"""
|
1144
|
+
Rapid movement override. Should make programmed jogs.
|
1145
|
+
|
1146
|
+
@param dx: change in x
|
1147
|
+
@param dy: change in y
|
1148
|
+
@param x_speed: max allowed speed in x direction
|
1149
|
+
@param y_speed: max allowed speed in y direction
|
1150
|
+
@return:
|
1151
|
+
"""
|
1152
|
+
if y_speed is None:
|
1153
|
+
y_speed = x_speed
|
1154
|
+
original_accel = self.acceleration
|
1155
|
+
original_speed = self.speed
|
1156
|
+
original_steps = self.raster_step_x, self.raster_step_y
|
1157
|
+
|
1158
|
+
# Do not allow custom accel codes, or raster steps.
|
1159
|
+
self._set_acceleration(None)
|
1160
|
+
self._set_step(0, 0)
|
1161
|
+
# We know we will travel dx, dy. Set the initial direction requests.
|
1162
|
+
self._request_leftward = dx < 0
|
1163
|
+
self._request_topward = dy < 0
|
1164
|
+
self._request_horizontal_major = abs(dx) > abs(dy)
|
1165
|
+
if y_speed <= x_speed and abs(dy) >= abs(dx):
|
1166
|
+
# y_speed is slowest and dy is larger than dx. The y-shift will take longer than x-shift. Combine.
|
1167
|
+
self._set_speed(y_speed)
|
1168
|
+
self.program_mode()
|
1169
|
+
dy_m = int(
|
1170
|
+
math.copysign(dx, dy)
|
1171
|
+
) # magnitude of shorter in the direction of longer.
|
1172
|
+
self._goto_octent(dx, dy_m, on=False)
|
1173
|
+
self._goto_octent(0, dy - dy_m, on=False)
|
1174
|
+
elif x_speed <= y_speed and abs(dx) >= abs(dy):
|
1175
|
+
# x_speed is slowest and dx is larger than dy. The x-shift will take longer than y-shift. Combine.
|
1176
|
+
self._set_speed(x_speed)
|
1177
|
+
self.program_mode()
|
1178
|
+
dx_m = int(
|
1179
|
+
math.copysign(dy, dx)
|
1180
|
+
) # magnitude of shorter in the direction of longer.
|
1181
|
+
self._goto_octent(dx_m, dy, on=False)
|
1182
|
+
self._goto_octent(dx - dx_m, 0, on=False)
|
1183
|
+
else:
|
1184
|
+
# The faster speed is going longer. The slower speed is going shorter. Full zig.
|
1185
|
+
if dx != 0:
|
1186
|
+
self._set_speed(x_speed)
|
1187
|
+
self.program_mode()
|
1188
|
+
self._goto_octent(dx, 0, on=False)
|
1189
|
+
if dy != 0:
|
1190
|
+
self._set_speed(y_speed)
|
1191
|
+
self.program_mode()
|
1192
|
+
self._goto_octent(0, dy, on=False)
|
1193
|
+
self.rapid_mode()
|
1194
|
+
|
1195
|
+
# We always restore the original settings.
|
1196
|
+
self._set_acceleration(original_accel)
|
1197
|
+
self._set_speed(original_speed)
|
1198
|
+
self._set_step(*original_steps)
|
1199
|
+
|
1200
|
+
def _move_in_rapid_mode(self, dx, dy, cut):
|
1201
|
+
if self.service.rapid_override and (dx != 0 or dy != 0):
|
1202
|
+
y_speed = self.service.rapid_override_speed_y
|
1203
|
+
x_speed = self.service.rapid_override_speed_x
|
1204
|
+
self._move_override_speed(dx, dy, x_speed, y_speed)
|
1205
|
+
return
|
1206
|
+
self(b"I")
|
1207
|
+
self._goto_xy(dx, dy)
|
1208
|
+
self(b"S1P\n")
|
1209
|
+
if not self.service.autolock:
|
1210
|
+
self(b"IS2P\n")
|
1211
|
+
|
1212
|
+
def _goto_relative(self, dx, dy, cut):
|
1213
|
+
"""
|
1214
|
+
Goto relative dx, dy. With cut set or not set.
|
1215
|
+
|
1216
|
+
@param dx:
|
1217
|
+
@param dy:
|
1218
|
+
@param cut:
|
1219
|
+
@return:
|
1220
|
+
"""
|
1221
|
+
if abs(dx) == 0 and abs(dy) == 0:
|
1222
|
+
return
|
1223
|
+
dx = int(round(dx))
|
1224
|
+
dy = int(round(dy))
|
1225
|
+
old_current = self.service.current
|
1226
|
+
if self.state == DRIVER_STATE_RAPID:
|
1227
|
+
self._move_in_rapid_mode(dx, dy, cut)
|
1228
|
+
elif self.state == DRIVER_STATE_RASTER:
|
1229
|
+
# goto in raster, switches to program to recall this function.
|
1230
|
+
self.program_mode()
|
1231
|
+
self._goto_relative(dx, dy, cut)
|
1232
|
+
return
|
1233
|
+
elif self.state == DRIVER_STATE_PROGRAM:
|
1234
|
+
mx = 0
|
1235
|
+
my = 0
|
1236
|
+
line = list(grouped(ZinglPlotter.plot_line(0, 0, dx, dy)))
|
1237
|
+
for x, y in line:
|
1238
|
+
self._goto_octent(x - mx, y - my, cut)
|
1239
|
+
mx = x
|
1240
|
+
my = y
|
1241
|
+
elif self.state == DRIVER_STATE_FINISH:
|
1242
|
+
self._goto_xy(dx, dy)
|
1243
|
+
self(b"N")
|
1244
|
+
elif self.state == DRIVER_STATE_MODECHANGE:
|
1245
|
+
self._mode_shift_on_the_fly(dx, dy)
|
1246
|
+
|
1247
|
+
new_current = self.service.current
|
1248
|
+
if self._signal_updates:
|
1249
|
+
self.service.signal(
|
1250
|
+
"driver;position",
|
1251
|
+
(old_current[0], old_current[1], new_current[0], new_current[1]),
|
1252
|
+
)
|
1253
|
+
|
1254
|
+
def _mode_shift_on_the_fly(self, dx=0, dy=0):
|
1255
|
+
"""
|
1256
|
+
Mode-shift on the fly changes the current modes while in programmed or raster mode
|
1257
|
+
this exits with a @ command that resets the modes. A movement operation can be added after
|
1258
|
+
the speed code and before the return to into programmed or raster mode.
|
1259
|
+
|
1260
|
+
This switch is often avoided because testing revealed some chance of a runaway during reset
|
1261
|
+
switching.
|
1262
|
+
|
1263
|
+
If the raster step has been changed from zero this can result in shifting from program to raster mode
|
1264
|
+
"""
|
1265
|
+
dx = int(round(dx))
|
1266
|
+
dy = int(round(dy))
|
1267
|
+
self(b"@NSE")
|
1268
|
+
self.laser = False
|
1269
|
+
self.state = DRIVER_STATE_RAPID
|
1270
|
+
self.program_mode(dx, dy)
|
1271
|
+
|
1272
|
+
def _h_switch_g(self, dy: float):
|
1273
|
+
"""
|
1274
|
+
Horizontal switch with a Gvalue set. The board will automatically step according to the step_value_set.
|
1275
|
+
|
1276
|
+
@return:
|
1277
|
+
"""
|
1278
|
+
set_step = self._raster_step_g_value
|
1279
|
+
if isinstance(set_step, tuple):
|
1280
|
+
set_step = set_step[self._raster_step_swing_index % len(set_step)]
|
1281
|
+
|
1282
|
+
# correct for fractional stepping
|
1283
|
+
self._raster_step_fractional_remainder += dy
|
1284
|
+
delta = math.trunc(self._raster_step_fractional_remainder)
|
1285
|
+
self._raster_step_fractional_remainder -= delta
|
1286
|
+
|
1287
|
+
step_amount = -abs(set_step) if self._topward else abs(set_step)
|
1288
|
+
remaining = delta - step_amount
|
1289
|
+
if (
|
1290
|
+
remaining > 0
|
1291
|
+
and self._topward
|
1292
|
+
or remaining < 0
|
1293
|
+
and not self._topward
|
1294
|
+
or abs(remaining) > 15
|
1295
|
+
):
|
1296
|
+
# Remaining value is in the wrong direction, abort and move.
|
1297
|
+
self.finished_mode()
|
1298
|
+
self._move_relative(0, remaining)
|
1299
|
+
self.raster_mode()
|
1300
|
+
remaining = 0
|
1301
|
+
if remaining:
|
1302
|
+
self._goto_octent(
|
1303
|
+
-abs(remaining) if self._leftward else abs(remaining), remaining, False
|
1304
|
+
)
|
1305
|
+
self._x_engaged = True
|
1306
|
+
self._y_engaged = False
|
1307
|
+
# We reverse direction and step.
|
1308
|
+
if self._leftward:
|
1309
|
+
self(self.CODE_RIGHT)
|
1310
|
+
self._leftward = False
|
1311
|
+
else:
|
1312
|
+
self(self.CODE_LEFT)
|
1313
|
+
self._leftward = True
|
1314
|
+
self.native_y += step_amount
|
1315
|
+
self.laser = False
|
1316
|
+
self._raster_step_swing_index += 1
|
1317
|
+
|
1318
|
+
def _v_switch_g(self, dx: float):
|
1319
|
+
"""
|
1320
|
+
Vertical switch with a Gvalue set. The board will automatically step according to the step_value_set.
|
1321
|
+
|
1322
|
+
@return:
|
1323
|
+
"""
|
1324
|
+
set_step = self._raster_step_g_value
|
1325
|
+
if isinstance(set_step, tuple):
|
1326
|
+
set_step = set_step[self._raster_step_swing_index % len(set_step)]
|
1327
|
+
|
1328
|
+
# correct for fractional stepping
|
1329
|
+
self._raster_step_fractional_remainder += dx
|
1330
|
+
delta = math.trunc(self._raster_step_fractional_remainder)
|
1331
|
+
self._raster_step_fractional_remainder -= delta
|
1332
|
+
|
1333
|
+
step_amount = -set_step if self._leftward else set_step
|
1334
|
+
remaining = delta - step_amount
|
1335
|
+
if (
|
1336
|
+
remaining > 0
|
1337
|
+
and self._leftward
|
1338
|
+
or remaining < 0
|
1339
|
+
and not self._leftward
|
1340
|
+
or abs(remaining) > 15
|
1341
|
+
):
|
1342
|
+
# Remaining value is in the wrong direction, abort and move.
|
1343
|
+
self.finished_mode()
|
1344
|
+
self._move_relative(remaining, 0)
|
1345
|
+
self.raster_mode()
|
1346
|
+
remaining = 0
|
1347
|
+
if remaining:
|
1348
|
+
self._goto_octent(
|
1349
|
+
remaining, -abs(remaining) if self._topward else abs(remaining), False
|
1350
|
+
)
|
1351
|
+
self._y_engaged = True
|
1352
|
+
self._x_engaged = False
|
1353
|
+
# We reverse direction and step.
|
1354
|
+
if self._topward:
|
1355
|
+
self(self.CODE_BOTTOM)
|
1356
|
+
self._topward = False
|
1357
|
+
else:
|
1358
|
+
self(self.CODE_TOP)
|
1359
|
+
self._topward = True
|
1360
|
+
self.native_x += step_amount
|
1361
|
+
self.laser = False
|
1362
|
+
self._raster_step_swing_index += 1
|
1363
|
+
|
1364
|
+
def _reset_modes(self):
|
1365
|
+
self.laser = False
|
1366
|
+
self._request_leftward = None
|
1367
|
+
self._request_topward = None
|
1368
|
+
self._request_horizontal_major = None
|
1369
|
+
self._topward = False
|
1370
|
+
self._leftward = False
|
1371
|
+
self._x_engaged = False
|
1372
|
+
self._y_engaged = False
|
1373
|
+
self._horizontal_major = False
|
1374
|
+
|
1375
|
+
def _goto_xy(self, dx, dy, on=None):
|
1376
|
+
rapid = self.state not in (DRIVER_STATE_PROGRAM, DRIVER_STATE_RASTER)
|
1377
|
+
if dx != 0:
|
1378
|
+
self.native_x += dx
|
1379
|
+
if dx > 0: # Moving right
|
1380
|
+
if not self.is_right or rapid:
|
1381
|
+
self(self.CODE_RIGHT)
|
1382
|
+
self._leftward = False
|
1383
|
+
else: # Moving left
|
1384
|
+
if not self.is_left or rapid:
|
1385
|
+
self(self.CODE_LEFT)
|
1386
|
+
self._leftward = True
|
1387
|
+
self._x_engaged = True
|
1388
|
+
self._y_engaged = False
|
1389
|
+
if on is not None:
|
1390
|
+
if on:
|
1391
|
+
self.laser_on()
|
1392
|
+
else:
|
1393
|
+
self.laser_off()
|
1394
|
+
self(lhymicro_distance(abs(dx)))
|
1395
|
+
if dy != 0:
|
1396
|
+
self.native_y += dy
|
1397
|
+
if dy > 0: # Moving bottom
|
1398
|
+
if not self.is_bottom or rapid:
|
1399
|
+
self(self.CODE_BOTTOM)
|
1400
|
+
self._topward = False
|
1401
|
+
else: # Moving top
|
1402
|
+
if not self.is_top or rapid:
|
1403
|
+
self(self.CODE_TOP)
|
1404
|
+
self._topward = True
|
1405
|
+
self._x_engaged = False
|
1406
|
+
self._y_engaged = True
|
1407
|
+
if on is not None:
|
1408
|
+
if on:
|
1409
|
+
self.laser_on()
|
1410
|
+
else:
|
1411
|
+
self.laser_off()
|
1412
|
+
self(lhymicro_distance(abs(dy)))
|
1413
|
+
|
1414
|
+
def _goto_octent(self, dx, dy, on):
|
1415
|
+
old_current = self.service.current
|
1416
|
+
if dx == 0 and dy == 0:
|
1417
|
+
return
|
1418
|
+
if abs(dx) == abs(dy):
|
1419
|
+
self._x_engaged = True # Set both on
|
1420
|
+
self._y_engaged = True
|
1421
|
+
if dx > 0: # Moving right
|
1422
|
+
if self._leftward:
|
1423
|
+
self(self.CODE_RIGHT)
|
1424
|
+
self._leftward = False
|
1425
|
+
else: # Moving left
|
1426
|
+
if not self._leftward:
|
1427
|
+
self(self.CODE_LEFT)
|
1428
|
+
self._leftward = True
|
1429
|
+
if dy > 0: # Moving bottom
|
1430
|
+
if self._topward:
|
1431
|
+
self(self.CODE_BOTTOM)
|
1432
|
+
self._topward = False
|
1433
|
+
else: # Moving top
|
1434
|
+
if not self._topward:
|
1435
|
+
self(self.CODE_TOP)
|
1436
|
+
self._topward = True
|
1437
|
+
self.native_x += dx
|
1438
|
+
self.native_y += dy
|
1439
|
+
self(self.CODE_ANGLE)
|
1440
|
+
if on:
|
1441
|
+
self.laser_on()
|
1442
|
+
else:
|
1443
|
+
self.laser_off()
|
1444
|
+
self(lhymicro_distance(abs(dy)))
|
1445
|
+
else:
|
1446
|
+
self._goto_xy(dx, dy, on=on)
|
1447
|
+
|
1448
|
+
new_current = self.service.current
|
1449
|
+
if self._signal_updates:
|
1450
|
+
self.service.signal(
|
1451
|
+
"driver;position",
|
1452
|
+
(old_current[0], old_current[1], new_current[0], new_current[1]),
|
1453
|
+
)
|
1454
|
+
|
1455
|
+
def _code_declare_directions(self):
|
1456
|
+
x_dir = self.CODE_LEFT if self._leftward else self.CODE_RIGHT
|
1457
|
+
y_dir = self.CODE_TOP if self._topward else self.CODE_BOTTOM
|
1458
|
+
if self._horizontal_major:
|
1459
|
+
self._x_engaged = True
|
1460
|
+
self._y_engaged = False
|
1461
|
+
return y_dir + x_dir
|
1462
|
+
else:
|
1463
|
+
self._x_engaged = False
|
1464
|
+
self._y_engaged = True
|
1465
|
+
return x_dir + y_dir
|
1466
|
+
|