meerk40t 0.9.3001__py2.py3-none-any.whl → 0.9.7010__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 +1195 -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 +1844 -1507
- meerk40t/core/elements/clipboard.py +229 -219
- meerk40t/core/elements/element_treeops.py +4561 -2837
- meerk40t/core/elements/element_types.py +125 -105
- meerk40t/core/elements/elements.py +4329 -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 +933 -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/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 +462 -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 +198 -0
- meerk40t/extra/ezd.py +1165 -1165
- meerk40t/extra/hershey.py +835 -340
- meerk40t/extra/imageactions.py +322 -316
- meerk40t/extra/inkscape.py +630 -622
- meerk40t/extra/lbrn.py +424 -424
- meerk40t/extra/outerworld.py +284 -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 +1081 -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 +170 -133
- meerk40t/gui/choicepropertypanel.py +1673 -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 +1430 -846
- meerk40t/gui/icons.py +3422 -2747
- meerk40t/gui/imagesplitter.py +555 -508
- meerk40t/gui/keymap.py +354 -344
- meerk40t/gui/laserpanel.py +892 -806
- meerk40t/gui/laserrender.py +1470 -1232
- meerk40t/gui/lasertoolpanel.py +805 -793
- meerk40t/gui/magnetoptions.py +436 -0
- meerk40t/gui/materialmanager.py +2917 -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 +494 -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 +2468 -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 +589 -346
- meerk40t/gui/scenewidgets/relocatewidget.py +33 -33
- meerk40t/gui/scenewidgets/reticlewidget.py +83 -83
- meerk40t/gui/scenewidgets/selectionwidget.py +2952 -2756
- meerk40t/gui/simpleui.py +357 -333
- meerk40t/gui/simulation.py +2431 -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 +591 -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 +160 -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 +1444 -1169
- meerk40t/gui/wxmmain.py +5578 -4112
- meerk40t/gui/wxmribbon.py +1591 -1076
- meerk40t/gui/wxmscene.py +1635 -1453
- meerk40t/gui/wxmtree.py +2410 -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 +2778 -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 +3809 -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 +102 -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 +390 -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 +672 -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 +940 -940
- meerk40t/tools/rasterplotter.py +1660 -547
- meerk40t/tools/shxparser.py +989 -901
- meerk40t/tools/ttfparser.py +726 -446
- meerk40t/tools/zinglplotter.py +595 -593
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/LICENSE +21 -21
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/METADATA +150 -139
- meerk40t-0.9.7010.dist-info/RECORD +445 -0
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/WHEEL +1 -1
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/top_level.txt +0 -1
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.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.7010.dist-info}/entry_points.txt +0 -0
meerk40t/ch341/libusb.py
CHANGED
@@ -1,589 +1,595 @@
|
|
1
|
-
import usb.core
|
2
|
-
import usb.util
|
3
|
-
from usb.backend.libusb1 import LIBUSB_ERROR_ACCESS, LIBUSB_ERROR_NOT_FOUND
|
4
|
-
|
5
|
-
STATUS_NO_DEVICE = -1
|
6
|
-
USB_LOCK_VENDOR = 0x1A86 # Dev : (1a86) QinHeng Electronics
|
7
|
-
USB_LOCK_PRODUCT = 0x5512 # (5512) CH341A
|
8
|
-
BULK_WRITE_ENDPOINT = 0x02 # usb.util.ENDPOINT_OUT|usb.util.ENDPOINT_TYPE_BULK
|
9
|
-
BULK_READ_ENDPOINT = 0x82 # usb.util.ENDPOINT_IN|usb.util.ENDPOINT_TYPE_BULK
|
10
|
-
CH341_PARA_MODE_EPP19 = 0x01
|
11
|
-
|
12
|
-
mCH341_PARA_CMD_R0 = 0xAC # 10101100
|
13
|
-
mCH341_PARA_CMD_R1 = 0xAD # 10101101
|
14
|
-
mCH341_PARA_CMD_W0 = 0xA6 # 10100110
|
15
|
-
mCH341_PARA_CMD_W1 = 0xA7 # 10100111
|
16
|
-
mCH341_PARA_CMD_STS = 0xA0 # 10100000
|
17
|
-
|
18
|
-
mCH341_PACKET_LENGTH = 32
|
19
|
-
mCH341_PKT_LEN_SHORT = 8
|
20
|
-
mCH341_SET_PARA_MODE = 0x9A
|
21
|
-
mCH341_PARA_INIT = 0xB1
|
22
|
-
mCH341_VENDOR_READ = 0xC0
|
23
|
-
mCH341_VENDOR_WRITE = 0x40
|
24
|
-
mCH341A_BUF_CLEAR = 0xB2
|
25
|
-
mCH341A_DELAY_MS = 0x5E
|
26
|
-
mCH341A_GET_VER = 0x5F
|
27
|
-
mCH341A_STATUS = 0x52
|
28
|
-
|
29
|
-
|
30
|
-
class Ch341LibusbDriver:
|
31
|
-
"""
|
32
|
-
Libusb driver for the CH341 chip. The CH341x is a USB interface chip that can emulate UART, parallel port,
|
33
|
-
and synchronous serial (EPP, I2C, SPI). The Lihuiyu boards (M2Nano, et al.) and Moshiboards and likely others
|
34
|
-
use this in EPP 1.9 mode. This class is not and not intended to be a full driver for that chip. Rather we are
|
35
|
-
duplicating the function calls and implementing compatible operations to permit a stand-in for the default CH341
|
36
|
-
driver. Using libusb to do the usb connection to the chip as well as permitting easy swapping that for the default
|
37
|
-
driver. This serves as the basis to permit multiple operative methods, permitting use of either the default driver
|
38
|
-
or Libusb driver interchangeably.
|
39
|
-
|
40
|
-
Since these functions will need swapping in MSW we should duplicate the function calls thereof. Also since a stated
|
41
|
-
goal is to support multiple devices implicitly, we should also properly support multiple device functionality.
|
42
|
-
|
43
|
-
To this end, this should duplicate the names of the function calls. And the use of index to reference which
|
44
|
-
connection to use for each command.
|
45
|
-
|
46
|
-
All the commands during the opening phase will raise a ConnectionRefusedError.
|
47
|
-
All commands during read and write raise ConnectionErrors
|
48
|
-
All commands during close don't care about errors, if it broke it's likely already closed.
|
49
|
-
"""
|
50
|
-
|
51
|
-
def __init__(self, channel, bulk=True):
|
52
|
-
self.devices = {}
|
53
|
-
self.interface = {}
|
54
|
-
self.channel = channel
|
55
|
-
self.backend_error_code = None
|
56
|
-
self.timeout = 1500
|
57
|
-
self.bulk = bulk
|
58
|
-
|
59
|
-
def find_device(self, index=0):
|
60
|
-
_ = self.channel._
|
61
|
-
self.channel("\n")
|
62
|
-
self.channel(_("Finding devices."))
|
63
|
-
try:
|
64
|
-
devices = list(
|
65
|
-
usb.core.find(
|
66
|
-
idVendor=USB_LOCK_VENDOR, idProduct=USB_LOCK_PRODUCT, find_all=True
|
67
|
-
)
|
68
|
-
)
|
69
|
-
except usb.core.USBError as e:
|
70
|
-
self.backend_error_code = e.backend_error_code
|
71
|
-
self.channel(str(e))
|
72
|
-
if self.backend_error_code == LIBUSB_ERROR_ACCESS:
|
73
|
-
self.channel(_("Your OS does not give you permissions to access USB."))
|
74
|
-
raise PermissionError
|
75
|
-
elif self.backend_error_code == LIBUSB_ERROR_NOT_FOUND:
|
76
|
-
self.channel(
|
77
|
-
_(
|
78
|
-
"K40 devices were found. But something else was connected to them."
|
79
|
-
)
|
80
|
-
)
|
81
|
-
raise ConnectionRefusedError
|
82
|
-
if len(devices) == 0:
|
83
|
-
self.channel(_("Devices Not Found."))
|
84
|
-
raise IndexError
|
85
|
-
else:
|
86
|
-
self.channel(_("{count} device(s) were found.").format(count=len(devices)))
|
87
|
-
if index >= len(devices):
|
88
|
-
self.channel(
|
89
|
-
_("Device index {index} exceeds devices found.").format(index=index)
|
90
|
-
)
|
91
|
-
raise IndexError
|
92
|
-
|
93
|
-
device = devices[index]
|
94
|
-
self.channel(_("K40 device detected:"))
|
95
|
-
string = str(device)
|
96
|
-
string = string.replace("\n", "\n\t")
|
97
|
-
self.channel(string)
|
98
|
-
return device
|
99
|
-
|
100
|
-
def detach_kernel(self, device, interface):
|
101
|
-
_ = self.channel._
|
102
|
-
try:
|
103
|
-
if device.is_kernel_driver_active(interface.bInterfaceNumber):
|
104
|
-
self.channel(_("Attempting to detach kernel."))
|
105
|
-
device.detach_kernel_driver(interface.bInterfaceNumber)
|
106
|
-
self.channel(_("Kernel detach: Success."))
|
107
|
-
except usb.core.USBError as e:
|
108
|
-
self.backend_error_code = e.backend_error_code
|
109
|
-
|
110
|
-
self.channel(str(e))
|
111
|
-
self.channel(_("Kernel detach: Failed."))
|
112
|
-
raise ConnectionRefusedError
|
113
|
-
except NotImplementedError:
|
114
|
-
self.channel(
|
115
|
-
_("Kernel detach: Not Implemented.")
|
116
|
-
) # Driver does not permit kernel detaching.
|
117
|
-
# Non-fatal error.
|
118
|
-
|
119
|
-
def get_active_config(self, device):
|
120
|
-
_ = self.channel._
|
121
|
-
self.channel(_("Getting Active Config"))
|
122
|
-
try:
|
123
|
-
interface = device.get_active_configuration()[(0, 0)]
|
124
|
-
self.channel(_("Active Config: Success."))
|
125
|
-
return interface
|
126
|
-
except usb.core.USBError as e:
|
127
|
-
self.backend_error_code = e.backend_error_code
|
128
|
-
|
129
|
-
self.channel(str(e))
|
130
|
-
self.channel(_("Active Config: Failed."))
|
131
|
-
raise ConnectionRefusedError
|
132
|
-
|
133
|
-
def set_config(self, device):
|
134
|
-
_ = self.channel._
|
135
|
-
self.channel(_("Config Set"))
|
136
|
-
try:
|
137
|
-
device.set_configuration()
|
138
|
-
self.channel(_("Config Set: Success"))
|
139
|
-
except usb.core.USBError as e:
|
140
|
-
self.backend_error_code = e.backend_error_code
|
141
|
-
|
142
|
-
self.channel(str(e))
|
143
|
-
self.channel(
|
144
|
-
_(
|
145
|
-
"Config Set: Fail\n(Hint: may recover if you change where the USB is plugged in.)"
|
146
|
-
)
|
147
|
-
)
|
148
|
-
# raise ConnectionRefusedError
|
149
|
-
except NotImplementedError
|
150
|
-
self.channel(
|
151
|
-
_(
|
152
|
-
"Config Set: Fail\nSet Configuration is not implemented on this platform. Pass."
|
153
|
-
)
|
154
|
-
)
|
155
|
-
|
156
|
-
def claim_interface(self, device, interface):
|
157
|
-
_ = self.channel._
|
158
|
-
try:
|
159
|
-
self.channel(_("Attempting to claim interface."))
|
160
|
-
usb.util.claim_interface(device, interface)
|
161
|
-
self.channel(_("Interface claim: Success"))
|
162
|
-
except usb.core.USBError as e:
|
163
|
-
self.backend_error_code = e.backend_error_code
|
164
|
-
|
165
|
-
self.channel(str(e))
|
166
|
-
self.channel(_("Interface claim: Failed. (Interface is in use.)"))
|
167
|
-
raise ConnectionRefusedError
|
168
|
-
# Already in use. This is critical.
|
169
|
-
|
170
|
-
def disconnect_detach(self, device, interface):
|
171
|
-
_ = self.channel._
|
172
|
-
try:
|
173
|
-
self.channel(_("Attempting kernel attach"))
|
174
|
-
device.attach_kernel_driver(interface.bInterfaceNumber)
|
175
|
-
self.channel(_("Kernel attach: Success."))
|
176
|
-
except usb.core.USBError as e:
|
177
|
-
self.backend_error_code = e.backend_error_code
|
178
|
-
|
179
|
-
self.channel(str(e))
|
180
|
-
self.channel(_("Kernel attach: Fail."))
|
181
|
-
# Continue and hope it is non-critical.
|
182
|
-
except NotImplementedError:
|
183
|
-
self.channel(_("Kernel attach: Fail."))
|
184
|
-
|
185
|
-
def unclaim_interface(self, device, interface):
|
186
|
-
_ = self.channel._
|
187
|
-
try:
|
188
|
-
self.channel(_("Attempting to release interface."))
|
189
|
-
usb.util.release_interface(device, interface)
|
190
|
-
self.channel(_("Interface released."))
|
191
|
-
except usb.core.USBError as e:
|
192
|
-
self.backend_error_code = e.backend_error_code
|
193
|
-
|
194
|
-
self.channel(str(e))
|
195
|
-
self.channel(_("Interface did not exist."))
|
196
|
-
|
197
|
-
def disconnect_dispose(self, device):
|
198
|
-
_ = self.channel._
|
199
|
-
try:
|
200
|
-
self.channel(_("Attempting to dispose resources."))
|
201
|
-
usb.util.dispose_resources(device)
|
202
|
-
self.channel(_("Dispose Resources: Success"))
|
203
|
-
except usb.core.USBError as e:
|
204
|
-
self.backend_error_code = e.backend_error_code
|
205
|
-
|
206
|
-
self.channel(str(e))
|
207
|
-
self.channel(_("Dispose Resources: Fail"))
|
208
|
-
|
209
|
-
def disconnect_reset(self, device):
|
210
|
-
_ = self.channel._
|
211
|
-
try:
|
212
|
-
self.channel(_("Attempting USB reset."))
|
213
|
-
device.reset()
|
214
|
-
self.channel(_("USB connection reset."))
|
215
|
-
except usb.core.USBError as e:
|
216
|
-
self.backend_error_code = e.backend_error_code
|
217
|
-
|
218
|
-
self.channel(str(e))
|
219
|
-
self.channel(_("USB connection did not exist."))
|
220
|
-
|
221
|
-
def bus(self, index):
|
222
|
-
return self.devices[index].bus
|
223
|
-
|
224
|
-
def address(self, index):
|
225
|
-
return self.devices[index].address
|
226
|
-
|
227
|
-
def CH341OpenDevice(self, index=0):
|
228
|
-
"""
|
229
|
-
Opens device, returns index.
|
230
|
-
|
231
|
-
Can throw a variety of USBErrors, IndexErrors, Backend errors.
|
232
|
-
"""
|
233
|
-
_ = self.channel._
|
234
|
-
device = self.find_device(index)
|
235
|
-
self.devices[index] = device
|
236
|
-
self.set_config(device)
|
237
|
-
interface = self.get_active_config(device)
|
238
|
-
self.interface[index] = interface
|
239
|
-
|
240
|
-
self.detach_kernel(device, interface)
|
241
|
-
try:
|
242
|
-
self.claim_interface(device, interface)
|
243
|
-
except ConnectionRefusedError:
|
244
|
-
# Attempting interface cycle.
|
245
|
-
self.unclaim_interface(device, interface)
|
246
|
-
self.claim_interface(device, interface)
|
247
|
-
return index
|
248
|
-
|
249
|
-
def CH341CloseDevice(self, index=0):
|
250
|
-
"""Closes device."""
|
251
|
-
_ = self.channel._
|
252
|
-
device = self.devices[index]
|
253
|
-
interface = self.interface[index]
|
254
|
-
if device is not None:
|
255
|
-
try:
|
256
|
-
self.disconnect_detach(device, interface)
|
257
|
-
self.unclaim_interface(device, interface)
|
258
|
-
self.disconnect_dispose(device)
|
259
|
-
self.disconnect_reset(device)
|
260
|
-
except ConnectionError:
|
261
|
-
pass
|
262
|
-
|
263
|
-
def CH341InitParallel(
|
264
|
-
self, index=0, mode=CH341_PARA_MODE_EPP19
|
265
|
-
): # Mode 1, we need EPP 1.9
|
266
|
-
"""Permits setting a mode, but our mode is only 1 since the device is using
|
267
|
-
EPP 1.9. This is a control transfer event."""
|
268
|
-
device = self.devices[index]
|
269
|
-
value = mode << 8
|
270
|
-
if mode < 256:
|
271
|
-
value |= 2
|
272
|
-
try:
|
273
|
-
device.ctrl_transfer(
|
274
|
-
bmRequestType=mCH341_VENDOR_WRITE,
|
275
|
-
bRequest=mCH341_PARA_INIT,
|
276
|
-
wValue=value,
|
277
|
-
wIndex=0,
|
278
|
-
data_or_wLength=0,
|
279
|
-
timeout=self.timeout,
|
280
|
-
)
|
281
|
-
# 0x40, 177, 0x8800, 0, 0
|
282
|
-
except usb.core.USBError as e:
|
283
|
-
self.backend_error_code = e.backend_error_code
|
284
|
-
|
285
|
-
self.channel(str(e))
|
286
|
-
# Device was not found. Timed out, etc.
|
287
|
-
raise ConnectionError
|
288
|
-
|
289
|
-
def CH341SetParaMode(self, index, mode=CH341_PARA_MODE_EPP19):
|
290
|
-
device = self.devices[index]
|
291
|
-
value = 0x2525
|
292
|
-
try:
|
293
|
-
device.ctrl_transfer(
|
294
|
-
bmRequestType=mCH341_VENDOR_WRITE,
|
295
|
-
bRequest=mCH341_SET_PARA_MODE,
|
296
|
-
wValue=value,
|
297
|
-
wIndex=index,
|
298
|
-
data_or_wLength=mode << 8 | mode,
|
299
|
-
timeout=self.timeout,
|
300
|
-
)
|
301
|
-
# 0x40, 154, 0x2525, 257, 0
|
302
|
-
except usb.core.USBError as e:
|
303
|
-
self.backend_error_code = e.backend_error_code
|
304
|
-
|
305
|
-
self.channel(str(e))
|
306
|
-
raise ConnectionError
|
307
|
-
|
308
|
-
# pylint: disable=dangerous-default-value
|
309
|
-
def CH341GetStatus(self, index=0, status=[0]):
|
310
|
-
if self.bulk:
|
311
|
-
return self.CH341GetStatusBulk(index=index, status=status)
|
312
|
-
else:
|
313
|
-
return self.CH341GetStatusControlTransfer(index=index, status=status)
|
314
|
-
|
315
|
-
# pylint: disable=dangerous-default-value
|
316
|
-
def CH341GetStatusControlTransfer(self, index=0, status=[0]):
|
317
|
-
"""D7-0, 8: err, 9: pEmp, 10: Int, 11: SLCT, 12: SDA, 13: Busy, 14: data, 15: addrs"""
|
318
|
-
device = self.devices[index]
|
319
|
-
try:
|
320
|
-
buffer = device.ctrl_transfer(
|
321
|
-
bmRequestType=mCH341_VENDOR_READ,
|
322
|
-
bRequest=mCH341A_STATUS,
|
323
|
-
wValue=0,
|
324
|
-
wIndex=0,
|
325
|
-
data_or_wLength=8,
|
326
|
-
timeout=self.timeout,
|
327
|
-
)
|
328
|
-
status[0] = buffer
|
329
|
-
except usb.core.USBError as e:
|
330
|
-
self.backend_error_code = e.backend_error_code
|
331
|
-
|
332
|
-
self.channel(str(e))
|
333
|
-
raise ConnectionError
|
334
|
-
return status[0]
|
335
|
-
|
336
|
-
# pylint: disable=dangerous-default-value
|
337
|
-
def CH341GetStatusBulk(self, index=0, status=[0]):
|
338
|
-
"""
|
339
|
-
Older bulk based version with a read and write rather than control transfer.
|
340
|
-
|
341
|
-
This version of the status check requires a bulk send of an A0 followed by a read. If the chip is
|
342
|
-
locked up, this will result in timeout errors.
|
343
|
-
|
344
|
-
@param index:
|
345
|
-
@param status:
|
346
|
-
@return:
|
347
|
-
"""
|
348
|
-
device = self.devices[index]
|
349
|
-
try:
|
350
|
-
device.write(
|
351
|
-
endpoint=BULK_WRITE_ENDPOINT,
|
352
|
-
data=[mCH341_PARA_CMD_STS],
|
353
|
-
timeout=self.timeout,
|
354
|
-
)
|
355
|
-
# read(self, endpoint, size_or_buffer, timeout = None)
|
356
|
-
status[0] = device.read(
|
357
|
-
endpoint=BULK_READ_ENDPOINT, size_or_buffer=6, timeout=self.timeout
|
358
|
-
)
|
359
|
-
except usb.core.USBError as e:
|
360
|
-
self.backend_error_code = e.backend_error_code
|
361
|
-
|
362
|
-
self.channel(str(e))
|
363
|
-
raise ConnectionError
|
364
|
-
return status[0]
|
365
|
-
|
366
|
-
def CH341GetVerIC(self, index=0):
|
367
|
-
device = self.devices[index]
|
368
|
-
try:
|
369
|
-
buffer = device.ctrl_transfer(
|
370
|
-
bmRequestType=mCH341_VENDOR_READ,
|
371
|
-
bRequest=mCH341A_GET_VER,
|
372
|
-
wValue=0,
|
373
|
-
wIndex=0,
|
374
|
-
data_or_wLength=2,
|
375
|
-
timeout=self.timeout,
|
376
|
-
)
|
377
|
-
except usb.core.USBError as e:
|
378
|
-
self.backend_error_code = e.backend_error_code
|
379
|
-
|
380
|
-
self.channel(str(e))
|
381
|
-
raise ConnectionError
|
382
|
-
if len(buffer) < 0:
|
383
|
-
return 2
|
384
|
-
else:
|
385
|
-
return (buffer[1] << 8) | buffer[0]
|
386
|
-
|
387
|
-
def CH341EppReadData(
|
388
|
-
self, index=0, buffer=None, length=0
|
389
|
-
): # WR=1, DS=0, AS=1, D0-D7 in
|
390
|
-
self.CH341EppRead(index, buffer, length, 0)
|
391
|
-
|
392
|
-
def CH341EppReadAddr(
|
393
|
-
self, index=0, buffer=None, length=0
|
394
|
-
): # WR=1, DS=0, AS=1 D0-D7 in
|
395
|
-
self.CH341EppRead(index, buffer, length, 1)
|
396
|
-
|
397
|
-
def CH341WriteData(self, index=0, buffer=None):
|
398
|
-
if buffer is None:
|
399
|
-
return
|
400
|
-
device = self.devices[index]
|
401
|
-
packet = list(buffer)
|
402
|
-
try:
|
403
|
-
# endpoint, data, timeout
|
404
|
-
device.write(
|
405
|
-
endpoint=BULK_WRITE_ENDPOINT, data=packet, timeout=self.timeout
|
406
|
-
)
|
407
|
-
except usb.core.USBError as e:
|
408
|
-
self.backend_error_code = e.backend_error_code
|
409
|
-
|
410
|
-
self.channel(str(e))
|
411
|
-
raise ConnectionError
|
412
|
-
|
413
|
-
def CH341EppRead(self, index=0, buffer=None, length=0, pipe=0):
|
414
|
-
try:
|
415
|
-
return self.devices[index].read(
|
416
|
-
endpoint=BULK_READ_ENDPOINT, size_or_buffer=length, timeout=self.timeout
|
417
|
-
)
|
418
|
-
except usb.core.USBError as e:
|
419
|
-
self.backend_error_code = e.backend_error_code
|
420
|
-
|
421
|
-
self.channel(str(e))
|
422
|
-
raise ConnectionError
|
423
|
-
|
424
|
-
def CH341EppWrite(self, index=0, buffer=None, pipe=0):
|
425
|
-
"""
|
426
|
-
EPP Data is written in max 31 bytes prepended with either A7 or A6 (addr/data). With a new value appended
|
427
|
-
each 31 characters.
|
428
|
-
|
429
|
-
@return:
|
430
|
-
"""
|
431
|
-
if buffer is None:
|
432
|
-
return
|
433
|
-
p = mCH341_PARA_CMD_W1 if pipe else mCH341_PARA_CMD_W0
|
434
|
-
device = self.devices[index]
|
435
|
-
data = list(buffer)
|
436
|
-
for i in range(0, len(data) + 1, 32):
|
437
|
-
data.insert(i, p)
|
438
|
-
try:
|
439
|
-
# endpoint, data, timeout
|
440
|
-
device.write(endpoint=BULK_WRITE_ENDPOINT, data=data, timeout=self.timeout)
|
441
|
-
except usb.core.USBError as e:
|
442
|
-
self.backend_error_code = e.backend_error_code
|
443
|
-
|
444
|
-
self.channel(str(e))
|
445
|
-
raise ConnectionError
|
446
|
-
|
447
|
-
def CH341EppWriteData(
|
448
|
-
self,
|
449
|
-
index,
|
450
|
-
buffer=None,
|
451
|
-
): # WR=0, DS=0, AS=1, D0-D7 out
|
452
|
-
self.CH341EppWrite(index, buffer, 0)
|
453
|
-
|
454
|
-
def CH341EppWriteAddr(
|
455
|
-
self,
|
456
|
-
index,
|
457
|
-
buffer=None,
|
458
|
-
): # WR=0, DS=1, AS=0, D0-D7 out
|
459
|
-
self.CH341EppWrite(index, buffer, 1)
|
460
|
-
|
461
|
-
|
462
|
-
class LibCH341Driver:
|
463
|
-
def __init__(
|
464
|
-
self,
|
465
|
-
channel=None,
|
466
|
-
state=None,
|
467
|
-
bulk=None,
|
468
|
-
):
|
469
|
-
self.driver_index = None
|
470
|
-
self.driver_value = None
|
471
|
-
self.channel = channel
|
472
|
-
self.state = state
|
473
|
-
|
474
|
-
self.driver = Ch341LibusbDriver(self.channel, bulk=bulk)
|
475
|
-
|
476
|
-
def is_connected(self):
|
477
|
-
return self.driver_value != -1 and self.driver_index is not None
|
478
|
-
|
479
|
-
@property
|
480
|
-
def driver_name(self):
|
481
|
-
return "LibUsb"
|
482
|
-
|
483
|
-
@property
|
484
|
-
def address(self):
|
485
|
-
if not self.driver:
|
486
|
-
return None
|
487
|
-
return self.driver.address(self.driver_index)
|
488
|
-
|
489
|
-
@property
|
490
|
-
def bus(self):
|
491
|
-
if not self.driver:
|
492
|
-
return None
|
493
|
-
return self.driver.bus(self.driver_index)
|
494
|
-
|
495
|
-
def open(self, usb_index):
|
496
|
-
"""
|
497
|
-
Opens the driver for unknown criteria.
|
498
|
-
"""
|
499
|
-
_ = self.channel._
|
500
|
-
if self.driver_value is None:
|
501
|
-
self.channel(_("Using LibUSB to connect."))
|
502
|
-
self.channel(_("Attempting connection to USB."))
|
503
|
-
self.state("STATE_USB_CONNECTING")
|
504
|
-
try:
|
505
|
-
self.driver_value = self.driver.CH341OpenDevice(usb_index)
|
506
|
-
except usb.core.NoBackendError as e:
|
507
|
-
self.channel(str(e))
|
508
|
-
self.channel(_("PyUsb detected no backend LibUSB driver."))
|
509
|
-
self.driver_value = None
|
510
|
-
self.state("STATE_DRIVER_NO_BACKEND")
|
511
|
-
raise ConnectionRefusedError
|
512
|
-
except ConnectionRefusedError as e:
|
513
|
-
self.channel(_("Connection to USB failed.\n"))
|
514
|
-
self.driver_value = None
|
515
|
-
self.state("STATE_CONNECTION_FAILED")
|
516
|
-
raise ConnectionRefusedError from e # No more devices.
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
self.driver.
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
_("CH341
|
534
|
-
|
535
|
-
|
536
|
-
)
|
537
|
-
self.
|
538
|
-
self.
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
self.
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
self.channel
|
549
|
-
if
|
550
|
-
self.channel(_("USB connection did not exist."))
|
551
|
-
|
552
|
-
self.
|
553
|
-
self.state("
|
554
|
-
self.channel(_("
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
self.
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
1
|
+
import usb.core
|
2
|
+
import usb.util
|
3
|
+
from usb.backend.libusb1 import LIBUSB_ERROR_ACCESS, LIBUSB_ERROR_NOT_FOUND
|
4
|
+
|
5
|
+
STATUS_NO_DEVICE = -1
|
6
|
+
USB_LOCK_VENDOR = 0x1A86 # Dev : (1a86) QinHeng Electronics
|
7
|
+
USB_LOCK_PRODUCT = 0x5512 # (5512) CH341A
|
8
|
+
BULK_WRITE_ENDPOINT = 0x02 # usb.util.ENDPOINT_OUT|usb.util.ENDPOINT_TYPE_BULK
|
9
|
+
BULK_READ_ENDPOINT = 0x82 # usb.util.ENDPOINT_IN|usb.util.ENDPOINT_TYPE_BULK
|
10
|
+
CH341_PARA_MODE_EPP19 = 0x01
|
11
|
+
|
12
|
+
mCH341_PARA_CMD_R0 = 0xAC # 10101100
|
13
|
+
mCH341_PARA_CMD_R1 = 0xAD # 10101101
|
14
|
+
mCH341_PARA_CMD_W0 = 0xA6 # 10100110
|
15
|
+
mCH341_PARA_CMD_W1 = 0xA7 # 10100111
|
16
|
+
mCH341_PARA_CMD_STS = 0xA0 # 10100000
|
17
|
+
|
18
|
+
mCH341_PACKET_LENGTH = 32
|
19
|
+
mCH341_PKT_LEN_SHORT = 8
|
20
|
+
mCH341_SET_PARA_MODE = 0x9A
|
21
|
+
mCH341_PARA_INIT = 0xB1
|
22
|
+
mCH341_VENDOR_READ = 0xC0
|
23
|
+
mCH341_VENDOR_WRITE = 0x40
|
24
|
+
mCH341A_BUF_CLEAR = 0xB2
|
25
|
+
mCH341A_DELAY_MS = 0x5E
|
26
|
+
mCH341A_GET_VER = 0x5F
|
27
|
+
mCH341A_STATUS = 0x52
|
28
|
+
|
29
|
+
|
30
|
+
class Ch341LibusbDriver:
|
31
|
+
"""
|
32
|
+
Libusb driver for the CH341 chip. The CH341x is a USB interface chip that can emulate UART, parallel port,
|
33
|
+
and synchronous serial (EPP, I2C, SPI). The Lihuiyu boards (M2Nano, et al.) and Moshiboards and likely others
|
34
|
+
use this in EPP 1.9 mode. This class is not and not intended to be a full driver for that chip. Rather we are
|
35
|
+
duplicating the function calls and implementing compatible operations to permit a stand-in for the default CH341
|
36
|
+
driver. Using libusb to do the usb connection to the chip as well as permitting easy swapping that for the default
|
37
|
+
driver. This serves as the basis to permit multiple operative methods, permitting use of either the default driver
|
38
|
+
or Libusb driver interchangeably.
|
39
|
+
|
40
|
+
Since these functions will need swapping in MSW we should duplicate the function calls thereof. Also since a stated
|
41
|
+
goal is to support multiple devices implicitly, we should also properly support multiple device functionality.
|
42
|
+
|
43
|
+
To this end, this should duplicate the names of the function calls. And the use of index to reference which
|
44
|
+
connection to use for each command.
|
45
|
+
|
46
|
+
All the commands during the opening phase will raise a ConnectionRefusedError.
|
47
|
+
All commands during read and write raise ConnectionErrors
|
48
|
+
All commands during close don't care about errors, if it broke it's likely already closed.
|
49
|
+
"""
|
50
|
+
|
51
|
+
def __init__(self, channel, bulk=True):
|
52
|
+
self.devices = {}
|
53
|
+
self.interface = {}
|
54
|
+
self.channel = channel
|
55
|
+
self.backend_error_code = None
|
56
|
+
self.timeout = 1500
|
57
|
+
self.bulk = bulk
|
58
|
+
|
59
|
+
def find_device(self, index=0):
|
60
|
+
_ = self.channel._
|
61
|
+
self.channel("\n")
|
62
|
+
self.channel(_("Finding devices."))
|
63
|
+
try:
|
64
|
+
devices = list(
|
65
|
+
usb.core.find(
|
66
|
+
idVendor=USB_LOCK_VENDOR, idProduct=USB_LOCK_PRODUCT, find_all=True
|
67
|
+
)
|
68
|
+
)
|
69
|
+
except usb.core.USBError as e:
|
70
|
+
self.backend_error_code = e.backend_error_code
|
71
|
+
self.channel(str(e))
|
72
|
+
if self.backend_error_code == LIBUSB_ERROR_ACCESS:
|
73
|
+
self.channel(_("Your OS does not give you permissions to access USB."))
|
74
|
+
raise PermissionError
|
75
|
+
elif self.backend_error_code == LIBUSB_ERROR_NOT_FOUND:
|
76
|
+
self.channel(
|
77
|
+
_(
|
78
|
+
"K40 devices were found. But something else was connected to them."
|
79
|
+
)
|
80
|
+
)
|
81
|
+
raise ConnectionRefusedError
|
82
|
+
if len(devices) == 0:
|
83
|
+
self.channel(_("Devices Not Found."))
|
84
|
+
raise IndexError
|
85
|
+
else:
|
86
|
+
self.channel(_("{count} device(s) were found.").format(count=len(devices)))
|
87
|
+
if index >= len(devices):
|
88
|
+
self.channel(
|
89
|
+
_("Device index {index} exceeds devices found.").format(index=index)
|
90
|
+
)
|
91
|
+
raise IndexError
|
92
|
+
|
93
|
+
device = devices[index]
|
94
|
+
self.channel(_("K40 device detected:"))
|
95
|
+
string = str(device)
|
96
|
+
string = string.replace("\n", "\n\t")
|
97
|
+
self.channel(string)
|
98
|
+
return device
|
99
|
+
|
100
|
+
def detach_kernel(self, device, interface):
|
101
|
+
_ = self.channel._
|
102
|
+
try:
|
103
|
+
if device.is_kernel_driver_active(interface.bInterfaceNumber):
|
104
|
+
self.channel(_("Attempting to detach kernel."))
|
105
|
+
device.detach_kernel_driver(interface.bInterfaceNumber)
|
106
|
+
self.channel(_("Kernel detach: Success."))
|
107
|
+
except usb.core.USBError as e:
|
108
|
+
self.backend_error_code = e.backend_error_code
|
109
|
+
|
110
|
+
self.channel(str(e))
|
111
|
+
self.channel(_("Kernel detach: Failed."))
|
112
|
+
raise ConnectionRefusedError
|
113
|
+
except NotImplementedError:
|
114
|
+
self.channel(
|
115
|
+
_("Kernel detach: Not Implemented.")
|
116
|
+
) # Driver does not permit kernel detaching.
|
117
|
+
# Non-fatal error.
|
118
|
+
|
119
|
+
def get_active_config(self, device):
|
120
|
+
_ = self.channel._
|
121
|
+
self.channel(_("Getting Active Config"))
|
122
|
+
try:
|
123
|
+
interface = device.get_active_configuration()[(0, 0)]
|
124
|
+
self.channel(_("Active Config: Success."))
|
125
|
+
return interface
|
126
|
+
except usb.core.USBError as e:
|
127
|
+
self.backend_error_code = e.backend_error_code
|
128
|
+
|
129
|
+
self.channel(str(e))
|
130
|
+
self.channel(_("Active Config: Failed."))
|
131
|
+
raise ConnectionRefusedError
|
132
|
+
|
133
|
+
def set_config(self, device):
|
134
|
+
_ = self.channel._
|
135
|
+
self.channel(_("Config Set"))
|
136
|
+
try:
|
137
|
+
device.set_configuration()
|
138
|
+
self.channel(_("Config Set: Success"))
|
139
|
+
except usb.core.USBError as e:
|
140
|
+
self.backend_error_code = e.backend_error_code
|
141
|
+
|
142
|
+
self.channel(str(e))
|
143
|
+
self.channel(
|
144
|
+
_(
|
145
|
+
"Config Set: Fail\n(Hint: may recover if you change where the USB is plugged in.)"
|
146
|
+
)
|
147
|
+
)
|
148
|
+
# raise ConnectionRefusedError
|
149
|
+
except NotImplementedError:
|
150
|
+
self.channel(
|
151
|
+
_(
|
152
|
+
"Config Set: Fail\nSet Configuration is not implemented on this platform. Pass."
|
153
|
+
)
|
154
|
+
)
|
155
|
+
|
156
|
+
def claim_interface(self, device, interface):
|
157
|
+
_ = self.channel._
|
158
|
+
try:
|
159
|
+
self.channel(_("Attempting to claim interface."))
|
160
|
+
usb.util.claim_interface(device, interface)
|
161
|
+
self.channel(_("Interface claim: Success"))
|
162
|
+
except usb.core.USBError as e:
|
163
|
+
self.backend_error_code = e.backend_error_code
|
164
|
+
|
165
|
+
self.channel(str(e))
|
166
|
+
self.channel(_("Interface claim: Failed. (Interface is in use.)"))
|
167
|
+
raise ConnectionRefusedError
|
168
|
+
# Already in use. This is critical.
|
169
|
+
|
170
|
+
def disconnect_detach(self, device, interface):
|
171
|
+
_ = self.channel._
|
172
|
+
try:
|
173
|
+
self.channel(_("Attempting kernel attach"))
|
174
|
+
device.attach_kernel_driver(interface.bInterfaceNumber)
|
175
|
+
self.channel(_("Kernel attach: Success."))
|
176
|
+
except usb.core.USBError as e:
|
177
|
+
self.backend_error_code = e.backend_error_code
|
178
|
+
|
179
|
+
self.channel(str(e))
|
180
|
+
self.channel(_("Kernel attach: Fail."))
|
181
|
+
# Continue and hope it is non-critical.
|
182
|
+
except NotImplementedError:
|
183
|
+
self.channel(_("Kernel attach: Fail."))
|
184
|
+
|
185
|
+
def unclaim_interface(self, device, interface):
|
186
|
+
_ = self.channel._
|
187
|
+
try:
|
188
|
+
self.channel(_("Attempting to release interface."))
|
189
|
+
usb.util.release_interface(device, interface)
|
190
|
+
self.channel(_("Interface released."))
|
191
|
+
except usb.core.USBError as e:
|
192
|
+
self.backend_error_code = e.backend_error_code
|
193
|
+
|
194
|
+
self.channel(str(e))
|
195
|
+
self.channel(_("Interface did not exist."))
|
196
|
+
|
197
|
+
def disconnect_dispose(self, device):
|
198
|
+
_ = self.channel._
|
199
|
+
try:
|
200
|
+
self.channel(_("Attempting to dispose resources."))
|
201
|
+
usb.util.dispose_resources(device)
|
202
|
+
self.channel(_("Dispose Resources: Success"))
|
203
|
+
except usb.core.USBError as e:
|
204
|
+
self.backend_error_code = e.backend_error_code
|
205
|
+
|
206
|
+
self.channel(str(e))
|
207
|
+
self.channel(_("Dispose Resources: Fail"))
|
208
|
+
|
209
|
+
def disconnect_reset(self, device):
|
210
|
+
_ = self.channel._
|
211
|
+
try:
|
212
|
+
self.channel(_("Attempting USB reset."))
|
213
|
+
device.reset()
|
214
|
+
self.channel(_("USB connection reset."))
|
215
|
+
except usb.core.USBError as e:
|
216
|
+
self.backend_error_code = e.backend_error_code
|
217
|
+
|
218
|
+
self.channel(str(e))
|
219
|
+
self.channel(_("USB connection did not exist."))
|
220
|
+
|
221
|
+
def bus(self, index):
|
222
|
+
return self.devices[index].bus
|
223
|
+
|
224
|
+
def address(self, index):
|
225
|
+
return self.devices[index].address
|
226
|
+
|
227
|
+
def CH341OpenDevice(self, index=0):
|
228
|
+
"""
|
229
|
+
Opens device, returns index.
|
230
|
+
|
231
|
+
Can throw a variety of USBErrors, IndexErrors, Backend errors.
|
232
|
+
"""
|
233
|
+
_ = self.channel._
|
234
|
+
device = self.find_device(index)
|
235
|
+
self.devices[index] = device
|
236
|
+
self.set_config(device)
|
237
|
+
interface = self.get_active_config(device)
|
238
|
+
self.interface[index] = interface
|
239
|
+
|
240
|
+
self.detach_kernel(device, interface)
|
241
|
+
try:
|
242
|
+
self.claim_interface(device, interface)
|
243
|
+
except ConnectionRefusedError:
|
244
|
+
# Attempting interface cycle.
|
245
|
+
self.unclaim_interface(device, interface)
|
246
|
+
self.claim_interface(device, interface)
|
247
|
+
return index
|
248
|
+
|
249
|
+
def CH341CloseDevice(self, index=0):
|
250
|
+
"""Closes device."""
|
251
|
+
_ = self.channel._
|
252
|
+
device = self.devices[index]
|
253
|
+
interface = self.interface[index]
|
254
|
+
if device is not None:
|
255
|
+
try:
|
256
|
+
self.disconnect_detach(device, interface)
|
257
|
+
self.unclaim_interface(device, interface)
|
258
|
+
self.disconnect_dispose(device)
|
259
|
+
self.disconnect_reset(device)
|
260
|
+
except ConnectionError:
|
261
|
+
pass
|
262
|
+
|
263
|
+
def CH341InitParallel(
|
264
|
+
self, index=0, mode=CH341_PARA_MODE_EPP19
|
265
|
+
): # Mode 1, we need EPP 1.9
|
266
|
+
"""Permits setting a mode, but our mode is only 1 since the device is using
|
267
|
+
EPP 1.9. This is a control transfer event."""
|
268
|
+
device = self.devices[index]
|
269
|
+
value = mode << 8
|
270
|
+
if mode < 256:
|
271
|
+
value |= 2
|
272
|
+
try:
|
273
|
+
device.ctrl_transfer(
|
274
|
+
bmRequestType=mCH341_VENDOR_WRITE,
|
275
|
+
bRequest=mCH341_PARA_INIT,
|
276
|
+
wValue=value,
|
277
|
+
wIndex=0,
|
278
|
+
data_or_wLength=0,
|
279
|
+
timeout=self.timeout,
|
280
|
+
)
|
281
|
+
# 0x40, 177, 0x8800, 0, 0
|
282
|
+
except usb.core.USBError as e:
|
283
|
+
self.backend_error_code = e.backend_error_code
|
284
|
+
|
285
|
+
self.channel(str(e))
|
286
|
+
# Device was not found. Timed out, etc.
|
287
|
+
raise ConnectionError
|
288
|
+
|
289
|
+
def CH341SetParaMode(self, index, mode=CH341_PARA_MODE_EPP19):
|
290
|
+
device = self.devices[index]
|
291
|
+
value = 0x2525
|
292
|
+
try:
|
293
|
+
device.ctrl_transfer(
|
294
|
+
bmRequestType=mCH341_VENDOR_WRITE,
|
295
|
+
bRequest=mCH341_SET_PARA_MODE,
|
296
|
+
wValue=value,
|
297
|
+
wIndex=index,
|
298
|
+
data_or_wLength=mode << 8 | mode,
|
299
|
+
timeout=self.timeout,
|
300
|
+
)
|
301
|
+
# 0x40, 154, 0x2525, 257, 0
|
302
|
+
except usb.core.USBError as e:
|
303
|
+
self.backend_error_code = e.backend_error_code
|
304
|
+
|
305
|
+
self.channel(str(e))
|
306
|
+
raise ConnectionError
|
307
|
+
|
308
|
+
# pylint: disable=dangerous-default-value
|
309
|
+
def CH341GetStatus(self, index=0, status=[0]):
|
310
|
+
if self.bulk:
|
311
|
+
return self.CH341GetStatusBulk(index=index, status=status)
|
312
|
+
else:
|
313
|
+
return self.CH341GetStatusControlTransfer(index=index, status=status)
|
314
|
+
|
315
|
+
# pylint: disable=dangerous-default-value
|
316
|
+
def CH341GetStatusControlTransfer(self, index=0, status=[0]):
|
317
|
+
"""D7-0, 8: err, 9: pEmp, 10: Int, 11: SLCT, 12: SDA, 13: Busy, 14: data, 15: addrs"""
|
318
|
+
device = self.devices[index]
|
319
|
+
try:
|
320
|
+
buffer = device.ctrl_transfer(
|
321
|
+
bmRequestType=mCH341_VENDOR_READ,
|
322
|
+
bRequest=mCH341A_STATUS,
|
323
|
+
wValue=0,
|
324
|
+
wIndex=0,
|
325
|
+
data_or_wLength=8,
|
326
|
+
timeout=self.timeout,
|
327
|
+
)
|
328
|
+
status[0] = buffer
|
329
|
+
except usb.core.USBError as e:
|
330
|
+
self.backend_error_code = e.backend_error_code
|
331
|
+
|
332
|
+
self.channel(str(e))
|
333
|
+
raise ConnectionError
|
334
|
+
return status[0]
|
335
|
+
|
336
|
+
# pylint: disable=dangerous-default-value
|
337
|
+
def CH341GetStatusBulk(self, index=0, status=[0]):
|
338
|
+
"""
|
339
|
+
Older bulk based version with a read and write rather than control transfer.
|
340
|
+
|
341
|
+
This version of the status check requires a bulk send of an A0 followed by a read. If the chip is
|
342
|
+
locked up, this will result in timeout errors.
|
343
|
+
|
344
|
+
@param index:
|
345
|
+
@param status:
|
346
|
+
@return:
|
347
|
+
"""
|
348
|
+
device = self.devices[index]
|
349
|
+
try:
|
350
|
+
device.write(
|
351
|
+
endpoint=BULK_WRITE_ENDPOINT,
|
352
|
+
data=[mCH341_PARA_CMD_STS],
|
353
|
+
timeout=self.timeout,
|
354
|
+
)
|
355
|
+
# read(self, endpoint, size_or_buffer, timeout = None)
|
356
|
+
status[0] = device.read(
|
357
|
+
endpoint=BULK_READ_ENDPOINT, size_or_buffer=6, timeout=self.timeout
|
358
|
+
)
|
359
|
+
except usb.core.USBError as e:
|
360
|
+
self.backend_error_code = e.backend_error_code
|
361
|
+
|
362
|
+
self.channel(str(e))
|
363
|
+
raise ConnectionError
|
364
|
+
return status[0]
|
365
|
+
|
366
|
+
def CH341GetVerIC(self, index=0):
|
367
|
+
device = self.devices[index]
|
368
|
+
try:
|
369
|
+
buffer = device.ctrl_transfer(
|
370
|
+
bmRequestType=mCH341_VENDOR_READ,
|
371
|
+
bRequest=mCH341A_GET_VER,
|
372
|
+
wValue=0,
|
373
|
+
wIndex=0,
|
374
|
+
data_or_wLength=2,
|
375
|
+
timeout=self.timeout,
|
376
|
+
)
|
377
|
+
except usb.core.USBError as e:
|
378
|
+
self.backend_error_code = e.backend_error_code
|
379
|
+
|
380
|
+
self.channel(str(e))
|
381
|
+
raise ConnectionError
|
382
|
+
if len(buffer) < 0:
|
383
|
+
return 2
|
384
|
+
else:
|
385
|
+
return (buffer[1] << 8) | buffer[0]
|
386
|
+
|
387
|
+
def CH341EppReadData(
|
388
|
+
self, index=0, buffer=None, length=0
|
389
|
+
): # WR=1, DS=0, AS=1, D0-D7 in
|
390
|
+
self.CH341EppRead(index, buffer, length, 0)
|
391
|
+
|
392
|
+
def CH341EppReadAddr(
|
393
|
+
self, index=0, buffer=None, length=0
|
394
|
+
): # WR=1, DS=0, AS=1 D0-D7 in
|
395
|
+
self.CH341EppRead(index, buffer, length, 1)
|
396
|
+
|
397
|
+
def CH341WriteData(self, index=0, buffer=None):
|
398
|
+
if buffer is None:
|
399
|
+
return
|
400
|
+
device = self.devices[index]
|
401
|
+
packet = list(buffer)
|
402
|
+
try:
|
403
|
+
# endpoint, data, timeout
|
404
|
+
device.write(
|
405
|
+
endpoint=BULK_WRITE_ENDPOINT, data=packet, timeout=self.timeout
|
406
|
+
)
|
407
|
+
except usb.core.USBError as e:
|
408
|
+
self.backend_error_code = e.backend_error_code
|
409
|
+
|
410
|
+
self.channel(str(e))
|
411
|
+
raise ConnectionError
|
412
|
+
|
413
|
+
def CH341EppRead(self, index=0, buffer=None, length=0, pipe=0):
|
414
|
+
try:
|
415
|
+
return self.devices[index].read(
|
416
|
+
endpoint=BULK_READ_ENDPOINT, size_or_buffer=length, timeout=self.timeout
|
417
|
+
)
|
418
|
+
except usb.core.USBError as e:
|
419
|
+
self.backend_error_code = e.backend_error_code
|
420
|
+
|
421
|
+
self.channel(str(e))
|
422
|
+
raise ConnectionError
|
423
|
+
|
424
|
+
def CH341EppWrite(self, index=0, buffer=None, pipe=0):
|
425
|
+
"""
|
426
|
+
EPP Data is written in max 31 bytes prepended with either A7 or A6 (addr/data). With a new value appended
|
427
|
+
each 31 characters.
|
428
|
+
|
429
|
+
@return:
|
430
|
+
"""
|
431
|
+
if buffer is None:
|
432
|
+
return
|
433
|
+
p = mCH341_PARA_CMD_W1 if pipe else mCH341_PARA_CMD_W0
|
434
|
+
device = self.devices[index]
|
435
|
+
data = list(buffer)
|
436
|
+
for i in range(0, len(data) + 1, 32):
|
437
|
+
data.insert(i, p)
|
438
|
+
try:
|
439
|
+
# endpoint, data, timeout
|
440
|
+
device.write(endpoint=BULK_WRITE_ENDPOINT, data=data, timeout=self.timeout)
|
441
|
+
except usb.core.USBError as e:
|
442
|
+
self.backend_error_code = e.backend_error_code
|
443
|
+
|
444
|
+
self.channel(str(e))
|
445
|
+
raise ConnectionError
|
446
|
+
|
447
|
+
def CH341EppWriteData(
|
448
|
+
self,
|
449
|
+
index,
|
450
|
+
buffer=None,
|
451
|
+
): # WR=0, DS=0, AS=1, D0-D7 out
|
452
|
+
self.CH341EppWrite(index, buffer, 0)
|
453
|
+
|
454
|
+
def CH341EppWriteAddr(
|
455
|
+
self,
|
456
|
+
index,
|
457
|
+
buffer=None,
|
458
|
+
): # WR=0, DS=1, AS=0, D0-D7 out
|
459
|
+
self.CH341EppWrite(index, buffer, 1)
|
460
|
+
|
461
|
+
|
462
|
+
class LibCH341Driver:
|
463
|
+
def __init__(
|
464
|
+
self,
|
465
|
+
channel=None,
|
466
|
+
state=None,
|
467
|
+
bulk=None,
|
468
|
+
):
|
469
|
+
self.driver_index = None
|
470
|
+
self.driver_value = None
|
471
|
+
self.channel = channel
|
472
|
+
self.state = state
|
473
|
+
|
474
|
+
self.driver = Ch341LibusbDriver(self.channel, bulk=bulk)
|
475
|
+
|
476
|
+
def is_connected(self):
|
477
|
+
return self.driver_value != -1 and self.driver_index is not None
|
478
|
+
|
479
|
+
@property
|
480
|
+
def driver_name(self):
|
481
|
+
return "LibUsb"
|
482
|
+
|
483
|
+
@property
|
484
|
+
def address(self):
|
485
|
+
if not self.driver:
|
486
|
+
return None
|
487
|
+
return self.driver.address(self.driver_index)
|
488
|
+
|
489
|
+
@property
|
490
|
+
def bus(self):
|
491
|
+
if not self.driver:
|
492
|
+
return None
|
493
|
+
return self.driver.bus(self.driver_index)
|
494
|
+
|
495
|
+
def open(self, usb_index):
|
496
|
+
"""
|
497
|
+
Opens the driver for unknown criteria.
|
498
|
+
"""
|
499
|
+
_ = self.channel._
|
500
|
+
if self.driver_value is None:
|
501
|
+
self.channel(_("Using LibUSB to connect."))
|
502
|
+
self.channel(_("Attempting connection to USB."))
|
503
|
+
self.state("STATE_USB_CONNECTING")
|
504
|
+
try:
|
505
|
+
self.driver_value = self.driver.CH341OpenDevice(usb_index)
|
506
|
+
except usb.core.NoBackendError as e:
|
507
|
+
self.channel(str(e))
|
508
|
+
self.channel(_("PyUsb detected no backend LibUSB driver."))
|
509
|
+
self.driver_value = None
|
510
|
+
self.state("STATE_DRIVER_NO_BACKEND")
|
511
|
+
raise ConnectionRefusedError
|
512
|
+
except ConnectionRefusedError as e:
|
513
|
+
self.channel(_("Connection to USB failed.\n"))
|
514
|
+
self.driver_value = None
|
515
|
+
self.state("STATE_CONNECTION_FAILED")
|
516
|
+
raise ConnectionRefusedError from e # No more devices.
|
517
|
+
except Exception as e:
|
518
|
+
self.channel(_("Connection to USB failed: {e}.\n"))
|
519
|
+
self.driver_value = None
|
520
|
+
self.state("STATE_CONNECTION_FAILED")
|
521
|
+
raise ConnectionRefusedError from e # No more devices.
|
522
|
+
|
523
|
+
self.driver_index = usb_index
|
524
|
+
self.channel(_("USB Connected."))
|
525
|
+
self.state("STATE_USB_CONNECTED")
|
526
|
+
self.channel(_("Sending CH341 mode change to EPP1.9."))
|
527
|
+
try:
|
528
|
+
self.driver.CH341InitParallel(
|
529
|
+
self.driver_index, 1
|
530
|
+
) # 0x40, 177, 0x8800, 0, 0
|
531
|
+
self.channel(_("CH341 mode change to EPP1.9: Success."))
|
532
|
+
except ConnectionError:
|
533
|
+
self.channel(_("CH341 mode change to EPP1.9: Fail."))
|
534
|
+
self.driver.CH341CloseDevice(self.driver_index)
|
535
|
+
raise ConnectionRefusedError
|
536
|
+
self.channel(_("Device Connected.\n"))
|
537
|
+
chip_version = self.get_chip_version()
|
538
|
+
self.channel(
|
539
|
+
_("CH341 Chip Version: {chip_version}").format(
|
540
|
+
chip_version=chip_version
|
541
|
+
)
|
542
|
+
)
|
543
|
+
self.channel(_("Driver Detected: LibUsb"))
|
544
|
+
self.state("STATE_CONNECTED")
|
545
|
+
self.channel(_("Device Connected.\n"))
|
546
|
+
|
547
|
+
def close(self):
|
548
|
+
_ = self.channel._
|
549
|
+
if not self.is_connected():
|
550
|
+
self.channel(_("USB connection did not exist."))
|
551
|
+
return
|
552
|
+
self.driver_value = None
|
553
|
+
self.state("STATE_USB_SET_DISCONNECTING")
|
554
|
+
self.channel(_("Attempting disconnection from USB."))
|
555
|
+
if self.driver_value == -1 or self.driver_index is None:
|
556
|
+
self.channel(_("USB connection did not exist."))
|
557
|
+
raise ConnectionError
|
558
|
+
self.driver.CH341CloseDevice(self.driver_index)
|
559
|
+
self.state("STATE_USB_DISCONNECTED")
|
560
|
+
self.channel(_("USB Disconnection Successful.\n"))
|
561
|
+
|
562
|
+
def reset(self):
|
563
|
+
if not self.is_connected():
|
564
|
+
raise ConnectionError
|
565
|
+
self.driver.disconnect_reset(self.driver_index)
|
566
|
+
|
567
|
+
def release(self):
|
568
|
+
if not self.is_connected():
|
569
|
+
raise ConnectionError
|
570
|
+
self.driver.disconnect_dispose(self.driver_index)
|
571
|
+
|
572
|
+
def write(self, packet):
|
573
|
+
if not self.is_connected():
|
574
|
+
raise ConnectionError
|
575
|
+
self.driver.CH341EppWriteData(self.driver_index, packet)
|
576
|
+
|
577
|
+
def write_addr(self, packet):
|
578
|
+
if not self.is_connected():
|
579
|
+
raise ConnectionError
|
580
|
+
self.driver.CH341EppWriteAddr(self.driver_index, packet)
|
581
|
+
|
582
|
+
def get_status(self):
|
583
|
+
if not self.is_connected():
|
584
|
+
raise ConnectionError
|
585
|
+
return self.driver.CH341GetStatus(self.driver_index)
|
586
|
+
|
587
|
+
def get_chip_version(self):
|
588
|
+
"""
|
589
|
+
Gets the version of the CH341 chip being used.
|
590
|
+
@return: version. E.g. 48.
|
591
|
+
"""
|
592
|
+
if not self.is_connected():
|
593
|
+
raise ConnectionError
|
594
|
+
# 48, reads 0xc0, 95, 0, 0 (30,00? = 48)
|
595
|
+
return self.driver.CH341GetVerIC(self.driver_index)
|