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.
Files changed (445) hide show
  1. meerk40t/__init__.py +1 -1
  2. meerk40t/balormk/balor_params.py +167 -167
  3. meerk40t/balormk/clone_loader.py +457 -457
  4. meerk40t/balormk/controller.py +1566 -1512
  5. meerk40t/balormk/cylindermod.py +64 -0
  6. meerk40t/balormk/device.py +966 -1959
  7. meerk40t/balormk/driver.py +778 -591
  8. meerk40t/balormk/galvo_commands.py +1195 -0
  9. meerk40t/balormk/gui/balorconfig.py +237 -111
  10. meerk40t/balormk/gui/balorcontroller.py +191 -184
  11. meerk40t/balormk/gui/baloroperationproperties.py +116 -115
  12. meerk40t/balormk/gui/corscene.py +845 -0
  13. meerk40t/balormk/gui/gui.py +179 -147
  14. meerk40t/balormk/livelightjob.py +466 -382
  15. meerk40t/balormk/mock_connection.py +131 -109
  16. meerk40t/balormk/plugin.py +133 -135
  17. meerk40t/balormk/usb_connection.py +306 -301
  18. meerk40t/camera/__init__.py +1 -1
  19. meerk40t/camera/camera.py +514 -397
  20. meerk40t/camera/gui/camerapanel.py +1241 -1095
  21. meerk40t/camera/gui/gui.py +58 -58
  22. meerk40t/camera/plugin.py +441 -399
  23. meerk40t/ch341/__init__.py +27 -27
  24. meerk40t/ch341/ch341device.py +628 -628
  25. meerk40t/ch341/libusb.py +595 -589
  26. meerk40t/ch341/mock.py +171 -171
  27. meerk40t/ch341/windriver.py +157 -157
  28. meerk40t/constants.py +13 -0
  29. meerk40t/core/__init__.py +1 -1
  30. meerk40t/core/bindalias.py +550 -539
  31. meerk40t/core/core.py +47 -47
  32. meerk40t/core/cutcode/cubiccut.py +73 -73
  33. meerk40t/core/cutcode/cutcode.py +315 -312
  34. meerk40t/core/cutcode/cutgroup.py +141 -137
  35. meerk40t/core/cutcode/cutobject.py +192 -185
  36. meerk40t/core/cutcode/dwellcut.py +37 -37
  37. meerk40t/core/cutcode/gotocut.py +29 -29
  38. meerk40t/core/cutcode/homecut.py +29 -29
  39. meerk40t/core/cutcode/inputcut.py +34 -34
  40. meerk40t/core/cutcode/linecut.py +33 -33
  41. meerk40t/core/cutcode/outputcut.py +34 -34
  42. meerk40t/core/cutcode/plotcut.py +335 -335
  43. meerk40t/core/cutcode/quadcut.py +61 -61
  44. meerk40t/core/cutcode/rastercut.py +168 -148
  45. meerk40t/core/cutcode/waitcut.py +34 -34
  46. meerk40t/core/cutplan.py +1843 -1316
  47. meerk40t/core/drivers.py +330 -329
  48. meerk40t/core/elements/align.py +801 -669
  49. meerk40t/core/elements/branches.py +1844 -1507
  50. meerk40t/core/elements/clipboard.py +229 -219
  51. meerk40t/core/elements/element_treeops.py +4561 -2837
  52. meerk40t/core/elements/element_types.py +125 -105
  53. meerk40t/core/elements/elements.py +4329 -3617
  54. meerk40t/core/elements/files.py +117 -64
  55. meerk40t/core/elements/geometry.py +473 -224
  56. meerk40t/core/elements/grid.py +467 -316
  57. meerk40t/core/elements/materials.py +158 -94
  58. meerk40t/core/elements/notes.py +50 -38
  59. meerk40t/core/elements/offset_clpr.py +933 -912
  60. meerk40t/core/elements/offset_mk.py +963 -955
  61. meerk40t/core/elements/penbox.py +339 -267
  62. meerk40t/core/elements/placements.py +300 -83
  63. meerk40t/core/elements/render.py +785 -687
  64. meerk40t/core/elements/shapes.py +2618 -2092
  65. meerk40t/core/elements/trace.py +651 -563
  66. meerk40t/core/elements/tree_commands.py +415 -409
  67. meerk40t/core/elements/undo_redo.py +116 -58
  68. meerk40t/core/elements/wordlist.py +319 -200
  69. meerk40t/core/exceptions.py +9 -9
  70. meerk40t/core/laserjob.py +220 -220
  71. meerk40t/core/logging.py +63 -63
  72. meerk40t/core/node/blobnode.py +83 -86
  73. meerk40t/core/node/bootstrap.py +105 -103
  74. meerk40t/core/node/branch_elems.py +40 -31
  75. meerk40t/core/node/branch_ops.py +45 -38
  76. meerk40t/core/node/branch_regmark.py +48 -41
  77. meerk40t/core/node/cutnode.py +29 -32
  78. meerk40t/core/node/effect_hatch.py +375 -257
  79. meerk40t/core/node/effect_warp.py +398 -0
  80. meerk40t/core/node/effect_wobble.py +441 -309
  81. meerk40t/core/node/elem_ellipse.py +404 -309
  82. meerk40t/core/node/elem_image.py +1082 -801
  83. meerk40t/core/node/elem_line.py +358 -292
  84. meerk40t/core/node/elem_path.py +259 -201
  85. meerk40t/core/node/elem_point.py +129 -102
  86. meerk40t/core/node/elem_polyline.py +310 -246
  87. meerk40t/core/node/elem_rect.py +376 -286
  88. meerk40t/core/node/elem_text.py +445 -418
  89. meerk40t/core/node/filenode.py +59 -40
  90. meerk40t/core/node/groupnode.py +138 -74
  91. meerk40t/core/node/image_processed.py +777 -766
  92. meerk40t/core/node/image_raster.py +156 -113
  93. meerk40t/core/node/layernode.py +31 -31
  94. meerk40t/core/node/mixins.py +135 -107
  95. meerk40t/core/node/node.py +1427 -1304
  96. meerk40t/core/node/nutils.py +117 -114
  97. meerk40t/core/node/op_cut.py +462 -335
  98. meerk40t/core/node/op_dots.py +296 -251
  99. meerk40t/core/node/op_engrave.py +414 -311
  100. meerk40t/core/node/op_image.py +755 -369
  101. meerk40t/core/node/op_raster.py +787 -522
  102. meerk40t/core/node/place_current.py +37 -40
  103. meerk40t/core/node/place_point.py +329 -126
  104. meerk40t/core/node/refnode.py +58 -47
  105. meerk40t/core/node/rootnode.py +225 -219
  106. meerk40t/core/node/util_console.py +48 -48
  107. meerk40t/core/node/util_goto.py +84 -65
  108. meerk40t/core/node/util_home.py +61 -61
  109. meerk40t/core/node/util_input.py +102 -102
  110. meerk40t/core/node/util_output.py +102 -102
  111. meerk40t/core/node/util_wait.py +65 -65
  112. meerk40t/core/parameters.py +709 -707
  113. meerk40t/core/planner.py +875 -785
  114. meerk40t/core/plotplanner.py +656 -652
  115. meerk40t/core/space.py +120 -113
  116. meerk40t/core/spoolers.py +706 -705
  117. meerk40t/core/svg_io.py +1836 -1549
  118. meerk40t/core/treeop.py +534 -445
  119. meerk40t/core/undos.py +278 -124
  120. meerk40t/core/units.py +784 -680
  121. meerk40t/core/view.py +393 -322
  122. meerk40t/core/webhelp.py +62 -62
  123. meerk40t/core/wordlist.py +513 -504
  124. meerk40t/cylinder/cylinder.py +247 -0
  125. meerk40t/cylinder/gui/cylindersettings.py +41 -0
  126. meerk40t/cylinder/gui/gui.py +24 -0
  127. meerk40t/device/__init__.py +1 -1
  128. meerk40t/device/basedevice.py +322 -123
  129. meerk40t/device/devicechoices.py +50 -0
  130. meerk40t/device/dummydevice.py +163 -128
  131. meerk40t/device/gui/defaultactions.py +618 -602
  132. meerk40t/device/gui/effectspanel.py +114 -0
  133. meerk40t/device/gui/formatterpanel.py +253 -290
  134. meerk40t/device/gui/warningpanel.py +337 -260
  135. meerk40t/device/mixins.py +13 -13
  136. meerk40t/dxf/__init__.py +1 -1
  137. meerk40t/dxf/dxf_io.py +766 -554
  138. meerk40t/dxf/plugin.py +47 -35
  139. meerk40t/external_plugins.py +79 -79
  140. meerk40t/external_plugins_build.py +28 -28
  141. meerk40t/extra/cag.py +112 -116
  142. meerk40t/extra/coolant.py +403 -0
  143. meerk40t/extra/encode_detect.py +198 -0
  144. meerk40t/extra/ezd.py +1165 -1165
  145. meerk40t/extra/hershey.py +835 -340
  146. meerk40t/extra/imageactions.py +322 -316
  147. meerk40t/extra/inkscape.py +630 -622
  148. meerk40t/extra/lbrn.py +424 -424
  149. meerk40t/extra/outerworld.py +284 -0
  150. meerk40t/extra/param_functions.py +1542 -1556
  151. meerk40t/extra/potrace.py +257 -253
  152. meerk40t/extra/serial_exchange.py +118 -0
  153. meerk40t/extra/updater.py +602 -453
  154. meerk40t/extra/vectrace.py +147 -146
  155. meerk40t/extra/winsleep.py +83 -83
  156. meerk40t/extra/xcs_reader.py +597 -0
  157. meerk40t/fill/fills.py +781 -335
  158. meerk40t/fill/patternfill.py +1061 -1061
  159. meerk40t/fill/patterns.py +614 -567
  160. meerk40t/grbl/control.py +87 -87
  161. meerk40t/grbl/controller.py +990 -903
  162. meerk40t/grbl/device.py +1081 -768
  163. meerk40t/grbl/driver.py +989 -771
  164. meerk40t/grbl/emulator.py +532 -497
  165. meerk40t/grbl/gcodejob.py +783 -767
  166. meerk40t/grbl/gui/grblconfiguration.py +373 -298
  167. meerk40t/grbl/gui/grblcontroller.py +485 -271
  168. meerk40t/grbl/gui/grblhardwareconfig.py +269 -153
  169. meerk40t/grbl/gui/grbloperationconfig.py +105 -0
  170. meerk40t/grbl/gui/gui.py +147 -116
  171. meerk40t/grbl/interpreter.py +44 -44
  172. meerk40t/grbl/loader.py +22 -22
  173. meerk40t/grbl/mock_connection.py +56 -56
  174. meerk40t/grbl/plugin.py +294 -264
  175. meerk40t/grbl/serial_connection.py +93 -88
  176. meerk40t/grbl/tcp_connection.py +81 -79
  177. meerk40t/grbl/ws_connection.py +112 -0
  178. meerk40t/gui/__init__.py +1 -1
  179. meerk40t/gui/about.py +2042 -296
  180. meerk40t/gui/alignment.py +1644 -1608
  181. meerk40t/gui/autoexec.py +199 -0
  182. meerk40t/gui/basicops.py +791 -670
  183. meerk40t/gui/bufferview.py +77 -71
  184. meerk40t/gui/busy.py +170 -133
  185. meerk40t/gui/choicepropertypanel.py +1673 -1469
  186. meerk40t/gui/consolepanel.py +706 -542
  187. meerk40t/gui/devicepanel.py +687 -581
  188. meerk40t/gui/dialogoptions.py +110 -107
  189. meerk40t/gui/executejob.py +316 -306
  190. meerk40t/gui/fonts.py +90 -90
  191. meerk40t/gui/functionwrapper.py +252 -0
  192. meerk40t/gui/gui_mixins.py +729 -0
  193. meerk40t/gui/guicolors.py +205 -182
  194. meerk40t/gui/help_assets/help_assets.py +218 -201
  195. meerk40t/gui/helper.py +154 -0
  196. meerk40t/gui/hersheymanager.py +1430 -846
  197. meerk40t/gui/icons.py +3422 -2747
  198. meerk40t/gui/imagesplitter.py +555 -508
  199. meerk40t/gui/keymap.py +354 -344
  200. meerk40t/gui/laserpanel.py +892 -806
  201. meerk40t/gui/laserrender.py +1470 -1232
  202. meerk40t/gui/lasertoolpanel.py +805 -793
  203. meerk40t/gui/magnetoptions.py +436 -0
  204. meerk40t/gui/materialmanager.py +2917 -0
  205. meerk40t/gui/materialtest.py +1722 -1694
  206. meerk40t/gui/mkdebug.py +646 -359
  207. meerk40t/gui/mwindow.py +163 -140
  208. meerk40t/gui/navigationpanels.py +2605 -2467
  209. meerk40t/gui/notes.py +143 -142
  210. meerk40t/gui/opassignment.py +414 -410
  211. meerk40t/gui/operation_info.py +310 -299
  212. meerk40t/gui/plugin.py +494 -328
  213. meerk40t/gui/position.py +714 -669
  214. meerk40t/gui/preferences.py +901 -650
  215. meerk40t/gui/propertypanels/attributes.py +1461 -1131
  216. meerk40t/gui/propertypanels/blobproperty.py +117 -114
  217. meerk40t/gui/propertypanels/consoleproperty.py +83 -80
  218. meerk40t/gui/propertypanels/gotoproperty.py +77 -0
  219. meerk40t/gui/propertypanels/groupproperties.py +223 -217
  220. meerk40t/gui/propertypanels/hatchproperty.py +489 -469
  221. meerk40t/gui/propertypanels/imageproperty.py +2244 -1384
  222. meerk40t/gui/propertypanels/inputproperty.py +59 -58
  223. meerk40t/gui/propertypanels/opbranchproperties.py +82 -80
  224. meerk40t/gui/propertypanels/operationpropertymain.py +1890 -1638
  225. meerk40t/gui/propertypanels/outputproperty.py +59 -58
  226. meerk40t/gui/propertypanels/pathproperty.py +389 -380
  227. meerk40t/gui/propertypanels/placementproperty.py +1214 -383
  228. meerk40t/gui/propertypanels/pointproperty.py +140 -136
  229. meerk40t/gui/propertypanels/propertywindow.py +313 -181
  230. meerk40t/gui/propertypanels/rasterwizardpanels.py +996 -912
  231. meerk40t/gui/propertypanels/regbranchproperties.py +76 -0
  232. meerk40t/gui/propertypanels/textproperty.py +770 -755
  233. meerk40t/gui/propertypanels/waitproperty.py +56 -55
  234. meerk40t/gui/propertypanels/warpproperty.py +121 -0
  235. meerk40t/gui/propertypanels/wobbleproperty.py +255 -204
  236. meerk40t/gui/ribbon.py +2468 -2210
  237. meerk40t/gui/scene/scene.py +1100 -1051
  238. meerk40t/gui/scene/sceneconst.py +22 -22
  239. meerk40t/gui/scene/scenepanel.py +439 -349
  240. meerk40t/gui/scene/scenespacewidget.py +365 -365
  241. meerk40t/gui/scene/widget.py +518 -505
  242. meerk40t/gui/scenewidgets/affinemover.py +215 -215
  243. meerk40t/gui/scenewidgets/attractionwidget.py +315 -309
  244. meerk40t/gui/scenewidgets/bedwidget.py +120 -97
  245. meerk40t/gui/scenewidgets/elementswidget.py +137 -107
  246. meerk40t/gui/scenewidgets/gridwidget.py +785 -745
  247. meerk40t/gui/scenewidgets/guidewidget.py +765 -765
  248. meerk40t/gui/scenewidgets/laserpathwidget.py +66 -66
  249. meerk40t/gui/scenewidgets/machineoriginwidget.py +86 -86
  250. meerk40t/gui/scenewidgets/nodeselector.py +28 -28
  251. meerk40t/gui/scenewidgets/rectselectwidget.py +589 -346
  252. meerk40t/gui/scenewidgets/relocatewidget.py +33 -33
  253. meerk40t/gui/scenewidgets/reticlewidget.py +83 -83
  254. meerk40t/gui/scenewidgets/selectionwidget.py +2952 -2756
  255. meerk40t/gui/simpleui.py +357 -333
  256. meerk40t/gui/simulation.py +2431 -2094
  257. meerk40t/gui/snapoptions.py +208 -203
  258. meerk40t/gui/spoolerpanel.py +1227 -1180
  259. meerk40t/gui/statusbarwidgets/defaultoperations.py +480 -353
  260. meerk40t/gui/statusbarwidgets/infowidget.py +520 -483
  261. meerk40t/gui/statusbarwidgets/opassignwidget.py +356 -355
  262. meerk40t/gui/statusbarwidgets/selectionwidget.py +172 -171
  263. meerk40t/gui/statusbarwidgets/shapepropwidget.py +754 -236
  264. meerk40t/gui/statusbarwidgets/statusbar.py +272 -260
  265. meerk40t/gui/statusbarwidgets/statusbarwidget.py +268 -270
  266. meerk40t/gui/statusbarwidgets/strokewidget.py +267 -251
  267. meerk40t/gui/themes.py +200 -78
  268. meerk40t/gui/tips.py +591 -0
  269. meerk40t/gui/toolwidgets/circlebrush.py +35 -35
  270. meerk40t/gui/toolwidgets/toolcircle.py +248 -242
  271. meerk40t/gui/toolwidgets/toolcontainer.py +82 -77
  272. meerk40t/gui/toolwidgets/tooldraw.py +97 -90
  273. meerk40t/gui/toolwidgets/toolellipse.py +219 -212
  274. meerk40t/gui/toolwidgets/toolimagecut.py +25 -132
  275. meerk40t/gui/toolwidgets/toolline.py +39 -144
  276. meerk40t/gui/toolwidgets/toollinetext.py +79 -236
  277. meerk40t/gui/toolwidgets/toollinetext_inline.py +296 -0
  278. meerk40t/gui/toolwidgets/toolmeasure.py +160 -216
  279. meerk40t/gui/toolwidgets/toolnodeedit.py +2088 -2074
  280. meerk40t/gui/toolwidgets/toolnodemove.py +92 -94
  281. meerk40t/gui/toolwidgets/toolparameter.py +754 -668
  282. meerk40t/gui/toolwidgets/toolplacement.py +108 -108
  283. meerk40t/gui/toolwidgets/toolpoint.py +68 -59
  284. meerk40t/gui/toolwidgets/toolpointlistbuilder.py +294 -0
  285. meerk40t/gui/toolwidgets/toolpointmove.py +183 -0
  286. meerk40t/gui/toolwidgets/toolpolygon.py +288 -403
  287. meerk40t/gui/toolwidgets/toolpolyline.py +38 -196
  288. meerk40t/gui/toolwidgets/toolrect.py +211 -207
  289. meerk40t/gui/toolwidgets/toolrelocate.py +72 -72
  290. meerk40t/gui/toolwidgets/toolribbon.py +598 -113
  291. meerk40t/gui/toolwidgets/tooltabedit.py +546 -0
  292. meerk40t/gui/toolwidgets/tooltext.py +98 -89
  293. meerk40t/gui/toolwidgets/toolvector.py +213 -204
  294. meerk40t/gui/toolwidgets/toolwidget.py +39 -39
  295. meerk40t/gui/usbconnect.py +98 -91
  296. meerk40t/gui/utilitywidgets/buttonwidget.py +18 -18
  297. meerk40t/gui/utilitywidgets/checkboxwidget.py +90 -90
  298. meerk40t/gui/utilitywidgets/controlwidget.py +14 -14
  299. meerk40t/gui/utilitywidgets/cyclocycloidwidget.py +343 -340
  300. meerk40t/gui/utilitywidgets/debugwidgets.py +148 -0
  301. meerk40t/gui/utilitywidgets/handlewidget.py +27 -27
  302. meerk40t/gui/utilitywidgets/harmonograph.py +450 -447
  303. meerk40t/gui/utilitywidgets/openclosewidget.py +40 -40
  304. meerk40t/gui/utilitywidgets/rotationwidget.py +54 -54
  305. meerk40t/gui/utilitywidgets/scalewidget.py +75 -75
  306. meerk40t/gui/utilitywidgets/seekbarwidget.py +183 -183
  307. meerk40t/gui/utilitywidgets/togglewidget.py +142 -142
  308. meerk40t/gui/utilitywidgets/toolbarwidget.py +8 -8
  309. meerk40t/gui/wordlisteditor.py +985 -931
  310. meerk40t/gui/wxmeerk40t.py +1444 -1169
  311. meerk40t/gui/wxmmain.py +5578 -4112
  312. meerk40t/gui/wxmribbon.py +1591 -1076
  313. meerk40t/gui/wxmscene.py +1635 -1453
  314. meerk40t/gui/wxmtree.py +2410 -2089
  315. meerk40t/gui/wxutils.py +1769 -1099
  316. meerk40t/gui/zmatrix.py +102 -102
  317. meerk40t/image/__init__.py +1 -1
  318. meerk40t/image/dither.py +429 -0
  319. meerk40t/image/imagetools.py +2778 -2269
  320. meerk40t/internal_plugins.py +150 -130
  321. meerk40t/kernel/__init__.py +63 -12
  322. meerk40t/kernel/channel.py +259 -212
  323. meerk40t/kernel/context.py +538 -538
  324. meerk40t/kernel/exceptions.py +41 -41
  325. meerk40t/kernel/functions.py +463 -414
  326. meerk40t/kernel/jobs.py +100 -100
  327. meerk40t/kernel/kernel.py +3809 -3571
  328. meerk40t/kernel/lifecycles.py +71 -71
  329. meerk40t/kernel/module.py +49 -49
  330. meerk40t/kernel/service.py +147 -147
  331. meerk40t/kernel/settings.py +383 -343
  332. meerk40t/lihuiyu/controller.py +883 -876
  333. meerk40t/lihuiyu/device.py +1181 -1069
  334. meerk40t/lihuiyu/driver.py +1466 -1372
  335. meerk40t/lihuiyu/gui/gui.py +127 -106
  336. meerk40t/lihuiyu/gui/lhyaccelgui.py +377 -363
  337. meerk40t/lihuiyu/gui/lhycontrollergui.py +741 -651
  338. meerk40t/lihuiyu/gui/lhydrivergui.py +470 -446
  339. meerk40t/lihuiyu/gui/lhyoperationproperties.py +238 -237
  340. meerk40t/lihuiyu/gui/tcpcontroller.py +226 -190
  341. meerk40t/lihuiyu/interpreter.py +53 -53
  342. meerk40t/lihuiyu/laserspeed.py +450 -450
  343. meerk40t/lihuiyu/loader.py +90 -90
  344. meerk40t/lihuiyu/parser.py +404 -404
  345. meerk40t/lihuiyu/plugin.py +101 -102
  346. meerk40t/lihuiyu/tcp_connection.py +111 -109
  347. meerk40t/main.py +231 -165
  348. meerk40t/moshi/builder.py +788 -781
  349. meerk40t/moshi/controller.py +505 -499
  350. meerk40t/moshi/device.py +495 -442
  351. meerk40t/moshi/driver.py +862 -696
  352. meerk40t/moshi/gui/gui.py +78 -76
  353. meerk40t/moshi/gui/moshicontrollergui.py +538 -522
  354. meerk40t/moshi/gui/moshidrivergui.py +87 -75
  355. meerk40t/moshi/plugin.py +43 -43
  356. meerk40t/network/console_server.py +102 -57
  357. meerk40t/network/kernelserver.py +10 -9
  358. meerk40t/network/tcp_server.py +142 -140
  359. meerk40t/network/udp_server.py +103 -77
  360. meerk40t/network/web_server.py +390 -0
  361. meerk40t/newly/controller.py +1158 -1144
  362. meerk40t/newly/device.py +874 -732
  363. meerk40t/newly/driver.py +540 -412
  364. meerk40t/newly/gui/gui.py +219 -188
  365. meerk40t/newly/gui/newlyconfig.py +116 -101
  366. meerk40t/newly/gui/newlycontroller.py +193 -186
  367. meerk40t/newly/gui/operationproperties.py +51 -51
  368. meerk40t/newly/mock_connection.py +82 -82
  369. meerk40t/newly/newly_params.py +56 -56
  370. meerk40t/newly/plugin.py +1214 -1246
  371. meerk40t/newly/usb_connection.py +322 -322
  372. meerk40t/rotary/gui/gui.py +52 -46
  373. meerk40t/rotary/gui/rotarysettings.py +240 -232
  374. meerk40t/rotary/rotary.py +202 -98
  375. meerk40t/ruida/control.py +291 -91
  376. meerk40t/ruida/controller.py +138 -1088
  377. meerk40t/ruida/device.py +672 -231
  378. meerk40t/ruida/driver.py +534 -472
  379. meerk40t/ruida/emulator.py +1494 -1491
  380. meerk40t/ruida/exceptions.py +4 -4
  381. meerk40t/ruida/gui/gui.py +71 -76
  382. meerk40t/ruida/gui/ruidaconfig.py +239 -72
  383. meerk40t/ruida/gui/ruidacontroller.py +187 -184
  384. meerk40t/ruida/gui/ruidaoperationproperties.py +48 -47
  385. meerk40t/ruida/loader.py +54 -52
  386. meerk40t/ruida/mock_connection.py +57 -109
  387. meerk40t/ruida/plugin.py +124 -87
  388. meerk40t/ruida/rdjob.py +2084 -945
  389. meerk40t/ruida/serial_connection.py +116 -0
  390. meerk40t/ruida/tcp_connection.py +146 -0
  391. meerk40t/ruida/udp_connection.py +73 -0
  392. meerk40t/svgelements.py +9671 -9669
  393. meerk40t/tools/driver_to_path.py +584 -579
  394. meerk40t/tools/geomstr.py +5583 -4680
  395. meerk40t/tools/jhfparser.py +357 -292
  396. meerk40t/tools/kerftest.py +904 -890
  397. meerk40t/tools/livinghinges.py +1168 -1033
  398. meerk40t/tools/pathtools.py +987 -949
  399. meerk40t/tools/pmatrix.py +234 -0
  400. meerk40t/tools/pointfinder.py +942 -942
  401. meerk40t/tools/polybool.py +940 -940
  402. meerk40t/tools/rasterplotter.py +1660 -547
  403. meerk40t/tools/shxparser.py +989 -901
  404. meerk40t/tools/ttfparser.py +726 -446
  405. meerk40t/tools/zinglplotter.py +595 -593
  406. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/LICENSE +21 -21
  407. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/METADATA +150 -139
  408. meerk40t-0.9.7010.dist-info/RECORD +445 -0
  409. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/WHEEL +1 -1
  410. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/top_level.txt +0 -1
  411. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/zip-safe +1 -1
  412. meerk40t/balormk/elementlightjob.py +0 -159
  413. meerk40t-0.9.3001.dist-info/RECORD +0 -437
  414. test/bootstrap.py +0 -63
  415. test/test_cli.py +0 -12
  416. test/test_core_cutcode.py +0 -418
  417. test/test_core_elements.py +0 -144
  418. test/test_core_plotplanner.py +0 -397
  419. test/test_core_viewports.py +0 -312
  420. test/test_drivers_grbl.py +0 -108
  421. test/test_drivers_lihuiyu.py +0 -443
  422. test/test_drivers_newly.py +0 -113
  423. test/test_element_degenerate_points.py +0 -43
  424. test/test_elements_classify.py +0 -97
  425. test/test_elements_penbox.py +0 -22
  426. test/test_file_svg.py +0 -176
  427. test/test_fill.py +0 -155
  428. test/test_geomstr.py +0 -1523
  429. test/test_geomstr_nodes.py +0 -18
  430. test/test_imagetools_actualize.py +0 -306
  431. test/test_imagetools_wizard.py +0 -258
  432. test/test_kernel.py +0 -200
  433. test/test_laser_speeds.py +0 -3303
  434. test/test_length.py +0 -57
  435. test/test_lifecycle.py +0 -66
  436. test/test_operations.py +0 -251
  437. test/test_operations_hatch.py +0 -57
  438. test/test_ruida.py +0 -19
  439. test/test_spooler.py +0 -22
  440. test/test_tools_rasterplotter.py +0 -29
  441. test/test_wobble.py +0 -133
  442. test/test_zingl.py +0 -124
  443. {test → meerk40t/cylinder}/__init__.py +0 -0
  444. /meerk40t/{core/element_commands.py → cylinder/gui/__init__.py} +0 -0
  445. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/entry_points.txt +0 -0
@@ -1,1512 +1,1566 @@
1
- """
2
- Galvo Controller
3
-
4
- The balor controller takes low level lmc galvo commands and converts them into lists and shorts commands to send
5
- to the hardware controller.
6
- """
7
-
8
- import struct
9
- import threading
10
- import time
11
- from copy import copy
12
-
13
- from meerk40t.balormk.mock_connection import MockConnection
14
- from meerk40t.balormk.usb_connection import USBConnection
15
-
16
- DRIVER_STATE_RAPID = 0
17
- DRIVER_STATE_LIGHT = 1
18
- DRIVER_STATE_PROGRAM = 2
19
- DRIVER_STATE_RAW = 3
20
-
21
- nop = [0x02, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
22
- empty = bytearray(nop * 0x100)
23
-
24
- listJumpTo = 0x8001
25
- listEndOfList = 0x8002
26
- listLaserOnPoint = 0x8003
27
- listDelayTime = 0x8004
28
- listMarkTo = 0x8005
29
- listJumpSpeed = 0x8006
30
- listLaserOnDelay = 0x8007
31
- listLaserOffDelay = 0x8008
32
- listMarkFreq = 0x800A
33
- listMarkPowerRatio = 0x800B
34
- listMarkSpeed = 0x800C
35
- listJumpDelay = 0x800D
36
- listPolygonDelay = 0x800F
37
- listWritePort = 0x8011
38
- listMarkCurrent = 0x8012
39
- listMarkFreq2 = 0x8013
40
- listFlyEnable = 0x801A
41
- listQSwitchPeriod = 0x801B
42
- listDirectLaserSwitch = 0x801C
43
- listFlyDelay = 0x801D
44
- listSetCo2FPK = 0x801E
45
- listFlyWaitInput = 0x801F
46
- listFiberOpenMO = 0x8021
47
- listWaitForInput = 0x8022
48
- listChangeMarkCount = 0x8023
49
- listSetWeldPowerWave = 0x8024
50
- listEnableWeldPowerWave = 0x8025
51
- listFiberYLPMPulseWidth = 0x8026
52
- listFlyEncoderCount = 0x8028
53
- listSetDaZWord = 0x8029
54
- listJptSetParam = 0x8050
55
- listReadyMark = 0x8051
56
-
57
- DisableLaser = 0x0002
58
- EnableLaser = 0x0004
59
- ExecuteList = 0x0005
60
- SetPwmPulseWidth = 0x0006
61
- GetVersion = 0x0007
62
- GetSerialNo = 0x0009
63
- GetListStatus = 0x000A
64
- GetPositionXY = 0x000C
65
- GotoXY = 0x000D
66
- LaserSignalOff = 0x000E
67
- LaserSignalOn = 0x000F
68
- WriteCorLine = 0x0010
69
- ResetList = 0x0012
70
- RestartList = 0x0013
71
- WriteCorTable = 0x0015
72
- SetControlMode = 0x0016
73
- SetDelayMode = 0x0017
74
- SetMaxPolyDelay = 0x0018
75
- SetEndOfList = 0x0019
76
- SetFirstPulseKiller = 0x001A
77
- SetLaserMode = 0x001B
78
- SetTiming = 0x001C
79
- SetStandby = 0x001D
80
- SetPwmHalfPeriod = 0x001E
81
- StopExecute = 0x001F
82
- StopList = 0x0020
83
- WritePort = 0x0021
84
- WriteAnalogPort1 = 0x0022
85
- WriteAnalogPort2 = 0x0023
86
- WriteAnalogPortX = 0x0024
87
- ReadPort = 0x0025
88
- SetAxisMotionParam = 0x0026
89
- SetAxisOriginParam = 0x0027
90
- AxisGoOrigin = 0x0028
91
- MoveAxisTo = 0x0029
92
- GetAxisPos = 0x002A
93
- GetFlyWaitCount = 0x002B
94
- GetMarkCount = 0x002D
95
- SetFpkParam2 = 0x002E
96
- Fiber_SetMo = 0x0033 # open and close set by value
97
- Fiber_GetStMO_AP = 0x0034
98
- EnableZ = 0x003A
99
- DisableZ = 0x0039
100
- SetZData = 0x003B
101
- SetSPISimmerCurrent = 0x003C
102
- SetFpkParam = 0x0062
103
- Reset = 0x0040
104
- GetFlySpeed = 0x0038
105
- FiberPulseWidth = 0x002F
106
- FiberGetConfigExtend = 0x0030
107
- InputPort = 0x0031 # ClearLockInputPort calls 0x04, then if EnableLockInputPort 0x02 else 0x01, GetLockInputPort
108
- GetMarkTime = 0x0041
109
- GetUserData = 0x0036
110
- SetFlyRes = 0x0032
111
-
112
- list_command_lookup = {
113
- 0x8001: "listJumpTo",
114
- 0x8002: "listEndOfList",
115
- 0x8003: "listLaserOnPoint",
116
- 0x8004: "listDelayTime",
117
- 0x8005: "listMarkTo",
118
- 0x8006: "listJumpSpeed",
119
- 0x8007: "listLaserOnDelay",
120
- 0x8008: "listLaserOffDelay",
121
- 0x800A: "listMarkFreq",
122
- 0x800B: "listMarkPowerRatio",
123
- 0x800C: "listMarkSpeed",
124
- 0x800D: "listJumpDelay",
125
- 0x800F: "listPolygonDelay",
126
- 0x8011: "listWritePort",
127
- 0x8012: "listMarkCurrent",
128
- 0x8013: "listMarkFreq2",
129
- 0x801A: "listFlyEnable",
130
- 0x801B: "listQSwitchPeriod",
131
- 0x801C: "listDirectLaserSwitch",
132
- 0x801D: "listFlyDelay",
133
- 0x801E: "listSetCo2FPK",
134
- 0x801F: "listFlyWaitInput",
135
- 0x8021: "listFiberOpenMO",
136
- 0x8022: "listWaitForInput",
137
- 0x8023: "listChangeMarkCount",
138
- 0x8024: "listSetWeldPowerWave",
139
- 0x8025: "listEnableWeldPowerWave",
140
- 0x8026: "listFiberYLPMPulseWidth",
141
- 0x8028: "listFlyEncoderCount",
142
- 0x8029: "listSetDaZWord",
143
- 0x8050: "listJptSetParam",
144
- 0x8051: "listReadyMark",
145
- }
146
-
147
- single_command_lookup = {
148
- 0x0002: "DisableLaser",
149
- 0x0004: "EnableLaser",
150
- 0x0005: "ExecuteList",
151
- 0x0006: "SetPwmPulseWidth",
152
- 0x0007: "GetVersion",
153
- 0x0009: "GetSerialNo",
154
- 0x000A: "GetListStatus",
155
- 0x000C: "GetPositionXY",
156
- 0x000D: "GotoXY",
157
- 0x000E: "LaserSignalOff",
158
- 0x000F: "LaserSignalOn",
159
- 0x0010: "WriteCorLine",
160
- 0x0012: "ResetList",
161
- 0x0013: "RestartList",
162
- 0x0015: "WriteCorTable",
163
- 0x0016: "SetControlMode",
164
- 0x0017: "SetDelayMode",
165
- 0x0018: "SetMaxPolyDelay",
166
- 0x0019: "SetEndOfList",
167
- 0x001A: "SetFirstPulseKiller",
168
- 0x001B: "SetLaserMode",
169
- 0x001C: "SetTiming",
170
- 0x001D: "SetStandby",
171
- 0x001E: "SetPwmHalfPeriod",
172
- 0x001F: "StopExecute",
173
- 0x0020: "StopList",
174
- 0x0021: "WritePort",
175
- 0x0022: "WriteAnalogPort1",
176
- 0x0023: "WriteAnalogPort2",
177
- 0x0024: "WriteAnalogPortX",
178
- 0x0025: "ReadPort",
179
- 0x0026: "SetAxisMotionParam",
180
- 0x0027: "SetAxisOriginParam",
181
- 0x0028: "AxisGoOrigin",
182
- 0x0029: "MoveAxisTo",
183
- 0x002A: "GetAxisPos",
184
- 0x002B: "GetFlyWaitCount",
185
- 0x002D: "GetMarkCount",
186
- 0x002E: "SetFpkParam2",
187
- 0x0033: "Fiber_SetMo",
188
- 0x0034: "Fiber_GetStMO_AP",
189
- 0x003A: "EnableZ",
190
- 0x0039: "DisableZ",
191
- 0x003B: "SetZData",
192
- 0x003C: "SetSPISimmerCurrent",
193
- 0x0062: "SetFpkParam",
194
- 0x0040: "Reset",
195
- 0x0038: "GetFlySpeed",
196
- 0x002F: "FiberPulseWidth",
197
- 0x0030: "FiberGetConfigExtend",
198
- 0x0031: "InputPort",
199
- 0x0041: "GetMarkTime",
200
- 0x0036: "GetUserData",
201
- 0x0032: "SetFlyRes",
202
- }
203
-
204
- BUSY = 0x04
205
- READY = 0x20
206
- AXIS = 0x40
207
-
208
-
209
- def _bytes_to_words(r):
210
- b0 = r[1] << 8 | r[0]
211
- b1 = r[3] << 8 | r[2]
212
- b2 = r[5] << 8 | r[4]
213
- b3 = r[7] << 8 | r[6]
214
- return b0, b1, b2, b3
215
-
216
-
217
- class GalvoController:
218
- """
219
- Galvo controller is tasked with sending queued data to the controller board and ensuring that the connection to the
220
- controller board is established to perform these actions.
221
-
222
- This should serve as a next generation command sequencer written from scratch for galvo lasers. The goal is to
223
- provide all the given commands in a coherent queue structure which provides correct sequences between list and
224
- single commands.
225
- """
226
-
227
- def __init__(
228
- self,
229
- service,
230
- x=0x8000,
231
- y=0x8000,
232
- mark_speed=None,
233
- goto_speed=None,
234
- light_speed=None,
235
- dark_speed=None,
236
- force_mock=False,
237
- ):
238
- self.service = service
239
- self.force_mock = force_mock
240
- self.is_shutdown = False # Shutdown finished.
241
-
242
- name = self.service.label
243
- self.usb_log = service.channel(f"{name}/usb", buffer_size=500)
244
- self.usb_log.watch(lambda e: service.signal("pipe;usb_status", e))
245
-
246
- self.connection = None
247
- self._is_opening = False
248
- self._abort_open = False
249
- self._disable_connect = False
250
-
251
- self._light_bit = service.setting(int, "light_pin", 8)
252
- self._foot_bit = service.setting(int, "footpedal_pin", 15)
253
-
254
- self._last_x = x
255
- self._last_y = y
256
- self._mark_speed = mark_speed
257
- self._goto_speed = goto_speed
258
- self._light_speed = light_speed
259
- self._dark_speed = dark_speed
260
-
261
- self._ready = None
262
- self._speed = None
263
- self._travel_speed = None
264
- self._frequency = None
265
- self._power = None
266
- self._pulse_width = None
267
- self._fpk = None
268
-
269
- self._delay_jump = None
270
- self._delay_on = None
271
- self._delay_off = None
272
- self._delay_poly = None
273
- self._delay_end = None
274
-
275
- self._port_bits = 0
276
- self._machine_index = 0
277
-
278
- self.mode = DRIVER_STATE_RAPID
279
- self._list_lock = threading.RLock()
280
- self._active_list = None
281
- self._active_index = 0
282
- self._list_executing = False
283
- self._number_of_list_packets = 0
284
- self.paused = False
285
-
286
- @property
287
- def source(self):
288
- return self.service.source
289
-
290
- @property
291
- def state(self):
292
- if self.mode == DRIVER_STATE_RAPID:
293
- return "idle", "idle"
294
- if self.paused:
295
- return "hold", "paused"
296
- if self.mode == DRIVER_STATE_RAW:
297
- return "busy", "raw"
298
- if self.mode == DRIVER_STATE_LIGHT:
299
- return "busy", "light"
300
- if self.mode == DRIVER_STATE_PROGRAM:
301
- return "busy", "program"
302
-
303
- def set_disable_connect(self, status):
304
- self._disable_connect = status
305
-
306
- def added(self):
307
- pass
308
-
309
- def service_detach(self):
310
- pass
311
-
312
- def shutdown(self, *args, **kwargs):
313
- self.is_shutdown = True
314
-
315
- @property
316
- def connected(self):
317
- if self.connection is None:
318
- return False
319
- return self.connection.is_open(self._machine_index)
320
-
321
- @property
322
- def is_connecting(self):
323
- if self.connection is None:
324
- return False
325
- return self._is_opening
326
-
327
- def abort_connect(self):
328
- self._abort_open = True
329
- self.usb_log("Connect Attempts Aborted")
330
-
331
- def disconnect(self):
332
- try:
333
- self.connection.close(self._machine_index)
334
- except (ConnectionError, ConnectionRefusedError, AttributeError):
335
- pass
336
- self.connection = None
337
- # Reset error to allow another attempt
338
- self.set_disable_connect(False)
339
-
340
- def connect_if_needed(self):
341
- if self._disable_connect:
342
- # After many failures automatic connects are disabled. We require a manual connection.
343
- self.abort_connect()
344
- self.connection = None
345
- raise ConnectionRefusedError(
346
- "LMC was unreachable. Explicit connect required."
347
- )
348
- if self.connection is None:
349
- if self.service.setting(bool, "mock", False) or self.force_mock:
350
- self.connection = MockConnection(self.usb_log)
351
- name = self.service.label
352
- self.connection.send = self.service.channel(f"{name}/send")
353
- self.connection.recv = self.service.channel(f"{name}/recv")
354
- else:
355
- self.connection = USBConnection(self.usb_log)
356
- self._is_opening = True
357
- self._abort_open = False
358
- count = 0
359
- while not self.connection.is_open(self._machine_index):
360
- try:
361
- if self.connection.open(self._machine_index) < 0:
362
- raise ConnectionError
363
- self.init_laser()
364
- except (ConnectionError, ConnectionRefusedError):
365
- if count == 0:
366
- self.service("clone_init\n")
367
- time.sleep(0.3)
368
- count += 1
369
- # self.usb_log(f"Error-Routine pass #{count}")
370
- if self.is_shutdown or self._abort_open:
371
- self._is_opening = False
372
- self._abort_open = False
373
- return
374
- if self.connection.is_open(self._machine_index):
375
- self.connection.close(self._machine_index)
376
- if count >= 10:
377
- # We have failed too many times.
378
- self._is_opening = False
379
- self.set_disable_connect(True)
380
- self.usb_log("Could not connect to the LMC controller.")
381
- self.usb_log("Automatic connections disabled.")
382
- raise ConnectionRefusedError(
383
- "Could not connect to the LMC controller."
384
- )
385
- time.sleep(0.3)
386
- continue
387
- self._is_opening = False
388
- self._abort_open = False
389
-
390
- def send(self, data, read=True):
391
- if self.is_shutdown:
392
- return -1, -1, -1, -1
393
- self.connect_if_needed()
394
- try:
395
- self.connection.write(self._machine_index, data)
396
- except ConnectionError:
397
- return -1, -1, -1, -1
398
- if read:
399
- try:
400
- r = self.connection.read(self._machine_index)
401
- return struct.unpack("<4H", r)
402
- except ConnectionError:
403
- return -1, -1, -1, -1
404
-
405
- def status(self):
406
- b0, b1, b2, b3 = self.get_version()
407
- return b3
408
-
409
- #######################
410
- # MODE SHIFTS
411
- #######################
412
-
413
- def raw_mode(self):
414
- self.mode = DRIVER_STATE_RAW
415
-
416
- def rapid_mode(self):
417
- if self.mode == DRIVER_STATE_RAPID:
418
- return
419
- self.list_end_of_list() # Ensure at least one list_end_of_list
420
- self._list_end()
421
- if not self._list_executing and self._number_of_list_packets:
422
- # If we never ran the list, and we sent some lists.
423
- self.execute_list()
424
- self._list_executing = False
425
- self._number_of_list_packets = 0
426
- self.wait_idle()
427
- if self.source == "fiber":
428
- self.set_fiber_mo(0)
429
- self.port_off(bit=0)
430
- self.write_port()
431
- marktime = self.get_mark_time()
432
- self.service.signal("galvo;marktime", marktime)
433
- self.usb_log(f"Time taken for list execution: {marktime}")
434
- self.mode = DRIVER_STATE_RAPID
435
-
436
- def raster_mode(self):
437
- self.program_mode()
438
-
439
- def program_mode(self):
440
- if self.mode == DRIVER_STATE_PROGRAM:
441
- return
442
- if self.mode == DRIVER_STATE_LIGHT:
443
- self.mode = DRIVER_STATE_PROGRAM
444
- self.light_off()
445
- self.port_on(bit=0)
446
- self.write_port()
447
- if self.source == "fiber":
448
- self.set_fiber_mo(1)
449
- else:
450
- self.mode = DRIVER_STATE_PROGRAM
451
- self.reset_list()
452
- self.port_on(bit=0)
453
- self.write_port()
454
- if self.source == "fiber":
455
- self.set_fiber_mo(1)
456
- self._ready = None
457
- self._speed = None
458
- self._travel_speed = None
459
- self._frequency = None
460
- self._power = None
461
- self._pulse_width = None
462
-
463
- self._delay_jump = None
464
- self._delay_on = None
465
- self._delay_off = None
466
- self._delay_poly = None
467
- self._delay_end = None
468
- self.list_ready()
469
- if self.service.delay_openmo != 0 and self.source == "fiber":
470
- self.list_delay_time(int(self.service.delay_openmo * 100))
471
- self.list_write_port()
472
- self.list_jump_speed(self.service.default_rapid_speed)
473
-
474
- def light_mode(self):
475
- if self.mode == DRIVER_STATE_LIGHT:
476
- return
477
- if self.mode == DRIVER_STATE_PROGRAM:
478
- if self.source == "fiber":
479
- self.set_fiber_mo(0)
480
- self.port_off(bit=0)
481
- self.port_on(self._light_bit)
482
- self.write_port()
483
- else:
484
- self._ready = None
485
- self._speed = None
486
- self._travel_speed = None
487
- self._frequency = None
488
- self._power = None
489
- self._pulse_width = None
490
-
491
- self._delay_jump = None
492
- self._delay_on = None
493
- self._delay_off = None
494
- self._delay_poly = None
495
- self._delay_end = None
496
-
497
- self.reset_list()
498
- self.list_ready()
499
- self.port_off(bit=0)
500
- self.port_on(self._light_bit)
501
- self.list_write_port()
502
- self.mode = DRIVER_STATE_LIGHT
503
-
504
- #######################
505
- # LIST APPENDING OPERATIONS
506
- #######################
507
-
508
- def _list_end(self):
509
- if not self._active_list or not self._active_index:
510
- # Ensure there is a list to end.
511
- return
512
- with self._list_lock:
513
- if not self._active_list or not self._active_index:
514
- # Double-gated syntax, make sure there's still that list needing ending.
515
- return
516
- self.wait_ready()
517
- while self.paused:
518
- time.sleep(0.3)
519
- self.send(self._active_list, False)
520
- if self.mode != DRIVER_STATE_RAW:
521
- self.set_end_of_list(0)
522
- self._number_of_list_packets += 1
523
- self._active_list = None
524
- self._active_index = 0
525
- if self._number_of_list_packets > 2 and not self._list_executing:
526
- if self.mode != DRIVER_STATE_RAW:
527
- self.execute_list()
528
- self._list_executing = True
529
-
530
- def _list_new(self):
531
- with self._list_lock:
532
- self._active_list = copy(empty)
533
- self._active_index = 0
534
-
535
- def _list_write(self, command, v1=0, v2=0, v3=0, v4=0, v5=0):
536
- with self._list_lock:
537
- if self._active_index >= 0xC00:
538
- self._list_end()
539
- if self._active_list is None:
540
- self._list_new()
541
- index = self._active_index
542
- self._active_list[index : index + 12] = struct.pack(
543
- "<6H", int(command), int(v1), int(v2), int(v3), int(v4), int(v5)
544
- )
545
- self._active_index += 12
546
-
547
- def _command(self, command, v1=0, v2=0, v3=0, v4=0, v5=0, read=True):
548
- cmd = struct.pack(
549
- "<6H", int(command), int(v1), int(v2), int(v3), int(v4), int(v5)
550
- )
551
- return self.send(cmd, read=read)
552
-
553
- def raw_write(self, command, v1=0, v2=0, v3=0, v4=0, v5=0):
554
- """
555
- Write this raw command to value. Sends the correct way based on command value.
556
-
557
- @return:
558
- """
559
- if command >= 0x8000:
560
- self._list_write(command, v1, v2, v3, v4, v5)
561
- else:
562
- self._command(command, v1, v2, v3, v4, v5)
563
-
564
- def raw_clear(self):
565
- self._list_new()
566
-
567
- #######################
568
- # SETS FOR PLOTLIKES
569
- #######################
570
-
571
- def set_settings(self, settings):
572
- """
573
- Sets the primary settings. Rapid, frequency, speed, and timings.
574
-
575
- @param settings: The current settings dictionary
576
- @return:
577
- """
578
- if self.service.pulse_width_enabled and self.source == "fiber":
579
- # Global Pulse Width is enabled.
580
- if str(settings.get("pulse_width_enabled", False)).lower() == "true":
581
- # Local Pulse Width value is enabled.
582
- # OpFiberYLPMPulseWidth
583
-
584
- self.list_fiber_ylpm_pulse_width(
585
- int(settings.get("pulse_width", self.service.default_pulse_width))
586
- )
587
- else:
588
- # Only global is enabled, use global pulse width value.
589
- self.list_fiber_ylpm_pulse_width(self.service.default_pulse_width)
590
-
591
- if str(settings.get("rapid_enabled", False)).lower() == "true":
592
- self.list_jump_speed(
593
- float(settings.get("rapid_speed", self.service.default_rapid_speed))
594
- )
595
- else:
596
- self.list_jump_speed(self.service.default_rapid_speed)
597
-
598
- power = (
599
- float(settings.get("power", self.service.default_power)) / 10.0
600
- ) # Convert power, out of 1000
601
- frequency = float(settings.get("frequency", self.service.default_frequency))
602
- fpk = float(settings.get("fpk", self.service.default_fpk))
603
- if self.source == "fiber":
604
- self.power(power)
605
- self.frequency(frequency)
606
- elif self.source == "co2":
607
- self.frequency(frequency)
608
- self.fpk(fpk)
609
- self.power(power)
610
- self.list_mark_speed(float(settings.get("speed", self.service.default_speed)))
611
-
612
- if str(settings.get("timing_enabled", False)).lower() == "true":
613
- self.list_laser_on_delay(
614
- settings.get("delay_laser_on", self.service.delay_laser_on)
615
- )
616
- self.list_laser_off_delay(
617
- settings.get("delay_laser_off", self.service.delay_laser_off)
618
- )
619
- self.list_polygon_delay(
620
- settings.get("delay_laser_polygon", self.service.delay_polygon)
621
- )
622
- else:
623
- # Use globals
624
- self.list_laser_on_delay(self.service.delay_laser_on)
625
- self.list_laser_off_delay(self.service.delay_laser_off)
626
- self.list_polygon_delay(self.service.delay_polygon)
627
-
628
- #######################
629
- # PLOTLIKE SHORTCUTS
630
- #######################
631
-
632
- def mark(self, x, y):
633
- if x == self._last_x and y == self._last_y:
634
- return
635
- if x > 0xFFFF or x < 0 or y > 0xFFFF or y < 0:
636
- # Moves to out of range are not performed.
637
- return
638
- if self._mark_speed is not None:
639
- self.list_mark_speed(self._mark_speed)
640
- self.list_mark(x, y)
641
-
642
- def goto(self, x, y, long=None, short=None, distance_limit=None):
643
- if x == self._last_x and y == self._last_y:
644
- return
645
- if x > 0xFFFF or x < 0 or y > 0xFFFF or y < 0:
646
- # Moves to out of range are not performed.
647
- return
648
- if self._goto_speed is not None:
649
- self.list_jump_speed(self._goto_speed)
650
- self.list_jump(x, y, long=long, short=short, distance_limit=distance_limit)
651
-
652
- def light(self, x, y, long=None, short=None, distance_limit=None):
653
- if x == self._last_x and y == self._last_y:
654
- return
655
- if x > 0xFFFF or x < 0 or y > 0xFFFF or y < 0:
656
- # Moves to out of range are not performed.
657
- return
658
- if self.light_on():
659
- self.list_write_port()
660
- if self._light_speed is not None:
661
- self.list_jump_speed(self._light_speed)
662
- self.list_jump(x, y, long=long, short=short, distance_limit=distance_limit)
663
-
664
- def dark(self, x, y, long=None, short=None, distance_limit=None):
665
- if x == self._last_x and y == self._last_y:
666
- return
667
- if x > 0xFFFF or x < 0 or y > 0xFFFF or y < 0:
668
- # Moves to out of range are not performed.
669
- return
670
- if self.light_off():
671
- self.list_write_port()
672
- if self._dark_speed is not None:
673
- self.list_jump_speed(self._dark_speed)
674
- self.list_jump(x, y, long=long, short=short, distance_limit=distance_limit)
675
-
676
- def set_xy(self, x, y):
677
- distance = int(abs(complex(x, y) - complex(self._last_x, self._last_y)))
678
- if distance > 0xFFFF:
679
- distance = 0xFFFF
680
- self.goto_xy(x, y, distance=distance)
681
-
682
- def get_last_xy(self):
683
- return self._last_x, self._last_y
684
-
685
- #######################
686
- # Command Shortcuts
687
- #######################
688
-
689
- def is_busy(self):
690
- status = self.status()
691
- return bool(status & BUSY)
692
-
693
- def is_ready(self):
694
- status = self.status()
695
- return bool(status & READY)
696
-
697
- def is_axis(self):
698
- status = self.status()
699
- return bool(status & AXIS)
700
-
701
- def is_ready_and_not_busy(self):
702
- if self.mode == DRIVER_STATE_RAW:
703
- return True
704
- status = self.status()
705
- return bool(status & READY) and not bool(status & BUSY)
706
-
707
- def wait_finished(self):
708
- if self.mode == DRIVER_STATE_RAW:
709
- return
710
- while not self.is_ready_and_not_busy():
711
- time.sleep(0.01)
712
- if self.is_shutdown:
713
- return
714
-
715
- def wait_axis(self):
716
- if self.mode == DRIVER_STATE_RAW:
717
- return
718
- while self.is_axis():
719
- time.sleep(0.01)
720
- if self.is_shutdown:
721
- return
722
-
723
- def wait_ready(self):
724
- if self.mode == DRIVER_STATE_RAW:
725
- return
726
- while not self.is_ready():
727
- time.sleep(0.01)
728
- if self.is_shutdown:
729
- return
730
-
731
- def wait_idle(self):
732
- if self.mode == DRIVER_STATE_RAW:
733
- return
734
- while self.is_busy():
735
- time.sleep(0.01)
736
- if self.is_shutdown:
737
- return
738
-
739
- def abort(self, dummy_packet=True):
740
- if self.mode == DRIVER_STATE_RAW:
741
- return
742
- self.stop_execute()
743
- self.paused = False
744
- self.set_fiber_mo(0)
745
- self.reset_list()
746
- if dummy_packet:
747
- self._list_new()
748
- self.list_end_of_list() # Ensure packet is sent on end.
749
- self._list_end()
750
- if not self._list_executing:
751
- self.execute_list()
752
- self._list_executing = False
753
- self._number_of_list_packets = 0
754
- self.set_fiber_mo(0)
755
- self.port_off(bit=0)
756
- self.write_port()
757
- self.mode = DRIVER_STATE_RAPID
758
-
759
- def pause(self):
760
- if self.mode == DRIVER_STATE_RAW:
761
- return
762
- self.paused = True
763
- self.stop_list()
764
-
765
- def resume(self):
766
- if self.mode == DRIVER_STATE_RAW:
767
- return
768
- self.restart_list()
769
- self.paused = False
770
-
771
- def init_laser(self):
772
- if self.mode == DRIVER_STATE_RAW:
773
- return
774
- cor_file = self.service.corfile if self.service.corfile_enabled else None
775
- first_pulse_killer = self.service.first_pulse_killer
776
- pwm_pulse_width = self.service.pwm_pulse_width
777
- pwm_half_period = self.service.pwm_half_period
778
- standby_param_1 = self.service.standby_param_1
779
- standby_param_2 = self.service.standby_param_2
780
- timing_mode = self.service.timing_mode
781
- delay_mode = self.service.delay_mode
782
- laser_mode = self.service.laser_mode
783
- control_mode = self.service.control_mode
784
- fpk2_p1 = self.service.fpk2_p1
785
- fpk2_p2 = self.service.fpk2_p2
786
- fpk2_p3 = self.service.fpk2_p3
787
- fpk2_p4 = self.service.fpk2_p3
788
- fly_res_p1 = self.service.fly_res_p1
789
- fly_res_p2 = self.service.fly_res_p2
790
- fly_res_p3 = self.service.fly_res_p3
791
- fly_res_p4 = self.service.fly_res_p4
792
-
793
- self.usb_log("Initializing Laser")
794
- serial_number = self.get_serial_number()
795
- self.usb_log(f"Serial Number: {serial_number}")
796
- version = self.get_version()
797
- self.usb_log(f"Version: {version}")
798
-
799
- self.reset()
800
- self.usb_log("Reset")
801
- self.write_correction_file(cor_file)
802
- self.enable_laser()
803
- self.usb_log("Laser Enabled")
804
- self.set_control_mode(control_mode)
805
- self.usb_log("Control Mode")
806
- self.set_laser_mode(laser_mode)
807
- self.usb_log("Laser Mode")
808
- self.set_delay_mode(delay_mode)
809
- self.usb_log("Delay Mode")
810
- self.set_timing(timing_mode)
811
- self.usb_log("Timing Mode")
812
- self.set_standby(standby_param_1, standby_param_2)
813
- self.usb_log("Setting Standby")
814
- self.set_first_pulse_killer(first_pulse_killer)
815
- self.usb_log("Set First Pulse Killer")
816
- self.set_pwm_half_period(pwm_half_period)
817
- self.usb_log("Set PWM Half-Period")
818
- self.set_pwm_pulse_width(pwm_pulse_width)
819
- self.usb_log("Set PWM pulse width")
820
- self.set_fiber_mo(0) # Close
821
- self.usb_log("Set Fiber Mo (Closed)")
822
- self.set_pfk_param_2(fpk2_p1, fpk2_p2, fpk2_p3, fpk2_p4)
823
- self.usb_log("First Pulse Killer Parameters")
824
- self.set_fly_res(fly_res_p1, fly_res_p2, fly_res_p3, fly_res_p4)
825
- self.usb_log("On-The-Fly Res")
826
- self.enable_z()
827
- self.usb_log("Z-Enabled")
828
- self.write_analog_port_1(0x7FF)
829
- self.usb_log("Analog Port 1")
830
- self.enable_z()
831
- self.usb_log("Z-Enabled-part2")
832
- time.sleep(0.05)
833
- self.usb_log("Ready")
834
-
835
- def power(self, power):
836
- """
837
- Accepts power in percent, automatically converts to power_ratio
838
-
839
- @param power:
840
- @return:
841
- """
842
- if self._power == power:
843
- return
844
- self._power = power
845
- if self.source == "co2":
846
- power_ratio = int(round(200 * power / self._frequency))
847
- self.list_mark_power_ratio(power_ratio)
848
- if self.source == "fiber":
849
- self.list_mark_current(self._convert_power(power))
850
-
851
- def frequency(self, frequency):
852
- if self._frequency == frequency:
853
- return
854
- self._frequency = frequency
855
- if self.source == "fiber":
856
- self.list_qswitch_period(self._convert_frequency(frequency, base=20000.0))
857
- elif self.source == "co2":
858
- self.list_mark_frequency(self._convert_frequency(frequency, base=10000.0))
859
-
860
- def fpk(self, fpk):
861
- """
862
- Set First Pulse Killer
863
- @param fpk: first_pulse_killer value in percent.
864
- @return:
865
- """
866
- if self.source != "co2":
867
- # FPK only used for CO2 source.
868
- return
869
- if self._fpk == fpk or fpk is None:
870
- return
871
- self._fpk = fpk
872
- first_pulse_killer = int(round(2000.0 / self._frequency))
873
- self.list_set_co2_fpk(first_pulse_killer)
874
-
875
- def light_on(self):
876
- if not self.is_port(self._light_bit):
877
- self.port_on(self._light_bit)
878
- return True
879
- return False
880
-
881
- def light_off(self):
882
- if self.is_port(self._light_bit):
883
- self.port_off(self._light_bit)
884
- return True
885
- return False
886
-
887
- def is_port(self, bit):
888
- return bool((1 << bit) & self._port_bits)
889
-
890
- def port_on(self, bit):
891
- self._port_bits = self._port_bits | (1 << bit)
892
-
893
- def port_off(self, bit):
894
- self._port_bits = ~((~self._port_bits) | (1 << bit))
895
-
896
- def port_set(self, mask, values):
897
- self._port_bits &= ~mask # Unset mask.
898
- self._port_bits |= values & mask # Set masked bits.
899
-
900
- #######################
901
- # UNIT CONVERSIONS
902
- #######################
903
-
904
- def _convert_speed(self, speed):
905
- """
906
- Speed in the galvo is given in galvos/ms this means mm/s needs to multiply by galvos_per_mm
907
- and divide by 1000 (s/ms)
908
-
909
- @param speed:
910
- @return:
911
- """
912
- # return int(speed / 2)
913
- galvos_per_mm, _ = self.service.view.position("1mm", "1mm", vector=True)
914
- return abs(int(speed * galvos_per_mm / 1000.0))
915
-
916
- def _convert_frequency(self, frequency_khz, base=20000.0):
917
- """
918
- Converts frequency to period.
919
-
920
- 20000000.0 / frequency in hz
921
-
922
- @param frequency_khz: Frequency to convert
923
- @return:
924
- """
925
- return int(round(base / frequency_khz)) & 0xFFFF
926
-
927
- def _convert_power(self, power):
928
- """
929
- Converts power percent to int value
930
- @return:
931
- """
932
- return int(round(power * 0xFFF / 100.0))
933
-
934
- #######################
935
- # HIGH LEVEL OPERATIONS
936
- #######################
937
-
938
- def write_correction_file(self, filename):
939
- if filename is None:
940
- self.write_blank_correct_file()
941
- self.usb_log("Correction file set to blank.")
942
- return
943
- try:
944
- table = self._read_correction_file(filename)
945
- self._write_correction_table(table)
946
- self.usb_log("Correction File Sent")
947
- except OSError:
948
- self.write_blank_correct_file()
949
- self.usb_log("Correction file set to blank.")
950
- return
951
-
952
- @staticmethod
953
- def get_scale_from_correction_file(filename):
954
- with open(filename, "rb") as f:
955
- label = f.read(0x16)
956
- if label.decode("utf-16") == "LMC1COR_1.0":
957
- unk = f.read(2)
958
- return struct.unpack("63d", f.read(0x1F8))[43]
959
- else:
960
- unk = f.read(6)
961
- return struct.unpack("d", f.read(8))[0]
962
-
963
- def write_blank_correct_file(self):
964
- self.write_cor_table(False)
965
-
966
- def _read_float_correction_file(self, f):
967
- """
968
- Read table for cor files marked: LMC1COR_1.0
969
- @param f:
970
- @return:
971
- """
972
- table = []
973
- for j in range(65):
974
- for k in range(65):
975
- dx = int(round(struct.unpack("d", f.read(8))[0]))
976
- dx = dx if dx >= 0 else -dx + 0x8000
977
- dy = int(round(struct.unpack("d", f.read(8))[0]))
978
- dy = dy if dy >= 0 else -dy + 0x8000
979
- table.append([dx & 0xFFFF, dy & 0xFFFF])
980
- return table
981
-
982
- def _read_int_correction_file(self, f):
983
- table = []
984
- for j in range(65):
985
- for k in range(65):
986
- dx = int.from_bytes(f.read(4), "little", signed=True)
987
- dx = dx if dx >= 0 else -dx + 0x8000
988
- dy = int.from_bytes(f.read(4), "little", signed=True)
989
- dy = dy if dy >= 0 else -dy + 0x8000
990
- table.append([dx & 0xFFFF, dy & 0xFFFF])
991
- return table
992
-
993
- def _read_correction_file(self, filename):
994
- """
995
- Reads a standard .cor file and builds a table from that.
996
-
997
- @param filename:
998
- @return:
999
- """
1000
- with open(filename, "rb") as f:
1001
- label = f.read(0x16)
1002
- if label.decode("utf-16") == "LMC1COR_1.0":
1003
- header = f.read(0x1FA)
1004
- return self._read_float_correction_file(f)
1005
- else:
1006
- header = f.read(0xE)
1007
- return self._read_int_correction_file(f)
1008
-
1009
- def _write_correction_table(self, table):
1010
- assert len(table) == 65 * 65
1011
- self.write_cor_table(True)
1012
- first = True
1013
- for dx, dy in table:
1014
- self.write_cor_line(dx, dy, 0 if first else 1)
1015
- first = False
1016
-
1017
- #######################
1018
- # COMMAND LIST COMMAND
1019
- #######################
1020
-
1021
- def list_jump(self, x, y, short=None, long=None, distance_limit=None):
1022
- distance = int(abs(complex(x, y) - complex(self._last_x, self._last_y)))
1023
- if distance_limit and distance > distance_limit:
1024
- delay = long
1025
- else:
1026
- delay = short
1027
- if distance > 0xFFFF:
1028
- distance = 0xFFFF
1029
- angle = 0
1030
- if delay:
1031
- self.list_jump_delay(delay)
1032
- x = int(x)
1033
- y = int(y)
1034
- self._list_write(listJumpTo, x, y, angle, distance)
1035
- self._last_x = x
1036
- self._last_y = y
1037
-
1038
- def list_end_of_list(self):
1039
- self._list_write(listEndOfList)
1040
-
1041
- def list_laser_on_point(self, dwell_time):
1042
- self._list_write(listLaserOnPoint, dwell_time)
1043
-
1044
- def list_delay_time(self, time):
1045
- """
1046
- Delay time in 10 microseconds units
1047
-
1048
- @param time:
1049
- @return:
1050
- """
1051
- self._list_write(listDelayTime, abs(time))
1052
-
1053
- def list_mark(self, x, y, angle=0):
1054
- distance = int(abs(complex(x, y) - complex(self._last_x, self._last_y)))
1055
- if distance > 0xFFFF:
1056
- distance = 0xFFFF
1057
- x = int(x)
1058
- y = int(y)
1059
- self._list_write(listMarkTo, x, y, angle, distance)
1060
- self._last_x = x
1061
- self._last_y = y
1062
-
1063
- def list_jump_speed(self, speed):
1064
- if self._travel_speed == speed:
1065
- return
1066
- self._travel_speed = speed
1067
- c_speed = self._convert_speed(speed)
1068
- if c_speed > 0xFFFF:
1069
- c_speed = 0xFFFF
1070
- self._list_write(listJumpSpeed, c_speed)
1071
-
1072
- def list_laser_on_delay(self, delay):
1073
- """
1074
- Set laser on delay in microseconds
1075
- @param delay:
1076
- @return:
1077
- """
1078
- if self._delay_on == delay:
1079
- return
1080
- self._delay_on = delay
1081
- self._list_write(listLaserOnDelay, abs(delay), 0x0000 if delay > 0 else 0x8000)
1082
-
1083
- def list_laser_off_delay(self, delay):
1084
- """
1085
- Set laser off delay in microseconds
1086
- @param delay:
1087
- @return:
1088
- """
1089
- if self._delay_off == delay:
1090
- return
1091
- self._delay_off = delay
1092
- self._list_write(listLaserOffDelay, abs(delay), 0x0000 if delay > 0 else 0x8000)
1093
-
1094
- def list_mark_frequency(self, frequency):
1095
- """
1096
- This command is used in some machines but, it's not clear given the amount of reverse engineering how those
1097
- values are set. This is done for laser_type = 4.
1098
-
1099
- @param frequency:
1100
- @return:
1101
- """
1102
- self._list_write(listMarkFreq, frequency)
1103
-
1104
- def list_mark_power_ratio(self, power_ratio):
1105
- """
1106
- This command is used in some machines. Laser_type=4 and laser_type=0 (CO2), if 0x800A returned 0.
1107
-
1108
- @param power_ratio:
1109
- @return:
1110
- """
1111
- # listMarkPowerRatio
1112
- self._list_write(listMarkPowerRatio, power_ratio)
1113
-
1114
- def list_mark_speed(self, speed):
1115
- """
1116
- Sets the marking speed for the laser.
1117
-
1118
- @param speed:
1119
- @return:
1120
- """
1121
- if self._speed == speed:
1122
- return
1123
- self._speed = speed
1124
- c_speed = self._convert_speed(speed)
1125
- if c_speed > 0xFFFF:
1126
- c_speed = 0xFFFF
1127
- self._list_write(listMarkSpeed, c_speed)
1128
-
1129
- def list_jump_delay(self, delay):
1130
- """
1131
- Set laser jump delay in microseconds
1132
- @param delay:
1133
- @return:
1134
- """
1135
- if self._delay_jump == delay:
1136
- return
1137
- self._delay_jump = delay
1138
- self._list_write(listJumpDelay, abs(delay), 0x0000 if delay > 0 else 0x8000)
1139
-
1140
- def list_polygon_delay(self, delay):
1141
- """
1142
- Set polygon delay in microseconds
1143
- @param delay:
1144
- @return:
1145
- """
1146
- if self._delay_poly == delay:
1147
- return
1148
- self._delay_poly = delay
1149
- self._list_write(listPolygonDelay, abs(delay), 0x0000 if delay > 0 else 0x8000)
1150
-
1151
- def list_write_port(self):
1152
- """
1153
- Writes the set port values to the list.
1154
-
1155
- @return:
1156
- """
1157
- self._list_write(listWritePort, self._port_bits)
1158
-
1159
- def list_mark_current(self, current):
1160
- """
1161
- Also called as part of setting the power ratio. This is not correctly understood.
1162
- @param current:
1163
- @return:
1164
- """
1165
- # listMarkCurrent
1166
- self._list_write(listMarkCurrent, current)
1167
-
1168
- def list_mark_frequency_2(self, frequency):
1169
- """
1170
- Also called as part of setting frequency and is not correctly understood.
1171
-
1172
- @param frequency:
1173
- @return:
1174
- """
1175
- # listMarkFreq2
1176
- raise NotImplementedError
1177
-
1178
- def list_fly_enable(self, enabled=1):
1179
- """
1180
- On-The-Fly control enable/disable within list.
1181
-
1182
- @param enabled:
1183
- @return:
1184
- """
1185
- self._list_write(listFlyEnable, enabled)
1186
-
1187
- def list_qswitch_period(self, qswitch):
1188
- """
1189
- Sets the qswitch period, which in is the inversely related to frequency.
1190
-
1191
- @param qswitch:
1192
- @return:
1193
- """
1194
- self._list_write(listQSwitchPeriod, qswitch)
1195
-
1196
- def list_direct_laser_switch(self):
1197
- """
1198
- This is not understood.
1199
- @return:
1200
- """
1201
- # ListDirectLaserSwitch
1202
- raise NotImplementedError
1203
-
1204
- def list_fly_delay(self, delay):
1205
- """
1206
- On-the-fly control.
1207
-
1208
- @param delay:
1209
- @return:
1210
- """
1211
- self._list_write(listFlyDelay, abs(delay), 0x0000 if delay > 0 else 0x8000)
1212
-
1213
- def list_set_co2_fpk(self, fpk1, fpk2=None):
1214
- """
1215
- Set the CO2 Laser, First Pulse Killer.
1216
-
1217
- @return:
1218
- """
1219
- if fpk2 is None:
1220
- fpk2 = fpk1
1221
- self._list_write(listSetCo2FPK, fpk1, fpk2)
1222
-
1223
- def list_fly_wait_input(self):
1224
- """
1225
- Sets the On-the-fly to wait for input.
1226
- @return:
1227
- """
1228
- self._list_write(listFlyWaitInput)
1229
-
1230
- def list_fiber_open_mo(self, open_mo):
1231
- """
1232
- Sets motion operations, without MO set the laser does not automatically fire while moving.
1233
-
1234
- @param open_mo:
1235
- @return:
1236
- """
1237
- self._list_write(listFiberOpenMO, open_mo)
1238
-
1239
- def list_wait_for_input(self, wait_mask, wait_level):
1240
- """
1241
- Unknown.
1242
-
1243
- @return:
1244
- """
1245
- self._list_write(listWaitForInput, wait_mask, wait_level)
1246
-
1247
- def list_change_mark_count(self, count):
1248
- """
1249
- Unknown.
1250
-
1251
- @param count:
1252
- @return:
1253
- """
1254
- self._list_write(listChangeMarkCount, count)
1255
-
1256
- def list_set_weld_power_wave(self, weld_power_wave):
1257
- """
1258
- Unknown.
1259
-
1260
- @param weld_power_wave:
1261
- @return:
1262
- """
1263
- self._list_write(listSetWeldPowerWave, weld_power_wave)
1264
-
1265
- def list_enable_weld_power_wave(self, enabled):
1266
- """
1267
- Unknown.
1268
-
1269
- @param enabled:
1270
- @return:
1271
- """
1272
- self._list_write(listEnableWeldPowerWave, enabled)
1273
-
1274
- def list_fiber_ylpm_pulse_width(self, pulse_width):
1275
- """
1276
- Unknown.
1277
-
1278
- @param pulse_width:
1279
- @return:
1280
- """
1281
- if self._pulse_width == pulse_width:
1282
- return
1283
- self._pulse_width = pulse_width
1284
- self._list_write(listFiberYLPMPulseWidth, pulse_width)
1285
-
1286
- def list_fly_encoder_count(self, count):
1287
- """
1288
- Unknown.
1289
-
1290
- @param count:
1291
- @return:
1292
- """
1293
- self._list_write(listFlyEncoderCount, count)
1294
-
1295
- def list_set_da_z_word(self, word):
1296
- """
1297
- Unknown.
1298
-
1299
- @param word:
1300
- @return:
1301
- """
1302
- self._list_write(listSetDaZWord, word)
1303
-
1304
- def list_jpt_set_param(self, param):
1305
- """
1306
- Unknown.
1307
-
1308
- @param param:
1309
- @return:
1310
- """
1311
- self._list_write(listJptSetParam, param)
1312
-
1313
- def list_ready(self):
1314
- """
1315
- Seen at the start of any new command list.
1316
-
1317
- @return:
1318
- """
1319
- self._list_write(listReadyMark)
1320
-
1321
- #######################
1322
- # COMMAND LIST SHORTCUTS
1323
- #######################
1324
-
1325
- def disable_laser(self):
1326
- return self._command(DisableLaser)
1327
-
1328
- def enable_laser(self):
1329
- return self._command(EnableLaser)
1330
-
1331
- def execute_list(self):
1332
- return self._command(ExecuteList)
1333
-
1334
- def set_pwm_pulse_width(self, pulse_width):
1335
- return self._command(SetPwmPulseWidth, pulse_width)
1336
-
1337
- def get_version(self):
1338
- return self._command(GetVersion)
1339
-
1340
- def get_serial_number(self):
1341
- return self._command(GetSerialNo)
1342
-
1343
- def get_list_status(self):
1344
- return self._command(GetListStatus)
1345
-
1346
- def get_position_xy(self):
1347
- return self._command(GetPositionXY)
1348
-
1349
- def goto_xy(self, x, y, angle=0, distance=0):
1350
- self._last_x = x
1351
- self._last_y = y
1352
- return self._command(GotoXY, int(x), int(y), int(angle), int(distance))
1353
-
1354
- def laser_signal_off(self):
1355
- return self._command(LaserSignalOff)
1356
-
1357
- def laser_signal_on(self):
1358
- return self._command(LaserSignalOn)
1359
-
1360
- def write_cor_line(self, dx, dy, non_first):
1361
- self._command(WriteCorLine, dx, dy, non_first, read=False)
1362
-
1363
- def reset_list(self):
1364
- return self._command(ResetList)
1365
-
1366
- def restart_list(self):
1367
- return self._command(RestartList)
1368
-
1369
- def write_cor_table(self, table: bool = True):
1370
- return self._command(WriteCorTable, int(table))
1371
-
1372
- def set_control_mode(self, mode):
1373
- return self._command(SetControlMode, mode)
1374
-
1375
- def set_delay_mode(self, mode):
1376
- return self._command(SetDelayMode, mode)
1377
-
1378
- def set_max_poly_delay(self, delay):
1379
- return self._command(
1380
- SetMaxPolyDelay, abs(delay), 0x0000 if delay > 0 else 0x8000
1381
- )
1382
-
1383
- def set_end_of_list(self, end):
1384
- return self._command(SetEndOfList, end)
1385
-
1386
- def set_first_pulse_killer(self, fpk):
1387
- return self._command(SetFirstPulseKiller, fpk)
1388
-
1389
- def set_laser_mode(self, mode):
1390
- return self._command(SetLaserMode, mode)
1391
-
1392
- def set_timing(self, timing):
1393
- return self._command(SetTiming, timing)
1394
-
1395
- def set_standby(self, standby1, standby2):
1396
- return self._command(SetStandby, standby1, standby2)
1397
-
1398
- def set_pwm_half_period(self, pwm_half_period):
1399
- return self._command(SetPwmHalfPeriod, pwm_half_period)
1400
-
1401
- def stop_execute(self):
1402
- return self._command(StopExecute)
1403
-
1404
- def stop_list(self):
1405
- return self._command(StopList)
1406
-
1407
- def write_port(self):
1408
- return self._command(WritePort, self._port_bits)
1409
-
1410
- def write_analog_port_1(self, port):
1411
- return self._command(WriteAnalogPort1, port)
1412
-
1413
- def write_analog_port_2(self, port):
1414
- return self._command(WriteAnalogPort2, port)
1415
-
1416
- def write_analog_port_x(self, port):
1417
- return self._command(WriteAnalogPortX, port)
1418
-
1419
- def read_port(self):
1420
- return self._command(ReadPort)
1421
-
1422
- def set_axis_motion_param(self, *param):
1423
- return self._command(SetAxisMotionParam, *param)
1424
-
1425
- def set_axis_origin_param(self, *param):
1426
- return self._command(SetAxisOriginParam, *param)
1427
-
1428
- def axis_go_origin(self):
1429
- return self._command(AxisGoOrigin)
1430
-
1431
- def move_axis_to(self, position, invert):
1432
- return self._command(MoveAxisTo, position, invert)
1433
-
1434
- def get_axis_pos(self, index=0):
1435
- return self._command(GetAxisPos, index)
1436
-
1437
- def get_fly_wait_count(self):
1438
- return self._command(GetFlyWaitCount)
1439
-
1440
- def get_mark_count(self):
1441
- return self._command(GetMarkCount)
1442
-
1443
- def set_pfk_param_2(self, param1, param2, param3, param4):
1444
- return self._command(SetFpkParam2, param1, param2, param3, param4)
1445
-
1446
- def set_fiber_mo(self, mo):
1447
- """
1448
- mo == 0 close
1449
- mo == 1 open
1450
-
1451
- @param mo:
1452
- @return:
1453
- """
1454
- return self._command(Fiber_SetMo, mo)
1455
-
1456
- def get_fiber_st_mo_ap(self):
1457
- return self._command(Fiber_GetStMO_AP)
1458
-
1459
- def enable_z(self):
1460
- return self._command(EnableZ)
1461
-
1462
- def disable_z(self):
1463
- return self._command(DisableZ)
1464
-
1465
- def set_z_data(self, zdata):
1466
- return self._command(SetZData, zdata)
1467
-
1468
- def set_spi_simmer_current(self, current):
1469
- return self._command(SetSPISimmerCurrent, current)
1470
-
1471
- def set_fpk_param(self, param):
1472
- return self._command(SetFpkParam, param)
1473
-
1474
- def reset(self):
1475
- return self._command(Reset)
1476
-
1477
- def get_fly_speed(self):
1478
- return self._command(GetFlySpeed)
1479
-
1480
- def fiber_pulse_width(self):
1481
- return self._command(FiberPulseWidth)
1482
-
1483
- def get_fiber_config_extend(self):
1484
- return self._command(FiberGetConfigExtend)
1485
-
1486
- def input_port(self, port):
1487
- return self._command(InputPort, port)
1488
-
1489
- def clear_lock_input_port(self):
1490
- return self._command(InputPort, 0x04)
1491
-
1492
- def enable_lock_input_port(self):
1493
- return self._command(InputPort, 0x02)
1494
-
1495
- def disable_lock_input_port(self):
1496
- return self._command(InputPort, 0x01)
1497
-
1498
- def get_input_port(self):
1499
- return self._command(InputPort)
1500
-
1501
- def get_mark_time(self):
1502
- """
1503
- Get Mark Time is always called with data 3. With 0 it returns 0. It is unknown what the payload means.
1504
- @return:
1505
- """
1506
- return self._command(GetMarkTime, 3)
1507
-
1508
- def get_user_data(self):
1509
- return self._command(GetUserData)
1510
-
1511
- def set_fly_res(self, fly_res1, fly_res2, fly_res3, fly_res4):
1512
- return self._command(SetFlyRes, fly_res1, fly_res2, fly_res3, fly_res4)
1
+ """
2
+ Galvo Controller
3
+
4
+ The balor controller takes low level lmc galvo commands and converts them into lists and shorts commands to send
5
+ to the hardware controller.
6
+ """
7
+
8
+ import struct
9
+ import threading
10
+ import time
11
+ from copy import copy
12
+ from usb.core import NoBackendError
13
+
14
+ from meerk40t.balormk.mock_connection import MockConnection
15
+ from meerk40t.balormk.usb_connection import USBConnection
16
+
17
+ DRIVER_STATE_RAPID = 0
18
+ DRIVER_STATE_LIGHT = 1
19
+ DRIVER_STATE_PROGRAM = 2
20
+ DRIVER_STATE_RAW = 3
21
+
22
+ nop = [0x02, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
23
+ empty = bytearray(nop * 0x100)
24
+
25
+ listJumpTo = 0x8001
26
+ listEndOfList = 0x8002
27
+ listLaserOnPoint = 0x8003
28
+ listDelayTime = 0x8004
29
+ listMarkTo = 0x8005
30
+ listJumpSpeed = 0x8006
31
+ listLaserOnDelay = 0x8007
32
+ listLaserOffDelay = 0x8008
33
+ listMarkFreq = 0x800A
34
+ listMarkPowerRatio = 0x800B
35
+ listMarkSpeed = 0x800C
36
+ listJumpDelay = 0x800D
37
+ listPolygonDelay = 0x800F
38
+ listWritePort = 0x8011
39
+ listMarkCurrent = 0x8012
40
+ listMarkFreq2 = 0x8013
41
+ listFlyEnable = 0x801A
42
+ listQSwitchPeriod = 0x801B
43
+ listDirectLaserSwitch = 0x801C
44
+ listFlyDelay = 0x801D
45
+ listSetCo2FPK = 0x801E
46
+ listFlyWaitInput = 0x801F
47
+ listFiberOpenMO = 0x8021
48
+ listWaitForInput = 0x8022
49
+ listChangeMarkCount = 0x8023
50
+ listSetWeldPowerWave = 0x8024
51
+ listEnableWeldPowerWave = 0x8025
52
+ listFiberYLPMPulseWidth = 0x8026
53
+ listFlyEncoderCount = 0x8028
54
+ listSetDaZWord = 0x8029
55
+ listJptSetParam = 0x8050
56
+ listReadyMark = 0x8051
57
+
58
+ DisableLaser = 0x0002
59
+ EnableLaser = 0x0004
60
+ ExecuteList = 0x0005
61
+ SetPwmPulseWidth = 0x0006
62
+ GetVersion = 0x0007
63
+ GetSerialNo = 0x0009
64
+ GetListStatus = 0x000A
65
+ GetPositionXY = 0x000C
66
+ GotoXY = 0x000D
67
+ LaserSignalOff = 0x000E
68
+ LaserSignalOn = 0x000F
69
+ WriteCorLine = 0x0010
70
+ ResetList = 0x0012
71
+ RestartList = 0x0013
72
+ WriteCorTable = 0x0015
73
+ SetControlMode = 0x0016
74
+ SetDelayMode = 0x0017
75
+ SetMaxPolyDelay = 0x0018
76
+ SetEndOfList = 0x0019
77
+ SetFirstPulseKiller = 0x001A
78
+ SetLaserMode = 0x001B
79
+ SetTiming = 0x001C
80
+ SetStandby = 0x001D
81
+ SetPwmHalfPeriod = 0x001E
82
+ StopExecute = 0x001F
83
+ StopList = 0x0020
84
+ WritePort = 0x0021
85
+ WriteAnalogPort1 = 0x0022
86
+ WriteAnalogPort2 = 0x0023
87
+ WriteAnalogPortX = 0x0024
88
+ ReadPort = 0x0025
89
+ SetAxisMotionParam = 0x0026
90
+ SetAxisOriginParam = 0x0027
91
+ AxisGoOrigin = 0x0028
92
+ MoveAxisTo = 0x0029
93
+ GetAxisPos = 0x002A
94
+ GetFlyWaitCount = 0x002B
95
+ GetMarkCount = 0x002D
96
+ SetFpkParam2 = 0x002E
97
+ Fiber_SetMo = 0x0033 # open and close set by value
98
+ Fiber_GetStMO_AP = 0x0034
99
+ EnableZ = 0x003A
100
+ DisableZ = 0x0039
101
+ SetZData = 0x003B
102
+ SetSPISimmerCurrent = 0x003C
103
+ SetFpkParam = 0x0062
104
+ Reset = 0x0040
105
+ GetFlySpeed = 0x0038
106
+ FiberPulseWidth = 0x002F
107
+ FiberGetConfigExtend = 0x0030
108
+ InputPort = 0x0031 # ClearLockInputPort calls 0x04, then if EnableLockInputPort 0x02 else 0x01, GetLockInputPort
109
+ GetMarkTime = 0x0041
110
+ GetUserData = 0x0036
111
+ SetFlyRes = 0x0032
112
+
113
+ list_command_lookup = {
114
+ 0x8001: "listJumpTo",
115
+ 0x8002: "listEndOfList",
116
+ 0x8003: "listLaserOnPoint",
117
+ 0x8004: "listDelayTime",
118
+ 0x8005: "listMarkTo",
119
+ 0x8006: "listJumpSpeed",
120
+ 0x8007: "listLaserOnDelay",
121
+ 0x8008: "listLaserOffDelay",
122
+ 0x800A: "listMarkFreq",
123
+ 0x800B: "listMarkPowerRatio",
124
+ 0x800C: "listMarkSpeed",
125
+ 0x800D: "listJumpDelay",
126
+ 0x800F: "listPolygonDelay",
127
+ 0x8011: "listWritePort",
128
+ 0x8012: "listMarkCurrent",
129
+ 0x8013: "listMarkFreq2",
130
+ 0x801A: "listFlyEnable",
131
+ 0x801B: "listQSwitchPeriod",
132
+ 0x801C: "listDirectLaserSwitch",
133
+ 0x801D: "listFlyDelay",
134
+ 0x801E: "listSetCo2FPK",
135
+ 0x801F: "listFlyWaitInput",
136
+ 0x8021: "listFiberOpenMO",
137
+ 0x8022: "listWaitForInput",
138
+ 0x8023: "listChangeMarkCount",
139
+ 0x8024: "listSetWeldPowerWave",
140
+ 0x8025: "listEnableWeldPowerWave",
141
+ 0x8026: "listFiberYLPMPulseWidth",
142
+ 0x8028: "listFlyEncoderCount",
143
+ 0x8029: "listSetDaZWord",
144
+ 0x8050: "listJptSetParam",
145
+ 0x8051: "listReadyMark",
146
+ }
147
+
148
+ single_command_lookup = {
149
+ 0x0002: "DisableLaser",
150
+ 0x0004: "EnableLaser",
151
+ 0x0005: "ExecuteList",
152
+ 0x0006: "SetPwmPulseWidth",
153
+ 0x0007: "GetVersion",
154
+ 0x0009: "GetSerialNo",
155
+ 0x000A: "GetListStatus",
156
+ 0x000C: "GetPositionXY",
157
+ 0x000D: "GotoXY",
158
+ 0x000E: "LaserSignalOff",
159
+ 0x000F: "LaserSignalOn",
160
+ 0x0010: "WriteCorLine",
161
+ 0x0012: "ResetList",
162
+ 0x0013: "RestartList",
163
+ 0x0015: "WriteCorTable",
164
+ 0x0016: "SetControlMode",
165
+ 0x0017: "SetDelayMode",
166
+ 0x0018: "SetMaxPolyDelay",
167
+ 0x0019: "SetEndOfList",
168
+ 0x001A: "SetFirstPulseKiller",
169
+ 0x001B: "SetLaserMode",
170
+ 0x001C: "SetTiming",
171
+ 0x001D: "SetStandby",
172
+ 0x001E: "SetPwmHalfPeriod",
173
+ 0x001F: "StopExecute",
174
+ 0x0020: "StopList",
175
+ 0x0021: "WritePort",
176
+ 0x0022: "WriteAnalogPort1",
177
+ 0x0023: "WriteAnalogPort2",
178
+ 0x0024: "WriteAnalogPortX",
179
+ 0x0025: "ReadPort",
180
+ 0x0026: "SetAxisMotionParam",
181
+ 0x0027: "SetAxisOriginParam",
182
+ 0x0028: "AxisGoOrigin",
183
+ 0x0029: "MoveAxisTo",
184
+ 0x002A: "GetAxisPos",
185
+ 0x002B: "GetFlyWaitCount",
186
+ 0x002D: "GetMarkCount",
187
+ 0x002E: "SetFpkParam2",
188
+ 0x0033: "Fiber_SetMo",
189
+ 0x0034: "Fiber_GetStMO_AP",
190
+ 0x003A: "EnableZ",
191
+ 0x0039: "DisableZ",
192
+ 0x003B: "SetZData",
193
+ 0x003C: "SetSPISimmerCurrent",
194
+ 0x0062: "SetFpkParam",
195
+ 0x0040: "Reset",
196
+ 0x0038: "GetFlySpeed",
197
+ 0x002F: "FiberPulseWidth",
198
+ 0x0030: "FiberGetConfigExtend",
199
+ 0x0031: "InputPort",
200
+ 0x0041: "GetMarkTime",
201
+ 0x0036: "GetUserData",
202
+ 0x0032: "SetFlyRes",
203
+ }
204
+
205
+ BUSY = 0x04
206
+ READY = 0x20
207
+ AXIS = 0x40
208
+
209
+
210
+ def _bytes_to_words(r):
211
+ b0 = r[1] << 8 | r[0]
212
+ b1 = r[3] << 8 | r[2]
213
+ b2 = r[5] << 8 | r[4]
214
+ b3 = r[7] << 8 | r[6]
215
+ return b0, b1, b2, b3
216
+
217
+
218
+ class GalvoController:
219
+ """
220
+ Galvo controller is tasked with sending queued data to the controller board and ensuring that the connection to the
221
+ controller board is established to perform these actions.
222
+
223
+ This should serve as a next generation command sequencer written from scratch for galvo lasers. The goal is to
224
+ provide all the given commands in a coherent queue structure which provides correct sequences between list and
225
+ single commands.
226
+ """
227
+
228
+ def __init__(
229
+ self,
230
+ service,
231
+ x=0x8000,
232
+ y=0x8000,
233
+ mark_speed=None,
234
+ goto_speed=None,
235
+ light_speed=None,
236
+ dark_speed=None,
237
+ force_mock=False,
238
+ ):
239
+ self.service = service
240
+ self.force_mock = force_mock
241
+ self.is_shutdown = False # Shutdown finished.
242
+
243
+ self.usb_log = service.channel(
244
+ f"{self.service.safe_label}/usb", buffer_size=500
245
+ )
246
+ self.usb_log.watch(lambda e: service.signal("pipe;usb_status", e))
247
+
248
+ self.connection = None
249
+ self._is_opening = False
250
+ self._abort_open = False
251
+ self._disable_connect = False
252
+
253
+ self._light_bit = 8
254
+ self._foot_bit = 15
255
+ self.define_pins()
256
+
257
+ self._last_x = x
258
+ self._last_y = y
259
+ self._mark_speed = mark_speed
260
+ self._goto_speed = goto_speed
261
+ self._light_speed = light_speed
262
+ self._dark_speed = dark_speed
263
+ self.serial_confirmed = False
264
+ self.serial_number_found = None
265
+
266
+ self._ready = None
267
+ self._speed = None
268
+ self._travel_speed = None
269
+ self._frequency = None
270
+ self._power = None
271
+ self._pulse_width = None
272
+ self._fpk = None
273
+
274
+ self._delay_jump = None
275
+ self._delay_on = None
276
+ self._delay_off = None
277
+ self._delay_poly = None
278
+ self._delay_end = None
279
+
280
+ self._port_bits = 0
281
+ self._machine_index = 0
282
+
283
+ self.mode = DRIVER_STATE_RAPID
284
+ self._list_lock = threading.RLock()
285
+ self._active_list = None
286
+ self._active_index = 0
287
+ self._list_executing = False
288
+ self._number_of_list_packets = 0
289
+ self.paused = False
290
+ self._signal_updates = self.service.setting(bool, "signal_updates", True)
291
+
292
+ def define_pins(self):
293
+ self._light_bit = self.service.setting(int, "light_pin", 8)
294
+ self._foot_bit = self.service.setting(int, "footpedal_pin", 15)
295
+
296
+ @property
297
+ def source(self):
298
+ return self.service.source
299
+
300
+ @property
301
+ def state(self):
302
+ if self.mode == DRIVER_STATE_RAPID:
303
+ return "idle", "idle"
304
+ if self.paused:
305
+ return "hold", "paused"
306
+ if self.mode == DRIVER_STATE_RAW:
307
+ return "busy", "raw"
308
+ if self.mode == DRIVER_STATE_LIGHT:
309
+ return "busy", "light"
310
+ if self.mode == DRIVER_STATE_PROGRAM:
311
+ return "busy", "program"
312
+
313
+ def set_disable_connect(self, status):
314
+ self._disable_connect = status
315
+
316
+ def added(self):
317
+ pass
318
+
319
+ def service_detach(self):
320
+ pass
321
+
322
+ def shutdown(self, *args, **kwargs):
323
+ self.is_shutdown = True
324
+
325
+ @property
326
+ def connected(self):
327
+ if self.connection is None:
328
+ return False
329
+ return self.connection.is_open(self._machine_index)
330
+
331
+ @property
332
+ def is_connecting(self):
333
+ if self.connection is None:
334
+ return False
335
+ return self._is_opening
336
+
337
+ def abort_connect(self):
338
+ self._abort_open = True
339
+ self.usb_log("Connect Attempts Aborted")
340
+
341
+ def disconnect(self):
342
+ try:
343
+ self.connection.close(self._machine_index)
344
+ except (ConnectionError, ConnectionRefusedError, AttributeError):
345
+ pass
346
+ self.connection = None
347
+ self.serial_number_found = None
348
+ # Reset error to allow another attempt
349
+ self.set_disable_connect(False)
350
+
351
+ def connect_if_needed(self):
352
+ if self._disable_connect:
353
+ # After many failures automatic connects are disabled. We require a manual connection.
354
+ self.abort_connect()
355
+ self.connection = None
356
+ raise ConnectionRefusedError(
357
+ "LMC was unreachable. Explicit connect required."
358
+ )
359
+ if self.connection is None:
360
+ if self.service.setting(bool, "mock", False) or self.force_mock:
361
+ self.connection = MockConnection(self.usb_log)
362
+ name = self.service.safe_label
363
+ self.connection.send = self.service.channel(f"{name}/send")
364
+ self.connection.recv = self.service.channel(f"{name}/recv")
365
+ else:
366
+ self.connection = USBConnection(self.usb_log)
367
+ self._is_opening = True
368
+ self._abort_open = False
369
+ count = 0
370
+ while not self.connection.is_open(self._machine_index):
371
+ try:
372
+ if self.connection.open(self._machine_index) < 0:
373
+ raise ConnectionError
374
+ self.init_laser()
375
+ except (ConnectionError, ConnectionRefusedError):
376
+ if count == 0:
377
+ self.service("clone_init\n")
378
+ time.sleep(0.3)
379
+ count += 1
380
+ # self.usb_log(f"Error-Routine pass #{count}")
381
+ if self.is_shutdown or self._abort_open:
382
+ self._is_opening = False
383
+ self._abort_open = False
384
+ return
385
+ if self.connection.is_open(self._machine_index):
386
+ self.connection.close(self._machine_index)
387
+ if count >= 10:
388
+ # We have failed too many times.
389
+ self._is_opening = False
390
+ self.set_disable_connect(True)
391
+ self.usb_log("Could not connect to the LMC controller.")
392
+ self.usb_log("Automatic connections disabled.")
393
+ from platform import system
394
+ osname = system()
395
+ if osname == "Windows":
396
+ self.usb_log("Did you install the libusb driver via Zadig (https://zadig.akeo.ie/)?")
397
+ self.usb_log("Consult the wiki: https://github.com/meerk40t/meerk40t/wiki/Install%3A-Windows")
398
+ raise ConnectionRefusedError(
399
+ "Could not connect to the LMC controller."
400
+ )
401
+ time.sleep(0.3)
402
+ continue
403
+ self._is_opening = False
404
+ self._abort_open = False
405
+
406
+ def send(self, data, read=True):
407
+ if self.is_shutdown:
408
+ return -1, -1, -1, -1
409
+ try:
410
+ self.connect_if_needed()
411
+ except (ConnectionRefusedError, NoBackendError):
412
+ return -1, -1, -1, -1
413
+ try:
414
+ self.connection.write(self._machine_index, data)
415
+ except ConnectionError:
416
+ return -1, -1, -1, -1
417
+ if read:
418
+ try:
419
+ r = self.connection.read(self._machine_index)
420
+ return struct.unpack("<4H", r)
421
+ except ConnectionError:
422
+ return -1, -1, -1, -1
423
+
424
+ def status(self):
425
+ b0, b1, b2, b3 = self.get_version()
426
+ return b3
427
+
428
+ #######################
429
+ # MODE SHIFTS
430
+ #######################
431
+
432
+ def raw_mode(self):
433
+ self.mode = DRIVER_STATE_RAW
434
+
435
+ def rapid_mode(self):
436
+ if self.mode == DRIVER_STATE_RAPID:
437
+ return
438
+ self.list_end_of_list() # Ensure at least one list_end_of_list
439
+ self._list_end()
440
+ if not self._list_executing and self._number_of_list_packets:
441
+ # If we never ran the list, and we sent some lists.
442
+ self.execute_list()
443
+ self._list_executing = False
444
+ self._number_of_list_packets = 0
445
+ self.wait_idle()
446
+ if self.source == "fiber":
447
+ self.set_fiber_mo(0)
448
+ self.port_off(bit=0)
449
+ self.write_port()
450
+ marktime = self.get_mark_time()
451
+ self.service.signal("galvo;marktime", marktime)
452
+ self.usb_log(f"Time taken for list execution: {marktime}")
453
+ self.mode = DRIVER_STATE_RAPID
454
+
455
+ def raster_mode(self):
456
+ self.program_mode()
457
+
458
+ def program_mode(self):
459
+ if self.mode == DRIVER_STATE_PROGRAM:
460
+ return
461
+ if self.mode == DRIVER_STATE_LIGHT:
462
+ self.mode = DRIVER_STATE_PROGRAM
463
+ self.light_off()
464
+ self.port_on(bit=0)
465
+ self.write_port()
466
+ if self.source == "fiber":
467
+ self.set_fiber_mo(1)
468
+ else:
469
+ self.mode = DRIVER_STATE_PROGRAM
470
+ self.reset_list()
471
+ self.port_on(bit=0)
472
+ self.write_port()
473
+ if self.source == "fiber":
474
+ self.set_fiber_mo(1)
475
+ self._ready = None
476
+ self._speed = None
477
+ self._travel_speed = None
478
+ self._frequency = None
479
+ self._power = None
480
+ self._pulse_width = None
481
+
482
+ self._delay_jump = None
483
+ self._delay_on = None
484
+ self._delay_off = None
485
+ self._delay_poly = None
486
+ self._delay_end = None
487
+ self.list_ready()
488
+ if self.service.delay_openmo != 0 and self.source == "fiber":
489
+ self.list_delay_time(int(self.service.delay_openmo * 100))
490
+ self.list_write_port()
491
+ self.list_jump_speed(self.service.default_rapid_speed)
492
+
493
+ def light_mode(self):
494
+ if self.mode == DRIVER_STATE_LIGHT:
495
+ return
496
+ if self.mode == DRIVER_STATE_PROGRAM:
497
+ if self.source == "fiber":
498
+ self.set_fiber_mo(0)
499
+ self.port_off(bit=0)
500
+ self.port_on(self._light_bit)
501
+ self.write_port()
502
+ else:
503
+ self._ready = None
504
+ self._speed = None
505
+ self._travel_speed = None
506
+ self._frequency = None
507
+ self._power = None
508
+ self._pulse_width = None
509
+
510
+ self._delay_jump = None
511
+ self._delay_on = None
512
+ self._delay_off = None
513
+ self._delay_poly = None
514
+ self._delay_end = None
515
+
516
+ self.reset_list()
517
+ self.list_ready()
518
+ self.port_off(bit=0)
519
+ self.port_on(self._light_bit)
520
+ self.list_write_port()
521
+ self.mode = DRIVER_STATE_LIGHT
522
+
523
+ #######################
524
+ # LIST APPENDING OPERATIONS
525
+ #######################
526
+
527
+ def _list_end(self):
528
+ if not self._active_list or not self._active_index:
529
+ # Ensure there is a list to end.
530
+ return
531
+ with self._list_lock:
532
+ if not self._active_list or not self._active_index:
533
+ # Double-gated syntax, make sure there's still that list needing ending.
534
+ return
535
+ self.wait_ready()
536
+ while self.paused:
537
+ time.sleep(0.3)
538
+ self.send(self._active_list, False)
539
+ if self.mode != DRIVER_STATE_RAW:
540
+ self.set_end_of_list(0)
541
+ self._number_of_list_packets += 1
542
+ self._active_list = None
543
+ self._active_index = 0
544
+ if self._number_of_list_packets > 2 and not self._list_executing:
545
+ if self.mode != DRIVER_STATE_RAW:
546
+ self.execute_list()
547
+ self._list_executing = True
548
+
549
+ def _list_new(self):
550
+ with self._list_lock:
551
+ self._active_list = copy(empty)
552
+ self._active_index = 0
553
+
554
+ def _list_write(self, command, v1=0, v2=0, v3=0, v4=0, v5=0):
555
+ with self._list_lock:
556
+ if self._active_index >= 0xC00:
557
+ self._list_end()
558
+ if self._active_list is None:
559
+ self._list_new()
560
+ index = self._active_index
561
+ self._active_list[index : index + 12] = struct.pack(
562
+ "<6H", int(command), int(v1), int(v2), int(v3), int(v4), int(v5)
563
+ )
564
+ self._active_index += 12
565
+
566
+ def _command(self, command, v1=0, v2=0, v3=0, v4=0, v5=0, read=True):
567
+ cmd = struct.pack(
568
+ "<6H", int(command), int(v1), int(v2), int(v3), int(v4), int(v5)
569
+ )
570
+ return self.send(cmd, read=read)
571
+
572
+ def raw_write(self, command, v1=0, v2=0, v3=0, v4=0, v5=0):
573
+ """
574
+ Write this raw command to value. Sends the correct way based on command value.
575
+
576
+ @return:
577
+ """
578
+ if command >= 0x8000:
579
+ self._list_write(command, v1, v2, v3, v4, v5)
580
+ else:
581
+ self._command(command, v1, v2, v3, v4, v5)
582
+
583
+ def raw_clear(self):
584
+ self._list_new()
585
+
586
+ #######################
587
+ # SETS FOR PLOTLIKES
588
+ #######################
589
+
590
+ def set_settings(self, settings):
591
+ """
592
+ Sets the primary settings. Rapid, frequency, speed, and timings.
593
+
594
+ @param settings: The current settings dictionary
595
+ @return:
596
+ """
597
+ if self.service.pulse_width_enabled and self.source == "fiber":
598
+ # Global Pulse Width is enabled.
599
+ if str(settings.get("pulse_width_enabled", False)).lower() == "true":
600
+ # Local Pulse Width value is enabled.
601
+ # OpFiberYLPMPulseWidth
602
+
603
+ self.list_fiber_ylpm_pulse_width(
604
+ int(settings.get("pulse_width", self.service.default_pulse_width))
605
+ )
606
+ else:
607
+ # Only global is enabled, use global pulse width value.
608
+ self.list_fiber_ylpm_pulse_width(self.service.default_pulse_width)
609
+
610
+ if str(settings.get("rapid_enabled", False)).lower() == "true":
611
+ self.list_jump_speed(
612
+ float(settings.get("rapid_speed", self.service.default_rapid_speed))
613
+ )
614
+ else:
615
+ self.list_jump_speed(self.service.default_rapid_speed)
616
+
617
+ power = (
618
+ float(settings.get("power", self.service.default_power)) / 10.0
619
+ ) # Convert power, out of 1000
620
+ frequency = float(settings.get("frequency", self.service.default_frequency))
621
+ fpk = float(settings.get("fpk", self.service.default_fpk))
622
+ if self.source == "fiber":
623
+ self.power(power)
624
+ self.frequency(frequency)
625
+ elif self.source == "co2":
626
+ self.frequency(frequency)
627
+ self.fpk(fpk)
628
+ self.power(power)
629
+ self.list_mark_speed(float(settings.get("speed", self.service.default_speed)))
630
+
631
+ if str(settings.get("timing_enabled", False)).lower() == "true":
632
+ self.list_laser_on_delay(
633
+ settings.get("delay_laser_on", self.service.delay_laser_on)
634
+ )
635
+ self.list_laser_off_delay(
636
+ settings.get("delay_laser_off", self.service.delay_laser_off)
637
+ )
638
+ self.list_polygon_delay(
639
+ settings.get("delay_laser_polygon", self.service.delay_polygon)
640
+ )
641
+ else:
642
+ # Use globals
643
+ self.list_laser_on_delay(self.service.delay_laser_on)
644
+ self.list_laser_off_delay(self.service.delay_laser_off)
645
+ self.list_polygon_delay(self.service.delay_polygon)
646
+
647
+ #######################
648
+ # PLOTLIKE SHORTCUTS
649
+ #######################
650
+
651
+ def mark(self, x, y):
652
+ if x == self._last_x and y == self._last_y:
653
+ return
654
+ if x > 0xFFFF or x < 0 or y > 0xFFFF or y < 0:
655
+ # Moves to out of range are not performed.
656
+ return
657
+ if self._mark_speed is not None:
658
+ self.list_mark_speed(self._mark_speed)
659
+ self.list_mark(x, y)
660
+
661
+ def goto(self, x, y, long=None, short=None, distance_limit=None):
662
+ if x == self._last_x and y == self._last_y:
663
+ return
664
+ if x > 0xFFFF or x < 0 or y > 0xFFFF or y < 0:
665
+ # Moves to out of range are not performed.
666
+ return
667
+ if self._goto_speed is not None:
668
+ self.list_jump_speed(self._goto_speed)
669
+ self.list_jump(x, y, long=long, short=short, distance_limit=distance_limit)
670
+
671
+ def light(self, x, y, long=None, short=None, distance_limit=None):
672
+ if x == self._last_x and y == self._last_y:
673
+ return
674
+ if x > 0xFFFF or x < 0 or y > 0xFFFF or y < 0:
675
+ # Moves to out of range are not performed.
676
+ return
677
+ if self.light_on():
678
+ self.list_write_port()
679
+ if self._light_speed is not None:
680
+ self.list_jump_speed(self._light_speed)
681
+ self.list_jump(x, y, long=long, short=short, distance_limit=distance_limit)
682
+
683
+ def dark(self, x, y, long=None, short=None, distance_limit=None):
684
+ if x == self._last_x and y == self._last_y:
685
+ return
686
+ if x > 0xFFFF or x < 0 or y > 0xFFFF or y < 0:
687
+ # Moves to out of range are not performed.
688
+ return
689
+ if self.light_off():
690
+ self.list_write_port()
691
+ if self._dark_speed is not None:
692
+ self.list_jump_speed(self._dark_speed)
693
+ self.list_jump(x, y, long=long, short=short, distance_limit=distance_limit)
694
+
695
+ def set_xy(self, x, y):
696
+ distance = int(abs(complex(x, y) - complex(self._last_x, self._last_y)))
697
+ if distance > 0xFFFF:
698
+ distance = 0xFFFF
699
+ self.goto_xy(x, y, distance=distance)
700
+
701
+ def get_last_xy(self):
702
+ return self._last_x, self._last_y
703
+
704
+ #######################
705
+ # Command Shortcuts
706
+ #######################
707
+
708
+ def is_busy(self):
709
+ status = self.status()
710
+ return bool(status & BUSY)
711
+
712
+ def is_ready(self):
713
+ status = self.status()
714
+ return bool(status & READY)
715
+
716
+ def is_axis(self):
717
+ status = self.status()
718
+ return bool(status & AXIS)
719
+
720
+ def is_ready_and_not_busy(self):
721
+ if self.mode == DRIVER_STATE_RAW:
722
+ return True
723
+ status = self.status()
724
+ return bool(status & READY) and not bool(status & BUSY)
725
+
726
+ def wait_finished(self):
727
+ if self.mode == DRIVER_STATE_RAW:
728
+ return
729
+ while not self.is_ready_and_not_busy():
730
+ time.sleep(0.01)
731
+ if self.is_shutdown:
732
+ return
733
+
734
+ def wait_axis(self):
735
+ if self.mode == DRIVER_STATE_RAW:
736
+ return
737
+ while self.is_axis():
738
+ time.sleep(0.01)
739
+ if self.is_shutdown:
740
+ return
741
+
742
+ def wait_ready(self):
743
+ if self.mode == DRIVER_STATE_RAW:
744
+ return
745
+ while not self.is_ready():
746
+ time.sleep(0.01)
747
+ if self.is_shutdown:
748
+ return
749
+
750
+ def wait_idle(self):
751
+ if self.mode == DRIVER_STATE_RAW:
752
+ return
753
+ while self.is_busy():
754
+ time.sleep(0.01)
755
+ if self.is_shutdown:
756
+ return
757
+
758
+ def abort(self, dummy_packet=True):
759
+ if self.mode == DRIVER_STATE_RAW:
760
+ return
761
+ self.stop_execute()
762
+ self.paused = False
763
+ self.set_fiber_mo(0)
764
+ self.reset_list()
765
+ if dummy_packet:
766
+ self._list_new()
767
+ self.list_end_of_list() # Ensure packet is sent on end.
768
+ self._list_end()
769
+ if not self._list_executing:
770
+ self.execute_list()
771
+ self._list_executing = False
772
+ self._number_of_list_packets = 0
773
+ self.set_fiber_mo(0)
774
+ self.port_off(bit=0)
775
+ self.write_port()
776
+ self.mode = DRIVER_STATE_RAPID
777
+
778
+ def pause(self):
779
+ if self.mode == DRIVER_STATE_RAW:
780
+ return
781
+ self.paused = True
782
+ self.stop_list()
783
+
784
+ def resume(self):
785
+ if self.mode == DRIVER_STATE_RAW:
786
+ return
787
+ self.restart_list()
788
+ self.paused = False
789
+
790
+ def init_laser(self):
791
+ if self.mode == DRIVER_STATE_RAW:
792
+ return
793
+ cor_file = self.service.corfile if self.service.corfile_enabled else None
794
+ first_pulse_killer = self.service.first_pulse_killer
795
+ pwm_pulse_width = self.service.pwm_pulse_width
796
+ pwm_half_period = self.service.pwm_half_period
797
+ standby_param_1 = self.service.standby_param_1
798
+ standby_param_2 = self.service.standby_param_2
799
+ timing_mode = self.service.timing_mode
800
+ delay_mode = self.service.delay_mode
801
+ laser_mode = self.service.laser_mode
802
+ control_mode = self.service.control_mode
803
+ fpk2_p1 = self.service.fpk2_p1
804
+ fpk2_p2 = self.service.fpk2_p2
805
+ fpk2_p3 = self.service.fpk2_p3
806
+ fpk2_p4 = self.service.fpk2_p3
807
+ fly_res_p1 = self.service.fly_res_p1
808
+ fly_res_p2 = self.service.fly_res_p2
809
+ fly_res_p3 = self.service.fly_res_p3
810
+ fly_res_p4 = self.service.fly_res_p4
811
+
812
+ self.usb_log("Initializing Laser")
813
+ serial_number = self.get_serial_number()
814
+ content = "0x"
815
+ for nibble in serial_number:
816
+ content += f"{nibble:04x}"
817
+ self.usb_log(f"Serial Number: {serial_number} ({content})")
818
+ if self.service.serial_enable and self.service.serial and not self.serial_confirmed:
819
+ self.usb_log(f"Requires serial number confirmation against {self.service.serial}.")
820
+ if content == self.service.serial:
821
+ self.serial_confirmed = True
822
+
823
+ if not self.serial_confirmed:
824
+ self.disconnect()
825
+ raise ConnectionRefusedError("Serial number confirmation failed.")
826
+ else:
827
+ self.usb_log("Serial number confirmed.")
828
+
829
+ version = self.get_version()
830
+ self.usb_log(f"Version: {version}")
831
+
832
+ self.reset()
833
+ self.usb_log("Reset")
834
+ self.write_correction_file(cor_file)
835
+ self.enable_laser()
836
+ self.usb_log("Laser Enabled")
837
+ self.set_control_mode(control_mode)
838
+ self.usb_log("Control Mode")
839
+ self.set_laser_mode(laser_mode)
840
+ self.usb_log("Laser Mode")
841
+ self.set_delay_mode(delay_mode)
842
+ self.usb_log("Delay Mode")
843
+ self.set_timing(timing_mode)
844
+ self.usb_log("Timing Mode")
845
+ self.set_standby(standby_param_1, standby_param_2)
846
+ self.usb_log("Setting Standby")
847
+ self.set_first_pulse_killer(first_pulse_killer)
848
+ self.usb_log("Set First Pulse Killer")
849
+ self.set_pwm_half_period(pwm_half_period)
850
+ self.usb_log("Set PWM Half-Period")
851
+ self.set_pwm_pulse_width(pwm_pulse_width)
852
+ self.usb_log("Set PWM pulse width")
853
+ self.set_fiber_mo(0) # Close
854
+ self.usb_log("Set Fiber Mo (Closed)")
855
+ self.set_pfk_param_2(fpk2_p1, fpk2_p2, fpk2_p3, fpk2_p4)
856
+ self.usb_log("First Pulse Killer Parameters")
857
+ self.set_fly_res(fly_res_p1, fly_res_p2, fly_res_p3, fly_res_p4)
858
+ self.usb_log("On-The-Fly Res")
859
+ self.enable_z()
860
+ self.usb_log("Z-Enabled")
861
+ self.write_analog_port_1(0x7FF)
862
+ self.usb_log("Analog Port 1")
863
+ self.enable_z()
864
+ self.usb_log("Z-Enabled-part2")
865
+ time.sleep(0.05)
866
+ self.usb_log("Ready")
867
+
868
+ def power(self, power):
869
+ """
870
+ Accepts power in percent, automatically converts to power_ratio
871
+
872
+ @param power:
873
+ @return:
874
+ """
875
+ if self._power == power:
876
+ return
877
+ self._power = power
878
+ if self.source == "co2":
879
+ power_ratio = int(round(200 * power / self._frequency))
880
+ self.list_mark_power_ratio(power_ratio)
881
+ if self.source == "fiber":
882
+ self.list_mark_current(self._convert_power(power))
883
+
884
+ def frequency(self, frequency):
885
+ if self._frequency == frequency:
886
+ return
887
+ self._frequency = frequency
888
+ if self.source == "fiber":
889
+ self.list_qswitch_period(self._convert_frequency(frequency, base=20000.0))
890
+ elif self.source == "co2":
891
+ self.list_mark_frequency(self._convert_frequency(frequency, base=10000.0))
892
+
893
+ def fpk(self, fpk):
894
+ """
895
+ Set First Pulse Killer
896
+ @param fpk: first_pulse_killer value in percent.
897
+ @return:
898
+ """
899
+ if self.source != "co2":
900
+ # FPK only used for CO2 source.
901
+ return
902
+ if self._fpk == fpk or fpk is None:
903
+ return
904
+ self._fpk = fpk
905
+ first_pulse_killer = int(round(2000.0 / self._frequency))
906
+ self.list_set_co2_fpk(first_pulse_killer)
907
+
908
+ def light_on(self):
909
+ if not self.is_port(self._light_bit):
910
+ self.port_on(self._light_bit)
911
+ return True
912
+ return False
913
+
914
+ def light_off(self):
915
+ if self.is_port(self._light_bit):
916
+ self.port_off(self._light_bit)
917
+ return True
918
+ return False
919
+
920
+ def is_port(self, bit):
921
+ return bool((1 << bit) & self._port_bits)
922
+
923
+ def port_on(self, bit):
924
+ self._port_bits = self._port_bits | (1 << bit)
925
+
926
+ def port_off(self, bit):
927
+ self._port_bits = ~((~self._port_bits) | (1 << bit))
928
+
929
+ def port_set(self, mask, values):
930
+ self._port_bits &= ~mask # Unset mask.
931
+ self._port_bits |= values & mask # Set masked bits.
932
+
933
+ #######################
934
+ # UNIT CONVERSIONS
935
+ #######################
936
+
937
+ def _convert_speed(self, speed):
938
+ """
939
+ Speed in the galvo is given in galvos/ms this means mm/s needs to multiply by galvos_per_mm
940
+ and divide by 1000 (s/ms)
941
+
942
+ @param speed:
943
+ @return:
944
+ """
945
+ # return int(speed / 2)
946
+ galvos_per_mm, _ = self.service.view.position("1mm", "1mm", vector=True, margins=False)
947
+ return abs(int(speed * galvos_per_mm / 1000.0))
948
+
949
+ def _convert_frequency(self, frequency_khz, base=20000.0):
950
+ """
951
+ Converts frequency to period.
952
+
953
+ 20000000.0 / frequency in hz
954
+
955
+ @param frequency_khz: Frequency to convert
956
+ @return:
957
+ """
958
+ return int(round(base / frequency_khz)) & 0xFFFF
959
+
960
+ def _convert_power(self, power):
961
+ """
962
+ Converts power percent to int value
963
+ @return:
964
+ """
965
+ return int(round(power * 0xFFF / 100.0))
966
+
967
+ #######################
968
+ # HIGH LEVEL OPERATIONS
969
+ #######################
970
+
971
+ def write_correction_file(self, filename):
972
+ if filename is None:
973
+ self.write_blank_correct_file()
974
+ self.usb_log("Correction file set to blank.")
975
+ return
976
+ try:
977
+ table = self._read_correction_file(filename)
978
+ self._write_correction_table(table)
979
+ self.usb_log("Correction File Sent")
980
+ except OSError:
981
+ self.write_blank_correct_file()
982
+ self.usb_log("Correction file set to blank.")
983
+ return
984
+
985
+ @staticmethod
986
+ def get_scale_from_correction_file(filename):
987
+ with open(filename, "rb") as f:
988
+ label = f.read(0x16)
989
+ if label.decode("utf-16") == "LMC1COR_1.0":
990
+ unk = f.read(2)
991
+ return struct.unpack("63d", f.read(0x1F8))[43]
992
+ else:
993
+ unk = f.read(6)
994
+ return struct.unpack("d", f.read(8))[0]
995
+
996
+ def write_blank_correct_file(self):
997
+ self.write_cor_table(False)
998
+
999
+ def _read_float_correction_file(self, f):
1000
+ """
1001
+ Read table for cor files marked: LMC1COR_1.0
1002
+ @param f:
1003
+ @return:
1004
+ """
1005
+ table = []
1006
+ for j in range(65):
1007
+ for k in range(65):
1008
+ dx = int(round(struct.unpack("d", f.read(8))[0]))
1009
+ dx = dx if dx >= 0 else -dx + 0x8000
1010
+ dy = int(round(struct.unpack("d", f.read(8))[0]))
1011
+ dy = dy if dy >= 0 else -dy + 0x8000
1012
+ table.append([dx & 0xFFFF, dy & 0xFFFF])
1013
+ return table
1014
+
1015
+ def _read_int_correction_file(self, f):
1016
+ table = []
1017
+ for j in range(65):
1018
+ for k in range(65):
1019
+ dx = int.from_bytes(f.read(4), "little", signed=True)
1020
+ dx = dx if dx >= 0 else -dx + 0x8000
1021
+ dy = int.from_bytes(f.read(4), "little", signed=True)
1022
+ dy = dy if dy >= 0 else -dy + 0x8000
1023
+ table.append([dx & 0xFFFF, dy & 0xFFFF])
1024
+ return table
1025
+
1026
+ def _read_correction_file(self, filename):
1027
+ """
1028
+ Reads a standard .cor file and builds a table from that.
1029
+
1030
+ @param filename:
1031
+ @return:
1032
+ """
1033
+ with open(filename, "rb") as f:
1034
+ label = f.read(0x16)
1035
+ if label.decode("utf-16") == "LMC1COR_1.0":
1036
+ header = f.read(0x1FA)
1037
+ return self._read_float_correction_file(f)
1038
+ else:
1039
+ header = f.read(0xE)
1040
+ return self._read_int_correction_file(f)
1041
+
1042
+ def _write_correction_table(self, table):
1043
+ assert len(table) == 65 * 65
1044
+ self.write_cor_table(True)
1045
+ first = True
1046
+ for dx, dy in table:
1047
+ self.write_cor_line(dx, dy, 0 if first else 1)
1048
+ first = False
1049
+
1050
+ #######################
1051
+ # COMMAND LIST COMMAND
1052
+ #######################
1053
+
1054
+ def list_jump(self, x, y, short=None, long=None, distance_limit=None):
1055
+ distance = int(abs(complex(x, y) - complex(self._last_x, self._last_y)))
1056
+ if distance_limit and distance > distance_limit:
1057
+ delay = long
1058
+ else:
1059
+ delay = short
1060
+ if distance > 0xFFFF:
1061
+ distance = 0xFFFF
1062
+ angle = 0
1063
+ if delay:
1064
+ self.list_jump_delay(delay)
1065
+ x = int(x)
1066
+ y = int(y)
1067
+ self._list_write(listJumpTo, x, y, angle, distance)
1068
+ if self._signal_updates:
1069
+ view = self.service.view
1070
+ l_x, l_y = view.iposition(self._last_x, self._last_y)
1071
+ n_x, n_y = view.iposition(x, y)
1072
+ self.service.signal(
1073
+ "driver;position",
1074
+ (l_x, l_y, n_x, n_y),
1075
+ )
1076
+
1077
+ self._last_x = x
1078
+ self._last_y = y
1079
+
1080
+ def list_end_of_list(self):
1081
+ self._list_write(listEndOfList)
1082
+
1083
+ def list_laser_on_point(self, dwell_time):
1084
+ self._list_write(listLaserOnPoint, dwell_time)
1085
+
1086
+ def list_delay_time(self, delay_time):
1087
+ """
1088
+ Delay time in 10 microseconds units
1089
+
1090
+ @param delay_time:
1091
+ @return:
1092
+ """
1093
+ self._list_write(listDelayTime, abs(delay_time))
1094
+
1095
+ def list_mark(self, x, y, angle=0):
1096
+ distance = int(abs(complex(x, y) - complex(self._last_x, self._last_y)))
1097
+ if distance > 0xFFFF:
1098
+ distance = 0xFFFF
1099
+ x = int(x)
1100
+ y = int(y)
1101
+ self._list_write(listMarkTo, x, y, angle, distance)
1102
+
1103
+ if self._signal_updates:
1104
+ view = self.service.view
1105
+ l_x, l_y = view.iposition(self._last_x, self._last_y)
1106
+ n_x, n_y = view.iposition(x, y)
1107
+ self.service.signal(
1108
+ "driver;position",
1109
+ (l_x, l_y, n_x, n_y),
1110
+ )
1111
+
1112
+ self._last_x = x
1113
+ self._last_y = y
1114
+
1115
+ def list_jump_speed(self, speed):
1116
+ if self._travel_speed == speed:
1117
+ return
1118
+ self._travel_speed = speed
1119
+ c_speed = self._convert_speed(speed)
1120
+ if c_speed > 0xFFFF:
1121
+ c_speed = 0xFFFF
1122
+ self._list_write(listJumpSpeed, c_speed)
1123
+
1124
+ def list_laser_on_delay(self, delay):
1125
+ """
1126
+ Set laser on delay in microseconds
1127
+ @param delay:
1128
+ @return:
1129
+ """
1130
+ if self._delay_on == delay:
1131
+ return
1132
+ self._delay_on = delay
1133
+ self._list_write(listLaserOnDelay, abs(delay), 0x0000 if delay > 0 else 0x8000)
1134
+
1135
+ def list_laser_off_delay(self, delay):
1136
+ """
1137
+ Set laser off delay in microseconds
1138
+ @param delay:
1139
+ @return:
1140
+ """
1141
+ if self._delay_off == delay:
1142
+ return
1143
+ self._delay_off = delay
1144
+ self._list_write(listLaserOffDelay, abs(delay), 0x0000 if delay > 0 else 0x8000)
1145
+
1146
+ def list_mark_frequency(self, frequency):
1147
+ """
1148
+ This command is used in some machines but, it's not clear given the amount of reverse engineering how those
1149
+ values are set. This is done for laser_type = 4.
1150
+
1151
+ @param frequency:
1152
+ @return:
1153
+ """
1154
+ self._list_write(listMarkFreq, frequency)
1155
+
1156
+ def list_mark_power_ratio(self, power_ratio):
1157
+ """
1158
+ This command is used in some machines. Laser_type=4 and laser_type=0 (CO2), if 0x800A returned 0.
1159
+
1160
+ @param power_ratio:
1161
+ @return:
1162
+ """
1163
+ # listMarkPowerRatio
1164
+ self._list_write(listMarkPowerRatio, power_ratio)
1165
+
1166
+ def list_mark_speed(self, speed):
1167
+ """
1168
+ Sets the marking speed for the laser.
1169
+
1170
+ @param speed:
1171
+ @return:
1172
+ """
1173
+ if self._speed == speed:
1174
+ return
1175
+ self._speed = speed
1176
+ c_speed = self._convert_speed(speed)
1177
+ if c_speed > 0xFFFF:
1178
+ c_speed = 0xFFFF
1179
+ self._list_write(listMarkSpeed, c_speed)
1180
+
1181
+ def list_jump_delay(self, delay):
1182
+ """
1183
+ Set laser jump delay in microseconds
1184
+ @param delay:
1185
+ @return:
1186
+ """
1187
+ if self._delay_jump == delay:
1188
+ return
1189
+ self._delay_jump = delay
1190
+ self._list_write(listJumpDelay, abs(delay), 0x0000 if delay > 0 else 0x8000)
1191
+
1192
+ def list_polygon_delay(self, delay):
1193
+ """
1194
+ Set polygon delay in microseconds
1195
+ @param delay:
1196
+ @return:
1197
+ """
1198
+ if self._delay_poly == delay:
1199
+ return
1200
+ self._delay_poly = delay
1201
+ self._list_write(listPolygonDelay, abs(delay), 0x0000 if delay > 0 else 0x8000)
1202
+
1203
+ def list_write_port(self):
1204
+ """
1205
+ Writes the set port values to the list.
1206
+
1207
+ @return:
1208
+ """
1209
+ self._list_write(listWritePort, self._port_bits)
1210
+
1211
+ def list_mark_current(self, current):
1212
+ """
1213
+ Also called as part of setting the power ratio. This is not correctly understood.
1214
+ @param current:
1215
+ @return:
1216
+ """
1217
+ # listMarkCurrent
1218
+ self._list_write(listMarkCurrent, current)
1219
+
1220
+ def list_mark_frequency_2(self, frequency):
1221
+ """
1222
+ Also called as part of setting frequency and is not correctly understood.
1223
+
1224
+ @param frequency:
1225
+ @return:
1226
+ """
1227
+ # listMarkFreq2
1228
+ raise NotImplementedError
1229
+
1230
+ def list_fly_enable(self, enabled=1):
1231
+ """
1232
+ On-The-Fly control enable/disable within list.
1233
+
1234
+ @param enabled:
1235
+ @return:
1236
+ """
1237
+ self._list_write(listFlyEnable, enabled)
1238
+
1239
+ def list_qswitch_period(self, qswitch):
1240
+ """
1241
+ Sets the qswitch period, which in is the inversely related to frequency.
1242
+
1243
+ @param qswitch:
1244
+ @return:
1245
+ """
1246
+ self._list_write(listQSwitchPeriod, qswitch)
1247
+
1248
+ def list_direct_laser_switch(self):
1249
+ """
1250
+ This is not understood.
1251
+ @return:
1252
+ """
1253
+ # ListDirectLaserSwitch
1254
+ raise NotImplementedError
1255
+
1256
+ def list_fly_delay(self, delay):
1257
+ """
1258
+ On-the-fly control.
1259
+
1260
+ @param delay:
1261
+ @return:
1262
+ """
1263
+ self._list_write(listFlyDelay, abs(delay), 0x0000 if delay > 0 else 0x8000)
1264
+
1265
+ def list_set_co2_fpk(self, fpk1, fpk2=None):
1266
+ """
1267
+ Set the CO2 Laser, First Pulse Killer.
1268
+
1269
+ @return:
1270
+ """
1271
+ if fpk2 is None:
1272
+ fpk2 = fpk1
1273
+ self._list_write(listSetCo2FPK, fpk1, fpk2)
1274
+
1275
+ def list_fly_wait_input(self):
1276
+ """
1277
+ Sets the On-the-fly to wait for input.
1278
+ @return:
1279
+ """
1280
+ self._list_write(listFlyWaitInput)
1281
+
1282
+ def list_fiber_open_mo(self, open_mo):
1283
+ """
1284
+ Sets motion operations, without MO set the laser does not automatically fire while moving.
1285
+
1286
+ @param open_mo:
1287
+ @return:
1288
+ """
1289
+ self._list_write(listFiberOpenMO, open_mo)
1290
+
1291
+ def list_wait_for_input(self, wait_mask, wait_level):
1292
+ """
1293
+ Unknown.
1294
+
1295
+ @return:
1296
+ """
1297
+ self._list_write(listWaitForInput, wait_mask, wait_level)
1298
+
1299
+ def list_change_mark_count(self, count):
1300
+ """
1301
+ Unknown.
1302
+
1303
+ @param count:
1304
+ @return:
1305
+ """
1306
+ self._list_write(listChangeMarkCount, count)
1307
+
1308
+ def list_set_weld_power_wave(self, weld_power_wave):
1309
+ """
1310
+ Unknown.
1311
+
1312
+ @param weld_power_wave:
1313
+ @return:
1314
+ """
1315
+ self._list_write(listSetWeldPowerWave, weld_power_wave)
1316
+
1317
+ def list_enable_weld_power_wave(self, enabled):
1318
+ """
1319
+ Unknown.
1320
+
1321
+ @param enabled:
1322
+ @return:
1323
+ """
1324
+ self._list_write(listEnableWeldPowerWave, enabled)
1325
+
1326
+ def list_fiber_ylpm_pulse_width(self, pulse_width):
1327
+ """
1328
+ Unknown.
1329
+
1330
+ @param pulse_width:
1331
+ @return:
1332
+ """
1333
+ if self._pulse_width == pulse_width:
1334
+ return
1335
+ self._pulse_width = pulse_width
1336
+ self._list_write(listFiberYLPMPulseWidth, pulse_width)
1337
+
1338
+ def list_fly_encoder_count(self, count):
1339
+ """
1340
+ Unknown.
1341
+
1342
+ @param count:
1343
+ @return:
1344
+ """
1345
+ self._list_write(listFlyEncoderCount, count)
1346
+
1347
+ def list_set_da_z_word(self, word):
1348
+ """
1349
+ Unknown.
1350
+
1351
+ @param word:
1352
+ @return:
1353
+ """
1354
+ self._list_write(listSetDaZWord, word)
1355
+
1356
+ def list_jpt_set_param(self, param):
1357
+ """
1358
+ Unknown.
1359
+
1360
+ @param param:
1361
+ @return:
1362
+ """
1363
+ self._list_write(listJptSetParam, param)
1364
+
1365
+ def list_ready(self):
1366
+ """
1367
+ Seen at the start of any new command list.
1368
+
1369
+ @return:
1370
+ """
1371
+ self._list_write(listReadyMark)
1372
+
1373
+ #######################
1374
+ # COMMAND LIST SHORTCUTS
1375
+ #######################
1376
+
1377
+ def disable_laser(self):
1378
+ return self._command(DisableLaser)
1379
+
1380
+ def enable_laser(self):
1381
+ return self._command(EnableLaser)
1382
+
1383
+ def execute_list(self):
1384
+ return self._command(ExecuteList)
1385
+
1386
+ def set_pwm_pulse_width(self, pulse_width):
1387
+ return self._command(SetPwmPulseWidth, pulse_width)
1388
+
1389
+ def get_version(self):
1390
+ return self._command(GetVersion)
1391
+
1392
+ def get_serial_number(self):
1393
+ if self.serial_number_found is None:
1394
+ self.serial_number_found = self._command(GetSerialNo)
1395
+ return self.serial_number_found
1396
+
1397
+ def get_list_status(self):
1398
+ return self._command(GetListStatus)
1399
+
1400
+ def get_position_xy(self):
1401
+ return self._command(GetPositionXY)
1402
+
1403
+ def goto_xy(self, x, y, angle=0, distance=0):
1404
+ self._last_x = x
1405
+ self._last_y = y
1406
+ return self._command(GotoXY, int(x), int(y), int(angle), int(distance))
1407
+
1408
+ def laser_signal_off(self):
1409
+ return self._command(LaserSignalOff)
1410
+
1411
+ def laser_signal_on(self):
1412
+ return self._command(LaserSignalOn)
1413
+
1414
+ def write_cor_line(self, dx, dy, non_first):
1415
+ self._command(WriteCorLine, dx, dy, non_first, read=False)
1416
+
1417
+ def reset_list(self):
1418
+ return self._command(ResetList)
1419
+
1420
+ def restart_list(self):
1421
+ return self._command(RestartList)
1422
+
1423
+ def write_cor_table(self, table: bool = True):
1424
+ return self._command(WriteCorTable, int(table))
1425
+
1426
+ def set_control_mode(self, mode):
1427
+ return self._command(SetControlMode, mode)
1428
+
1429
+ def set_delay_mode(self, mode):
1430
+ return self._command(SetDelayMode, mode)
1431
+
1432
+ def set_max_poly_delay(self, delay):
1433
+ return self._command(
1434
+ SetMaxPolyDelay, abs(delay), 0x0000 if delay > 0 else 0x8000
1435
+ )
1436
+
1437
+ def set_end_of_list(self, end):
1438
+ return self._command(SetEndOfList, end)
1439
+
1440
+ def set_first_pulse_killer(self, fpk):
1441
+ return self._command(SetFirstPulseKiller, fpk)
1442
+
1443
+ def set_laser_mode(self, mode):
1444
+ return self._command(SetLaserMode, mode)
1445
+
1446
+ def set_timing(self, timing):
1447
+ return self._command(SetTiming, timing)
1448
+
1449
+ def set_standby(self, standby1, standby2):
1450
+ return self._command(SetStandby, standby1, standby2)
1451
+
1452
+ def set_pwm_half_period(self, pwm_half_period):
1453
+ return self._command(SetPwmHalfPeriod, pwm_half_period)
1454
+
1455
+ def stop_execute(self):
1456
+ return self._command(StopExecute)
1457
+
1458
+ def stop_list(self):
1459
+ return self._command(StopList)
1460
+
1461
+ def write_port(self):
1462
+ return self._command(WritePort, self._port_bits)
1463
+
1464
+ def write_analog_port_1(self, port):
1465
+ return self._command(WriteAnalogPort1, port)
1466
+
1467
+ def write_analog_port_2(self, port):
1468
+ return self._command(WriteAnalogPort2, port)
1469
+
1470
+ def write_analog_port_x(self, port):
1471
+ return self._command(WriteAnalogPortX, port)
1472
+
1473
+ def read_port(self):
1474
+ return self._command(ReadPort)
1475
+
1476
+ def set_axis_motion_param(self, *param):
1477
+ return self._command(SetAxisMotionParam, *param)
1478
+
1479
+ def set_axis_origin_param(self, *param):
1480
+ return self._command(SetAxisOriginParam, *param)
1481
+
1482
+ def axis_go_origin(self):
1483
+ return self._command(AxisGoOrigin)
1484
+
1485
+ def move_axis_to(self, position, invert):
1486
+ return self._command(MoveAxisTo, position, invert)
1487
+
1488
+ def get_axis_pos(self, index=0):
1489
+ return self._command(GetAxisPos, index)
1490
+
1491
+ def get_fly_wait_count(self):
1492
+ return self._command(GetFlyWaitCount)
1493
+
1494
+ def get_mark_count(self):
1495
+ return self._command(GetMarkCount)
1496
+
1497
+ def set_pfk_param_2(self, param1, param2, param3, param4):
1498
+ return self._command(SetFpkParam2, param1, param2, param3, param4)
1499
+
1500
+ def set_fiber_mo(self, mo):
1501
+ """
1502
+ mo == 0 close
1503
+ mo == 1 open
1504
+
1505
+ @param mo:
1506
+ @return:
1507
+ """
1508
+ return self._command(Fiber_SetMo, mo)
1509
+
1510
+ def get_fiber_st_mo_ap(self):
1511
+ return self._command(Fiber_GetStMO_AP)
1512
+
1513
+ def enable_z(self):
1514
+ return self._command(EnableZ)
1515
+
1516
+ def disable_z(self):
1517
+ return self._command(DisableZ)
1518
+
1519
+ def set_z_data(self, zdata):
1520
+ return self._command(SetZData, zdata)
1521
+
1522
+ def set_spi_simmer_current(self, current):
1523
+ return self._command(SetSPISimmerCurrent, current)
1524
+
1525
+ def set_fpk_param(self, param):
1526
+ return self._command(SetFpkParam, param)
1527
+
1528
+ def reset(self):
1529
+ return self._command(Reset)
1530
+
1531
+ def get_fly_speed(self):
1532
+ return self._command(GetFlySpeed)
1533
+
1534
+ def fiber_pulse_width(self):
1535
+ return self._command(FiberPulseWidth)
1536
+
1537
+ def get_fiber_config_extend(self):
1538
+ return self._command(FiberGetConfigExtend)
1539
+
1540
+ def input_port(self, port):
1541
+ return self._command(InputPort, port)
1542
+
1543
+ def clear_lock_input_port(self):
1544
+ return self._command(InputPort, 0x04)
1545
+
1546
+ def enable_lock_input_port(self):
1547
+ return self._command(InputPort, 0x02)
1548
+
1549
+ def disable_lock_input_port(self):
1550
+ return self._command(InputPort, 0x01)
1551
+
1552
+ def get_input_port(self):
1553
+ return self._command(InputPort)
1554
+
1555
+ def get_mark_time(self):
1556
+ """
1557
+ Get Mark Time is always called with data 3. With 0 it returns 0. It is unknown what the payload means.
1558
+ @return:
1559
+ """
1560
+ return self._command(GetMarkTime, 3)
1561
+
1562
+ def get_user_data(self):
1563
+ return self._command(GetUserData)
1564
+
1565
+ def set_fly_res(self, fly_res1, fly_res2, fly_res3, fly_res4):
1566
+ return self._command(SetFlyRes, fly_res1, fly_res2, fly_res3, fly_res4)