From 5692f4bb08df246253372833e5c0cd08fd0d429f Mon Sep 17 00:00:00 2001 From: jondale Date: Thu, 22 Jan 2026 09:55:57 -0500 Subject: [PATCH] force new release --- extensions/km-plot/.gitignore | 19 - extensions/km-plot/.upstream_branch | 1 - extensions/km-plot/.upstream_commit | 1 - extensions/km-plot/.upstream_url | 1 - extensions/km-plot/LICENSE | 622 -------- extensions/km-plot/README.md | 25 - extensions/km-plot/deps/serial/__init__.py | 91 -- extensions/km-plot/deps/serial/__main__.py | 3 - extensions/km-plot/deps/serial/rfc2217.py | 1351 ----------------- extensions/km-plot/deps/serial/rs485.py | 94 -- extensions/km-plot/deps/serial/serialcli.py | 253 --- extensions/km-plot/deps/serial/serialjava.py | 251 --- extensions/km-plot/deps/serial/serialposix.py | 900 ----------- extensions/km-plot/deps/serial/serialutil.py | 697 --------- extensions/km-plot/deps/serial/serialwin32.py | 477 ------ .../km-plot/deps/serial/threaded/__init__.py | 297 ---- .../km-plot/deps/serial/tools/__init__.py | 0 .../deps/serial/tools/hexlify_codec.py | 126 -- .../km-plot/deps/serial/tools/list_ports.py | 110 -- .../deps/serial/tools/list_ports_common.py | 121 -- .../deps/serial/tools/list_ports_linux.py | 109 -- .../deps/serial/tools/list_ports_osx.py | 299 ---- .../deps/serial/tools/list_ports_posix.py | 119 -- .../deps/serial/tools/list_ports_windows.py | 427 ------ .../km-plot/deps/serial/tools/miniterm.py | 1042 ------------- .../deps/serial/urlhandler/__init__.py | 0 .../deps/serial/urlhandler/protocol_alt.py | 57 - .../deps/serial/urlhandler/protocol_cp2110.py | 258 ---- .../deps/serial/urlhandler/protocol_hwgrep.py | 91 -- .../deps/serial/urlhandler/protocol_loop.py | 308 ---- .../serial/urlhandler/protocol_rfc2217.py | 12 - .../deps/serial/urlhandler/protocol_socket.py | 359 ----- .../deps/serial/urlhandler/protocol_spy.py | 290 ---- extensions/km-plot/deps/serial/win32.py | 366 ----- extensions/km-plot/docs/km-plot.gif | Bin 339544 -> 0 bytes extensions/km-plot/gui.py | 471 ------ extensions/km-plot/icons/noport.png | Bin 72957 -> 0 bytes extensions/km-plot/icons/unknown.png | Bin 63055 -> 0 bytes extensions/km-plot/icons/vinyl1.png | Bin 29887 -> 0 bytes extensions/km-plot/icons/vinyl2.png | Bin 31163 -> 0 bytes extensions/km-plot/kmplot.inx | 16 - extensions/km-plot/kmplot.py | 177 --- extensions/km-plot/plot.py | 150 -- extensions/km-plot/plotters.py | 10 - 44 files changed, 10001 deletions(-) delete mode 100644 extensions/km-plot/.gitignore delete mode 100644 extensions/km-plot/.upstream_branch delete mode 100644 extensions/km-plot/.upstream_commit delete mode 100644 extensions/km-plot/.upstream_url delete mode 100644 extensions/km-plot/LICENSE delete mode 100644 extensions/km-plot/README.md delete mode 100644 extensions/km-plot/deps/serial/__init__.py delete mode 100644 extensions/km-plot/deps/serial/__main__.py delete mode 100644 extensions/km-plot/deps/serial/rfc2217.py delete mode 100644 extensions/km-plot/deps/serial/rs485.py delete mode 100644 extensions/km-plot/deps/serial/serialcli.py delete mode 100644 extensions/km-plot/deps/serial/serialjava.py delete mode 100644 extensions/km-plot/deps/serial/serialposix.py delete mode 100644 extensions/km-plot/deps/serial/serialutil.py delete mode 100644 extensions/km-plot/deps/serial/serialwin32.py delete mode 100644 extensions/km-plot/deps/serial/threaded/__init__.py delete mode 100644 extensions/km-plot/deps/serial/tools/__init__.py delete mode 100644 extensions/km-plot/deps/serial/tools/hexlify_codec.py delete mode 100644 extensions/km-plot/deps/serial/tools/list_ports.py delete mode 100644 extensions/km-plot/deps/serial/tools/list_ports_common.py delete mode 100644 extensions/km-plot/deps/serial/tools/list_ports_linux.py delete mode 100644 extensions/km-plot/deps/serial/tools/list_ports_osx.py delete mode 100644 extensions/km-plot/deps/serial/tools/list_ports_posix.py delete mode 100644 extensions/km-plot/deps/serial/tools/list_ports_windows.py delete mode 100644 extensions/km-plot/deps/serial/tools/miniterm.py delete mode 100644 extensions/km-plot/deps/serial/urlhandler/__init__.py delete mode 100644 extensions/km-plot/deps/serial/urlhandler/protocol_alt.py delete mode 100644 extensions/km-plot/deps/serial/urlhandler/protocol_cp2110.py delete mode 100644 extensions/km-plot/deps/serial/urlhandler/protocol_hwgrep.py delete mode 100644 extensions/km-plot/deps/serial/urlhandler/protocol_loop.py delete mode 100644 extensions/km-plot/deps/serial/urlhandler/protocol_rfc2217.py delete mode 100644 extensions/km-plot/deps/serial/urlhandler/protocol_socket.py delete mode 100644 extensions/km-plot/deps/serial/urlhandler/protocol_spy.py delete mode 100644 extensions/km-plot/deps/serial/win32.py delete mode 100644 extensions/km-plot/docs/km-plot.gif delete mode 100644 extensions/km-plot/gui.py delete mode 100644 extensions/km-plot/icons/noport.png delete mode 100644 extensions/km-plot/icons/unknown.png delete mode 100644 extensions/km-plot/icons/vinyl1.png delete mode 100644 extensions/km-plot/icons/vinyl2.png delete mode 100644 extensions/km-plot/kmplot.inx delete mode 100644 extensions/km-plot/kmplot.py delete mode 100644 extensions/km-plot/plot.py delete mode 100644 extensions/km-plot/plotters.py diff --git a/extensions/km-plot/.gitignore b/extensions/km-plot/.gitignore deleted file mode 100644 index bf388fd..0000000 --- a/extensions/km-plot/.gitignore +++ /dev/null @@ -1,19 +0,0 @@ -# Byte-compiled / cache files -__pycache__/ -*.py[cod] -*$py.class - -# Virtual environments -.venv/ -env/ -venv/ - -# Editor / OS files -.DS_Store -.idea/ -.vscode/ - -# Python packaging artifacts -build/ -dist/ -*.egg-info/ diff --git a/extensions/km-plot/.upstream_branch b/extensions/km-plot/.upstream_branch deleted file mode 100644 index ba2906d..0000000 --- a/extensions/km-plot/.upstream_branch +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/extensions/km-plot/.upstream_commit b/extensions/km-plot/.upstream_commit deleted file mode 100644 index 52b2272..0000000 --- a/extensions/km-plot/.upstream_commit +++ /dev/null @@ -1 +0,0 @@ -b6ebf0b1366ab7e6f68d81e4a30278c015049726 diff --git a/extensions/km-plot/.upstream_url b/extensions/km-plot/.upstream_url deleted file mode 100644 index dc50718..0000000 --- a/extensions/km-plot/.upstream_url +++ /dev/null @@ -1 +0,0 @@ -https://git.knoxmakers.org/KnoxMakers/km-plot.git diff --git a/extensions/km-plot/LICENSE b/extensions/km-plot/LICENSE deleted file mode 100644 index 995203f..0000000 --- a/extensions/km-plot/LICENSE +++ /dev/null @@ -1,622 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the Corresponding - Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for -incorporation into a dwelling. In determining whether a product is a -consumer product, doubtful cases shall be resolved in favor of -coverage. For a particular product received by a particular user, -"normally used" refers to a typical or common use of that class of -product, regardless of the status of the particular user or of the way -in which the particular user actually uses, or expects or is expected -to use, the product. A product is a consumer product regardless of -whether the product has substantial commercial, industrial or -non-consumer uses, unless such uses represent the only significant mode -of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to -install and execute modified versions of a covered work in that User -Product from a modified version of its Corresponding Source. The -information must suffice to ensure that the continued functioning of -the modified object code is in no case prevented or interfered with -solely because modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS diff --git a/extensions/km-plot/README.md b/extensions/km-plot/README.md deleted file mode 100644 index f78991a..0000000 --- a/extensions/km-plot/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# KM Plot - -Inkscape extension for Knox Makers to drive HPGL based vinyl/plotter devices over serial. Largely based on the built-in Export > Plot extension for Inkscape but with a GTK interface and Serial Port detection. - -https://git.knoxmakers.org/KnoxMakers/km-plot - - -## Manual Installation - -1) Create a km-plot/ sub-directory in your Inkscape extensions directory: - - Linux: `~/.config/inkscape/extensions/` - - Flatpak: `~/.var/app/org.inkscape.Inkscape/config/inkscape/extensions/` - - Snap: `~/snap/inkscape/current/.config/inkscape/extensions/` - - macOS (Inkscape app bundle): `~/Library/Application Support/org.inkscape.Inkscape/config/inkscape/extensions/` - - Windows: `%APPDATA%\Inkscape\extensions\` - -2) Copy the files from this repo into that km-plot directory - -3) Restart Inkscape, then find the extension under **Extensions > Knox Makers > Vinyl Cutter > Plot**. - -4) Connect your plotter via USB/serial; select the detected port in the Device tab, adjust settings as needed, and click **Send to plotter**. - -## Demo - -![KM Plot demo](docs/km-plot.gif) diff --git a/extensions/km-plot/deps/serial/__init__.py b/extensions/km-plot/deps/serial/__init__.py deleted file mode 100644 index caa4de1..0000000 --- a/extensions/km-plot/deps/serial/__init__.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python -# -# This is a wrapper module for different platform implementations -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2020 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -from __future__ import absolute_import - -import sys -import importlib - -from serial.serialutil import * -#~ SerialBase, SerialException, to_bytes, iterbytes - -__version__ = '3.5' - -VERSION = __version__ - -# pylint: disable=wrong-import-position -if sys.platform == 'cli': - from serial.serialcli import Serial -else: - import os - # chose an implementation, depending on os - if os.name == 'nt': # sys.platform == 'win32': - from serial.serialwin32 import Serial - elif os.name == 'posix': - from serial.serialposix import Serial, PosixPollSerial, VTIMESerial # noqa - elif os.name == 'java': - from serial.serialjava import Serial - else: - raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name)) - - -protocol_handler_packages = [ - 'serial.urlhandler', -] - - -def serial_for_url(url, *args, **kwargs): - """\ - Get an instance of the Serial class, depending on port/url. The port is not - opened when the keyword parameter 'do_not_open' is true, by default it - is. All other parameters are directly passed to the __init__ method when - the port is instantiated. - - The list of package names that is searched for protocol handlers is kept in - ``protocol_handler_packages``. - - e.g. we want to support a URL ``foobar://``. A module - ``my_handlers.protocol_foobar`` is provided by the user. Then - ``protocol_handler_packages.append("my_handlers")`` would extend the search - path so that ``serial_for_url("foobar://"))`` would work. - """ - # check and remove extra parameter to not confuse the Serial class - do_open = not kwargs.pop('do_not_open', False) - # the default is to use the native implementation - klass = Serial - try: - url_lowercase = url.lower() - except AttributeError: - # it's not a string, use default - pass - else: - # if it is an URL, try to import the handler module from the list of possible packages - if '://' in url_lowercase: - protocol = url_lowercase.split('://', 1)[0] - module_name = '.protocol_{}'.format(protocol) - for package_name in protocol_handler_packages: - try: - importlib.import_module(package_name) - handler_module = importlib.import_module(module_name, package_name) - except ImportError: - continue - else: - if hasattr(handler_module, 'serial_class_for_url'): - url, klass = handler_module.serial_class_for_url(url) - else: - klass = handler_module.Serial - break - else: - raise ValueError('invalid URL, protocol {!r} not known'.format(protocol)) - # instantiate and open when desired - instance = klass(None, *args, **kwargs) - instance.port = url - if do_open: - instance.open() - return instance diff --git a/extensions/km-plot/deps/serial/__main__.py b/extensions/km-plot/deps/serial/__main__.py deleted file mode 100644 index bd0a2e6..0000000 --- a/extensions/km-plot/deps/serial/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .tools import miniterm - -miniterm.main() diff --git a/extensions/km-plot/deps/serial/rfc2217.py b/extensions/km-plot/deps/serial/rfc2217.py deleted file mode 100644 index 2ae188e..0000000 --- a/extensions/km-plot/deps/serial/rfc2217.py +++ /dev/null @@ -1,1351 +0,0 @@ -#! python -# -# This module implements a RFC2217 compatible client. RF2217 descibes a -# protocol to access serial ports over TCP/IP and allows setting the baud rate, -# modem control lines etc. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -# TODO: -# - setting control line -> answer is not checked (had problems with one of the -# severs). consider implementing a compatibility mode flag to make check -# conditional -# - write timeout not implemented at all - -# ########################################################################### -# observations and issues with servers -# =========================================================================== -# sredird V2.2.1 -# - http://www.ibiblio.org/pub/Linux/system/serial/ sredird-2.2.2.tar.gz -# - does not acknowledge SET_CONTROL (RTS/DTR) correctly, always responding -# [105 1] instead of the actual value. -# - SET_BAUDRATE answer contains 4 extra null bytes -> probably for larger -# numbers than 2**32? -# - To get the signature [COM_PORT_OPTION 0] has to be sent. -# - run a server: while true; do nc -l -p 7000 -c "sredird debug /dev/ttyUSB0 /var/lock/sredir"; done -# =========================================================================== -# telnetcpcd (untested) -# - http://ftp.wayne.edu/kermit/sredird/telnetcpcd-1.09.tar.gz -# - To get the signature [COM_PORT_OPTION] w/o data has to be sent. -# =========================================================================== -# ser2net -# - does not negotiate BINARY or COM_PORT_OPTION for his side but at least -# acknowledges that the client activates these options -# - The configuration may be that the server prints a banner. As this client -# implementation does a flushInput on connect, this banner is hidden from -# the user application. -# - NOTIFY_MODEMSTATE: the poll interval of the server seems to be one -# second. -# - To get the signature [COM_PORT_OPTION 0] has to be sent. -# - run a server: run ser2net daemon, in /etc/ser2net.conf: -# 2000:telnet:0:/dev/ttyS0:9600 remctl banner -# ########################################################################### - -# How to identify ports? pySerial might want to support other protocols in the -# future, so lets use an URL scheme. -# for RFC2217 compliant servers we will use this: -# rfc2217://:[?option[&option...]] -# -# options: -# - "logging" set log level print diagnostic messages (e.g. "logging=debug") -# - "ign_set_control": do not look at the answers to SET_CONTROL -# - "poll_modem": issue NOTIFY_MODEMSTATE requests when CTS/DTR/RI/CD is read. -# Without this option it expects that the server sends notifications -# automatically on change (which most servers do and is according to the -# RFC). -# the order of the options is not relevant - -from __future__ import absolute_import - -import logging -import socket -import struct -import threading -import time -try: - import urlparse -except ImportError: - import urllib.parse as urlparse -try: - import Queue -except ImportError: - import queue as Queue - -import serial -from serial.serialutil import SerialBase, SerialException, to_bytes, \ - iterbytes, PortNotOpenError, Timeout - -# port string is expected to be something like this: -# rfc2217://host:port -# host may be an IP or including domain, whatever. -# port is 0...65535 - -# map log level names to constants. used in from_url() -LOGGER_LEVELS = { - 'debug': logging.DEBUG, - 'info': logging.INFO, - 'warning': logging.WARNING, - 'error': logging.ERROR, -} - - -# telnet protocol characters -SE = b'\xf0' # Subnegotiation End -NOP = b'\xf1' # No Operation -DM = b'\xf2' # Data Mark -BRK = b'\xf3' # Break -IP = b'\xf4' # Interrupt process -AO = b'\xf5' # Abort output -AYT = b'\xf6' # Are You There -EC = b'\xf7' # Erase Character -EL = b'\xf8' # Erase Line -GA = b'\xf9' # Go Ahead -SB = b'\xfa' # Subnegotiation Begin -WILL = b'\xfb' -WONT = b'\xfc' -DO = b'\xfd' -DONT = b'\xfe' -IAC = b'\xff' # Interpret As Command -IAC_DOUBLED = b'\xff\xff' - -# selected telnet options -BINARY = b'\x00' # 8-bit data path -ECHO = b'\x01' # echo -SGA = b'\x03' # suppress go ahead - -# RFC2217 -COM_PORT_OPTION = b'\x2c' - -# Client to Access Server -SET_BAUDRATE = b'\x01' -SET_DATASIZE = b'\x02' -SET_PARITY = b'\x03' -SET_STOPSIZE = b'\x04' -SET_CONTROL = b'\x05' -NOTIFY_LINESTATE = b'\x06' -NOTIFY_MODEMSTATE = b'\x07' -FLOWCONTROL_SUSPEND = b'\x08' -FLOWCONTROL_RESUME = b'\x09' -SET_LINESTATE_MASK = b'\x0a' -SET_MODEMSTATE_MASK = b'\x0b' -PURGE_DATA = b'\x0c' - -SERVER_SET_BAUDRATE = b'\x65' -SERVER_SET_DATASIZE = b'\x66' -SERVER_SET_PARITY = b'\x67' -SERVER_SET_STOPSIZE = b'\x68' -SERVER_SET_CONTROL = b'\x69' -SERVER_NOTIFY_LINESTATE = b'\x6a' -SERVER_NOTIFY_MODEMSTATE = b'\x6b' -SERVER_FLOWCONTROL_SUSPEND = b'\x6c' -SERVER_FLOWCONTROL_RESUME = b'\x6d' -SERVER_SET_LINESTATE_MASK = b'\x6e' -SERVER_SET_MODEMSTATE_MASK = b'\x6f' -SERVER_PURGE_DATA = b'\x70' - -RFC2217_ANSWER_MAP = { - SET_BAUDRATE: SERVER_SET_BAUDRATE, - SET_DATASIZE: SERVER_SET_DATASIZE, - SET_PARITY: SERVER_SET_PARITY, - SET_STOPSIZE: SERVER_SET_STOPSIZE, - SET_CONTROL: SERVER_SET_CONTROL, - NOTIFY_LINESTATE: SERVER_NOTIFY_LINESTATE, - NOTIFY_MODEMSTATE: SERVER_NOTIFY_MODEMSTATE, - FLOWCONTROL_SUSPEND: SERVER_FLOWCONTROL_SUSPEND, - FLOWCONTROL_RESUME: SERVER_FLOWCONTROL_RESUME, - SET_LINESTATE_MASK: SERVER_SET_LINESTATE_MASK, - SET_MODEMSTATE_MASK: SERVER_SET_MODEMSTATE_MASK, - PURGE_DATA: SERVER_PURGE_DATA, -} - -SET_CONTROL_REQ_FLOW_SETTING = b'\x00' # Request Com Port Flow Control Setting (outbound/both) -SET_CONTROL_USE_NO_FLOW_CONTROL = b'\x01' # Use No Flow Control (outbound/both) -SET_CONTROL_USE_SW_FLOW_CONTROL = b'\x02' # Use XON/XOFF Flow Control (outbound/both) -SET_CONTROL_USE_HW_FLOW_CONTROL = b'\x03' # Use HARDWARE Flow Control (outbound/both) -SET_CONTROL_REQ_BREAK_STATE = b'\x04' # Request BREAK State -SET_CONTROL_BREAK_ON = b'\x05' # Set BREAK State ON -SET_CONTROL_BREAK_OFF = b'\x06' # Set BREAK State OFF -SET_CONTROL_REQ_DTR = b'\x07' # Request DTR Signal State -SET_CONTROL_DTR_ON = b'\x08' # Set DTR Signal State ON -SET_CONTROL_DTR_OFF = b'\x09' # Set DTR Signal State OFF -SET_CONTROL_REQ_RTS = b'\x0a' # Request RTS Signal State -SET_CONTROL_RTS_ON = b'\x0b' # Set RTS Signal State ON -SET_CONTROL_RTS_OFF = b'\x0c' # Set RTS Signal State OFF -SET_CONTROL_REQ_FLOW_SETTING_IN = b'\x0d' # Request Com Port Flow Control Setting (inbound) -SET_CONTROL_USE_NO_FLOW_CONTROL_IN = b'\x0e' # Use No Flow Control (inbound) -SET_CONTROL_USE_SW_FLOW_CONTOL_IN = b'\x0f' # Use XON/XOFF Flow Control (inbound) -SET_CONTROL_USE_HW_FLOW_CONTOL_IN = b'\x10' # Use HARDWARE Flow Control (inbound) -SET_CONTROL_USE_DCD_FLOW_CONTROL = b'\x11' # Use DCD Flow Control (outbound/both) -SET_CONTROL_USE_DTR_FLOW_CONTROL = b'\x12' # Use DTR Flow Control (inbound) -SET_CONTROL_USE_DSR_FLOW_CONTROL = b'\x13' # Use DSR Flow Control (outbound/both) - -LINESTATE_MASK_TIMEOUT = 128 # Time-out Error -LINESTATE_MASK_SHIFTREG_EMPTY = 64 # Transfer Shift Register Empty -LINESTATE_MASK_TRANSREG_EMPTY = 32 # Transfer Holding Register Empty -LINESTATE_MASK_BREAK_DETECT = 16 # Break-detect Error -LINESTATE_MASK_FRAMING_ERROR = 8 # Framing Error -LINESTATE_MASK_PARTIY_ERROR = 4 # Parity Error -LINESTATE_MASK_OVERRUN_ERROR = 2 # Overrun Error -LINESTATE_MASK_DATA_READY = 1 # Data Ready - -MODEMSTATE_MASK_CD = 128 # Receive Line Signal Detect (also known as Carrier Detect) -MODEMSTATE_MASK_RI = 64 # Ring Indicator -MODEMSTATE_MASK_DSR = 32 # Data-Set-Ready Signal State -MODEMSTATE_MASK_CTS = 16 # Clear-To-Send Signal State -MODEMSTATE_MASK_CD_CHANGE = 8 # Delta Receive Line Signal Detect -MODEMSTATE_MASK_RI_CHANGE = 4 # Trailing-edge Ring Detector -MODEMSTATE_MASK_DSR_CHANGE = 2 # Delta Data-Set-Ready -MODEMSTATE_MASK_CTS_CHANGE = 1 # Delta Clear-To-Send - -PURGE_RECEIVE_BUFFER = b'\x01' # Purge access server receive data buffer -PURGE_TRANSMIT_BUFFER = b'\x02' # Purge access server transmit data buffer -PURGE_BOTH_BUFFERS = b'\x03' # Purge both the access server receive data - # buffer and the access server transmit data buffer - - -RFC2217_PARITY_MAP = { - serial.PARITY_NONE: 1, - serial.PARITY_ODD: 2, - serial.PARITY_EVEN: 3, - serial.PARITY_MARK: 4, - serial.PARITY_SPACE: 5, -} -RFC2217_REVERSE_PARITY_MAP = dict((v, k) for k, v in RFC2217_PARITY_MAP.items()) - -RFC2217_STOPBIT_MAP = { - serial.STOPBITS_ONE: 1, - serial.STOPBITS_ONE_POINT_FIVE: 3, - serial.STOPBITS_TWO: 2, -} -RFC2217_REVERSE_STOPBIT_MAP = dict((v, k) for k, v in RFC2217_STOPBIT_MAP.items()) - -# Telnet filter states -M_NORMAL = 0 -M_IAC_SEEN = 1 -M_NEGOTIATE = 2 - -# TelnetOption and TelnetSubnegotiation states -REQUESTED = 'REQUESTED' -ACTIVE = 'ACTIVE' -INACTIVE = 'INACTIVE' -REALLY_INACTIVE = 'REALLY_INACTIVE' - - -class TelnetOption(object): - """Manage a single telnet option, keeps track of DO/DONT WILL/WONT.""" - - def __init__(self, connection, name, option, send_yes, send_no, ack_yes, - ack_no, initial_state, activation_callback=None): - """\ - Initialize option. - :param connection: connection used to transmit answers - :param name: a readable name for debug outputs - :param send_yes: what to send when option is to be enabled. - :param send_no: what to send when option is to be disabled. - :param ack_yes: what to expect when remote agrees on option. - :param ack_no: what to expect when remote disagrees on option. - :param initial_state: options initialized with REQUESTED are tried to - be enabled on startup. use INACTIVE for all others. - """ - self.connection = connection - self.name = name - self.option = option - self.send_yes = send_yes - self.send_no = send_no - self.ack_yes = ack_yes - self.ack_no = ack_no - self.state = initial_state - self.active = False - self.activation_callback = activation_callback - - def __repr__(self): - """String for debug outputs""" - return "{o.name}:{o.active}({o.state})".format(o=self) - - def process_incoming(self, command): - """\ - A DO/DONT/WILL/WONT was received for this option, update state and - answer when needed. - """ - if command == self.ack_yes: - if self.state is REQUESTED: - self.state = ACTIVE - self.active = True - if self.activation_callback is not None: - self.activation_callback() - elif self.state is ACTIVE: - pass - elif self.state is INACTIVE: - self.state = ACTIVE - self.connection.telnet_send_option(self.send_yes, self.option) - self.active = True - if self.activation_callback is not None: - self.activation_callback() - elif self.state is REALLY_INACTIVE: - self.connection.telnet_send_option(self.send_no, self.option) - else: - raise ValueError('option in illegal state {!r}'.format(self)) - elif command == self.ack_no: - if self.state is REQUESTED: - self.state = INACTIVE - self.active = False - elif self.state is ACTIVE: - self.state = INACTIVE - self.connection.telnet_send_option(self.send_no, self.option) - self.active = False - elif self.state is INACTIVE: - pass - elif self.state is REALLY_INACTIVE: - pass - else: - raise ValueError('option in illegal state {!r}'.format(self)) - - -class TelnetSubnegotiation(object): - """\ - A object to handle subnegotiation of options. In this case actually - sub-sub options for RFC 2217. It is used to track com port options. - """ - - def __init__(self, connection, name, option, ack_option=None): - if ack_option is None: - ack_option = option - self.connection = connection - self.name = name - self.option = option - self.value = None - self.ack_option = ack_option - self.state = INACTIVE - - def __repr__(self): - """String for debug outputs.""" - return "{sn.name}:{sn.state}".format(sn=self) - - def set(self, value): - """\ - Request a change of the value. a request is sent to the server. if - the client needs to know if the change is performed he has to check the - state of this object. - """ - self.value = value - self.state = REQUESTED - self.connection.rfc2217_send_subnegotiation(self.option, self.value) - if self.connection.logger: - self.connection.logger.debug("SB Requesting {} -> {!r}".format(self.name, self.value)) - - def is_ready(self): - """\ - Check if answer from server has been received. when server rejects - the change, raise a ValueError. - """ - if self.state == REALLY_INACTIVE: - raise ValueError("remote rejected value for option {!r}".format(self.name)) - return self.state == ACTIVE - # add property to have a similar interface as TelnetOption - active = property(is_ready) - - def wait(self, timeout=3): - """\ - Wait until the subnegotiation has been acknowledged or timeout. It - can also throw a value error when the answer from the server does not - match the value sent. - """ - timeout_timer = Timeout(timeout) - while not timeout_timer.expired(): - time.sleep(0.05) # prevent 100% CPU load - if self.is_ready(): - break - else: - raise SerialException("timeout while waiting for option {!r}".format(self.name)) - - def check_answer(self, suboption): - """\ - Check an incoming subnegotiation block. The parameter already has - cut off the header like sub option number and com port option value. - """ - if self.value == suboption[:len(self.value)]: - self.state = ACTIVE - else: - # error propagation done in is_ready - self.state = REALLY_INACTIVE - if self.connection.logger: - self.connection.logger.debug("SB Answer {} -> {!r} -> {}".format(self.name, suboption, self.state)) - - -class Serial(SerialBase): - """Serial port implementation for RFC 2217 remote serial ports.""" - - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200) - - def __init__(self, *args, **kwargs): - self._thread = None - self._socket = None - self._linestate = 0 - self._modemstate = None - self._modemstate_timeout = Timeout(-1) - self._remote_suspend_flow = False - self._write_lock = None - self.logger = None - self._ignore_set_control_answer = False - self._poll_modem_state = False - self._network_timeout = 3 - self._telnet_options = None - self._rfc2217_port_settings = None - self._rfc2217_options = None - self._read_buffer = None - super(Serial, self).__init__(*args, **kwargs) # must be last call in case of auto-open - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - self.logger = None - self._ignore_set_control_answer = False - self._poll_modem_state = False - self._network_timeout = 3 - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - try: - self._socket = socket.create_connection(self.from_url(self.portstr), timeout=5) # XXX good value? - self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - except Exception as msg: - self._socket = None - raise SerialException("Could not open port {}: {}".format(self.portstr, msg)) - - # use a thread save queue as buffer. it also simplifies implementing - # the read timeout - self._read_buffer = Queue.Queue() - # to ensure that user writes does not interfere with internal - # telnet/rfc2217 options establish a lock - self._write_lock = threading.Lock() - # name the following separately so that, below, a check can be easily done - mandadory_options = [ - TelnetOption(self, 'we-BINARY', BINARY, WILL, WONT, DO, DONT, INACTIVE), - TelnetOption(self, 'we-RFC2217', COM_PORT_OPTION, WILL, WONT, DO, DONT, REQUESTED), - ] - # all supported telnet options - self._telnet_options = [ - TelnetOption(self, 'ECHO', ECHO, DO, DONT, WILL, WONT, REQUESTED), - TelnetOption(self, 'we-SGA', SGA, WILL, WONT, DO, DONT, REQUESTED), - TelnetOption(self, 'they-SGA', SGA, DO, DONT, WILL, WONT, REQUESTED), - TelnetOption(self, 'they-BINARY', BINARY, DO, DONT, WILL, WONT, INACTIVE), - TelnetOption(self, 'they-RFC2217', COM_PORT_OPTION, DO, DONT, WILL, WONT, REQUESTED), - ] + mandadory_options - # RFC 2217 specific states - # COM port settings - self._rfc2217_port_settings = { - 'baudrate': TelnetSubnegotiation(self, 'baudrate', SET_BAUDRATE, SERVER_SET_BAUDRATE), - 'datasize': TelnetSubnegotiation(self, 'datasize', SET_DATASIZE, SERVER_SET_DATASIZE), - 'parity': TelnetSubnegotiation(self, 'parity', SET_PARITY, SERVER_SET_PARITY), - 'stopsize': TelnetSubnegotiation(self, 'stopsize', SET_STOPSIZE, SERVER_SET_STOPSIZE), - } - # There are more subnegotiation objects, combine all in one dictionary - # for easy access - self._rfc2217_options = { - 'purge': TelnetSubnegotiation(self, 'purge', PURGE_DATA, SERVER_PURGE_DATA), - 'control': TelnetSubnegotiation(self, 'control', SET_CONTROL, SERVER_SET_CONTROL), - } - self._rfc2217_options.update(self._rfc2217_port_settings) - # cache for line and modem states that the server sends to us - self._linestate = 0 - self._modemstate = None - self._modemstate_timeout = Timeout(-1) - # RFC 2217 flow control between server and client - self._remote_suspend_flow = False - - self.is_open = True - self._thread = threading.Thread(target=self._telnet_read_loop) - self._thread.setDaemon(True) - self._thread.setName('pySerial RFC 2217 reader thread for {}'.format(self._port)) - self._thread.start() - - try: # must clean-up if open fails - # negotiate Telnet/RFC 2217 -> send initial requests - for option in self._telnet_options: - if option.state is REQUESTED: - self.telnet_send_option(option.send_yes, option.option) - # now wait until important options are negotiated - timeout = Timeout(self._network_timeout) - while not timeout.expired(): - time.sleep(0.05) # prevent 100% CPU load - if sum(o.active for o in mandadory_options) == sum(o.state != INACTIVE for o in mandadory_options): - break - else: - raise SerialException( - "Remote does not seem to support RFC2217 or BINARY mode {!r}".format(mandadory_options)) - if self.logger: - self.logger.info("Negotiated options: {}".format(self._telnet_options)) - - # fine, go on, set RFC 2217 specific things - self._reconfigure_port() - # all things set up get, now a clean start - if not self._dsrdtr: - self._update_dtr_state() - if not self._rtscts: - self._update_rts_state() - self.reset_input_buffer() - self.reset_output_buffer() - except: - self.close() - raise - - def _reconfigure_port(self): - """Set communication parameters on opened port.""" - if self._socket is None: - raise SerialException("Can only operate on open ports") - - # if self._timeout != 0 and self._interCharTimeout is not None: - # XXX - - if self._write_timeout is not None: - raise NotImplementedError('write_timeout is currently not supported') - # XXX - - # Setup the connection - # to get good performance, all parameter changes are sent first... - if not 0 < self._baudrate < 2 ** 32: - raise ValueError("invalid baudrate: {!r}".format(self._baudrate)) - self._rfc2217_port_settings['baudrate'].set(struct.pack(b'!I', self._baudrate)) - self._rfc2217_port_settings['datasize'].set(struct.pack(b'!B', self._bytesize)) - self._rfc2217_port_settings['parity'].set(struct.pack(b'!B', RFC2217_PARITY_MAP[self._parity])) - self._rfc2217_port_settings['stopsize'].set(struct.pack(b'!B', RFC2217_STOPBIT_MAP[self._stopbits])) - - # and now wait until parameters are active - items = self._rfc2217_port_settings.values() - if self.logger: - self.logger.debug("Negotiating settings: {}".format(items)) - timeout = Timeout(self._network_timeout) - while not timeout.expired(): - time.sleep(0.05) # prevent 100% CPU load - if sum(o.active for o in items) == len(items): - break - else: - raise SerialException("Remote does not accept parameter change (RFC2217): {!r}".format(items)) - if self.logger: - self.logger.info("Negotiated settings: {}".format(items)) - - if self._rtscts and self._xonxoff: - raise ValueError('xonxoff and rtscts together are not supported') - elif self._rtscts: - self.rfc2217_set_control(SET_CONTROL_USE_HW_FLOW_CONTROL) - elif self._xonxoff: - self.rfc2217_set_control(SET_CONTROL_USE_SW_FLOW_CONTROL) - else: - self.rfc2217_set_control(SET_CONTROL_USE_NO_FLOW_CONTROL) - - def close(self): - """Close port""" - self.is_open = False - if self._socket: - try: - self._socket.shutdown(socket.SHUT_RDWR) - self._socket.close() - except: - # ignore errors. - pass - if self._thread: - self._thread.join(7) # XXX more than socket timeout - self._thread = None - # in case of quick reconnects, give the server some time - time.sleep(0.3) - self._socket = None - - def from_url(self, url): - """\ - extract host and port from an URL string, other settings are extracted - an stored in instance - """ - parts = urlparse.urlsplit(url) - if parts.scheme != "rfc2217": - raise SerialException( - 'expected a string in the form ' - '"rfc2217://:[?option[&option...]]": ' - 'not starting with rfc2217:// ({!r})'.format(parts.scheme)) - try: - # process options now, directly altering self - for option, values in urlparse.parse_qs(parts.query, True).items(): - if option == 'logging': - logging.basicConfig() # XXX is that good to call it here? - self.logger = logging.getLogger('pySerial.rfc2217') - self.logger.setLevel(LOGGER_LEVELS[values[0]]) - self.logger.debug('enabled logging') - elif option == 'ign_set_control': - self._ignore_set_control_answer = True - elif option == 'poll_modem': - self._poll_modem_state = True - elif option == 'timeout': - self._network_timeout = float(values[0]) - else: - raise ValueError('unknown option: {!r}'.format(option)) - if not 0 <= parts.port < 65536: - raise ValueError("port not in range 0...65535") - except ValueError as e: - raise SerialException( - 'expected a string in the form ' - '"rfc2217://:[?option[&option...]]": {}'.format(e)) - return (parts.hostname, parts.port) - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def in_waiting(self): - """Return the number of bytes currently in the input buffer.""" - if not self.is_open: - raise PortNotOpenError() - return self._read_buffer.qsize() - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self.is_open: - raise PortNotOpenError() - data = bytearray() - try: - timeout = Timeout(self._timeout) - while len(data) < size: - if self._thread is None or not self._thread.is_alive(): - raise SerialException('connection failed (reader thread died)') - buf = self._read_buffer.get(True, timeout.time_left()) - if buf is None: - return bytes(data) - data += buf - if timeout.expired(): - break - except Queue.Empty: # -> timeout - pass - return bytes(data) - - def write(self, data): - """\ - Output the given byte string over the serial port. Can block if the - connection is blocked. May raise SerialException if the connection is - closed. - """ - if not self.is_open: - raise PortNotOpenError() - with self._write_lock: - try: - self._socket.sendall(to_bytes(data).replace(IAC, IAC_DOUBLED)) - except socket.error as e: - raise SerialException("connection failed (socket error): {}".format(e)) - return len(data) - - def reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self.is_open: - raise PortNotOpenError() - self.rfc2217_send_purge(PURGE_RECEIVE_BUFFER) - # empty read buffer - while self._read_buffer.qsize(): - self._read_buffer.get(False) - - def reset_output_buffer(self): - """\ - Clear output buffer, aborting the current output and - discarding all that is in the buffer. - """ - if not self.is_open: - raise PortNotOpenError() - self.rfc2217_send_purge(PURGE_TRANSMIT_BUFFER) - - def _update_break_state(self): - """\ - Set break: Controls TXD. When active, to transmitting is - possible. - """ - if not self.is_open: - raise PortNotOpenError() - if self.logger: - self.logger.info('set BREAK to {}'.format('active' if self._break_state else 'inactive')) - if self._break_state: - self.rfc2217_set_control(SET_CONTROL_BREAK_ON) - else: - self.rfc2217_set_control(SET_CONTROL_BREAK_OFF) - - def _update_rts_state(self): - """Set terminal status line: Request To Send.""" - if not self.is_open: - raise PortNotOpenError() - if self.logger: - self.logger.info('set RTS to {}'.format('active' if self._rts_state else 'inactive')) - if self._rts_state: - self.rfc2217_set_control(SET_CONTROL_RTS_ON) - else: - self.rfc2217_set_control(SET_CONTROL_RTS_OFF) - - def _update_dtr_state(self): - """Set terminal status line: Data Terminal Ready.""" - if not self.is_open: - raise PortNotOpenError() - if self.logger: - self.logger.info('set DTR to {}'.format('active' if self._dtr_state else 'inactive')) - if self._dtr_state: - self.rfc2217_set_control(SET_CONTROL_DTR_ON) - else: - self.rfc2217_set_control(SET_CONTROL_DTR_OFF) - - @property - def cts(self): - """Read terminal status line: Clear To Send.""" - if not self.is_open: - raise PortNotOpenError() - return bool(self.get_modem_state() & MODEMSTATE_MASK_CTS) - - @property - def dsr(self): - """Read terminal status line: Data Set Ready.""" - if not self.is_open: - raise PortNotOpenError() - return bool(self.get_modem_state() & MODEMSTATE_MASK_DSR) - - @property - def ri(self): - """Read terminal status line: Ring Indicator.""" - if not self.is_open: - raise PortNotOpenError() - return bool(self.get_modem_state() & MODEMSTATE_MASK_RI) - - @property - def cd(self): - """Read terminal status line: Carrier Detect.""" - if not self.is_open: - raise PortNotOpenError() - return bool(self.get_modem_state() & MODEMSTATE_MASK_CD) - - # - - - platform specific - - - - # None so far - - # - - - RFC2217 specific - - - - - def _telnet_read_loop(self): - """Read loop for the socket.""" - mode = M_NORMAL - suboption = None - try: - while self.is_open: - try: - data = self._socket.recv(1024) - except socket.timeout: - # just need to get out of recv form time to time to check if - # still alive - continue - except socket.error as e: - # connection fails -> terminate loop - if self.logger: - self.logger.debug("socket error in reader thread: {}".format(e)) - self._read_buffer.put(None) - break - if not data: - self._read_buffer.put(None) - break # lost connection - for byte in iterbytes(data): - if mode == M_NORMAL: - # interpret as command or as data - if byte == IAC: - mode = M_IAC_SEEN - else: - # store data in read buffer or sub option buffer - # depending on state - if suboption is not None: - suboption += byte - else: - self._read_buffer.put(byte) - elif mode == M_IAC_SEEN: - if byte == IAC: - # interpret as command doubled -> insert character - # itself - if suboption is not None: - suboption += IAC - else: - self._read_buffer.put(IAC) - mode = M_NORMAL - elif byte == SB: - # sub option start - suboption = bytearray() - mode = M_NORMAL - elif byte == SE: - # sub option end -> process it now - self._telnet_process_subnegotiation(bytes(suboption)) - suboption = None - mode = M_NORMAL - elif byte in (DO, DONT, WILL, WONT): - # negotiation - telnet_command = byte - mode = M_NEGOTIATE - else: - # other telnet commands - self._telnet_process_command(byte) - mode = M_NORMAL - elif mode == M_NEGOTIATE: # DO, DONT, WILL, WONT was received, option now following - self._telnet_negotiate_option(telnet_command, byte) - mode = M_NORMAL - finally: - if self.logger: - self.logger.debug("read thread terminated") - - # - incoming telnet commands and options - - def _telnet_process_command(self, command): - """Process commands other than DO, DONT, WILL, WONT.""" - # Currently none. RFC2217 only uses negotiation and subnegotiation. - if self.logger: - self.logger.warning("ignoring Telnet command: {!r}".format(command)) - - def _telnet_negotiate_option(self, command, option): - """Process incoming DO, DONT, WILL, WONT.""" - # check our registered telnet options and forward command to them - # they know themselves if they have to answer or not - known = False - for item in self._telnet_options: - # can have more than one match! as some options are duplicated for - # 'us' and 'them' - if item.option == option: - item.process_incoming(command) - known = True - if not known: - # handle unknown options - # only answer to positive requests and deny them - if command == WILL or command == DO: - self.telnet_send_option((DONT if command == WILL else WONT), option) - if self.logger: - self.logger.warning("rejected Telnet option: {!r}".format(option)) - - def _telnet_process_subnegotiation(self, suboption): - """Process subnegotiation, the data between IAC SB and IAC SE.""" - if suboption[0:1] == COM_PORT_OPTION: - if suboption[1:2] == SERVER_NOTIFY_LINESTATE and len(suboption) >= 3: - self._linestate = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("NOTIFY_LINESTATE: {}".format(self._linestate)) - elif suboption[1:2] == SERVER_NOTIFY_MODEMSTATE and len(suboption) >= 3: - self._modemstate = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("NOTIFY_MODEMSTATE: {}".format(self._modemstate)) - # update time when we think that a poll would make sense - self._modemstate_timeout.restart(0.3) - elif suboption[1:2] == FLOWCONTROL_SUSPEND: - self._remote_suspend_flow = True - elif suboption[1:2] == FLOWCONTROL_RESUME: - self._remote_suspend_flow = False - else: - for item in self._rfc2217_options.values(): - if item.ack_option == suboption[1:2]: - #~ print "processing COM_PORT_OPTION: %r" % list(suboption[1:]) - item.check_answer(bytes(suboption[2:])) - break - else: - if self.logger: - self.logger.warning("ignoring COM_PORT_OPTION: {!r}".format(suboption)) - else: - if self.logger: - self.logger.warning("ignoring subnegotiation: {!r}".format(suboption)) - - # - outgoing telnet commands and options - - def _internal_raw_write(self, data): - """internal socket write with no data escaping. used to send telnet stuff.""" - with self._write_lock: - self._socket.sendall(data) - - def telnet_send_option(self, action, option): - """Send DO, DONT, WILL, WONT.""" - self._internal_raw_write(IAC + action + option) - - def rfc2217_send_subnegotiation(self, option, value=b''): - """Subnegotiation of RFC2217 parameters.""" - value = value.replace(IAC, IAC_DOUBLED) - self._internal_raw_write(IAC + SB + COM_PORT_OPTION + option + value + IAC + SE) - - def rfc2217_send_purge(self, value): - """\ - Send purge request to the remote. - (PURGE_RECEIVE_BUFFER / PURGE_TRANSMIT_BUFFER / PURGE_BOTH_BUFFERS) - """ - item = self._rfc2217_options['purge'] - item.set(value) # transmit desired purge type - item.wait(self._network_timeout) # wait for acknowledge from the server - - def rfc2217_set_control(self, value): - """transmit change of control line to remote""" - item = self._rfc2217_options['control'] - item.set(value) # transmit desired control type - if self._ignore_set_control_answer: - # answers are ignored when option is set. compatibility mode for - # servers that answer, but not the expected one... (or no answer - # at all) i.e. sredird - time.sleep(0.1) # this helps getting the unit tests passed - else: - item.wait(self._network_timeout) # wait for acknowledge from the server - - def rfc2217_flow_server_ready(self): - """\ - check if server is ready to receive data. block for some time when - not. - """ - #~ if self._remote_suspend_flow: - #~ wait--- - - def get_modem_state(self): - """\ - get last modem state (cached value. If value is "old", request a new - one. This cache helps that we don't issue to many requests when e.g. all - status lines, one after the other is queried by the user (CTS, DSR - etc.) - """ - # active modem state polling enabled? is the value fresh enough? - if self._poll_modem_state and self._modemstate_timeout.expired(): - if self.logger: - self.logger.debug('polling modem state') - # when it is older, request an update - self.rfc2217_send_subnegotiation(NOTIFY_MODEMSTATE) - timeout = Timeout(self._network_timeout) - while not timeout.expired(): - time.sleep(0.05) # prevent 100% CPU load - # when expiration time is updated, it means that there is a new - # value - if not self._modemstate_timeout.expired(): - break - else: - if self.logger: - self.logger.warning('poll for modem state failed') - # even when there is a timeout, do not generate an error just - # return the last known value. this way we can support buggy - # servers that do not respond to polls, but send automatic - # updates. - if self._modemstate is not None: - if self.logger: - self.logger.debug('using cached modem state') - return self._modemstate - else: - # never received a notification from the server - raise SerialException("remote sends no NOTIFY_MODEMSTATE") - - -############################################################################# -# The following is code that helps implementing an RFC 2217 server. - -class PortManager(object): - """\ - This class manages the state of Telnet and RFC 2217. It needs a serial - instance and a connection to work with. Connection is expected to implement - a (thread safe) write function, that writes the string to the network. - """ - - def __init__(self, serial_port, connection, logger=None): - self.serial = serial_port - self.connection = connection - self.logger = logger - self._client_is_rfc2217 = False - - # filter state machine - self.mode = M_NORMAL - self.suboption = None - self.telnet_command = None - - # states for modem/line control events - self.modemstate_mask = 255 - self.last_modemstate = None - self.linstate_mask = 0 - - # all supported telnet options - self._telnet_options = [ - TelnetOption(self, 'ECHO', ECHO, WILL, WONT, DO, DONT, REQUESTED), - TelnetOption(self, 'we-SGA', SGA, WILL, WONT, DO, DONT, REQUESTED), - TelnetOption(self, 'they-SGA', SGA, DO, DONT, WILL, WONT, INACTIVE), - TelnetOption(self, 'we-BINARY', BINARY, WILL, WONT, DO, DONT, INACTIVE), - TelnetOption(self, 'they-BINARY', BINARY, DO, DONT, WILL, WONT, REQUESTED), - TelnetOption(self, 'we-RFC2217', COM_PORT_OPTION, WILL, WONT, DO, DONT, REQUESTED, self._client_ok), - TelnetOption(self, 'they-RFC2217', COM_PORT_OPTION, DO, DONT, WILL, WONT, INACTIVE, self._client_ok), - ] - - # negotiate Telnet/RFC2217 -> send initial requests - if self.logger: - self.logger.debug("requesting initial Telnet/RFC 2217 options") - for option in self._telnet_options: - if option.state is REQUESTED: - self.telnet_send_option(option.send_yes, option.option) - # issue 1st modem state notification - - def _client_ok(self): - """\ - callback of telnet option. It gets called when option is activated. - This one here is used to detect when the client agrees on RFC 2217. A - flag is set so that other functions like check_modem_lines know if the - client is OK. - """ - # The callback is used for we and they so if one party agrees, we're - # already happy. it seems not all servers do the negotiation correctly - # and i guess there are incorrect clients too.. so be happy if client - # answers one or the other positively. - self._client_is_rfc2217 = True - if self.logger: - self.logger.info("client accepts RFC 2217") - # this is to ensure that the client gets a notification, even if there - # was no change - self.check_modem_lines(force_notification=True) - - # - outgoing telnet commands and options - - def telnet_send_option(self, action, option): - """Send DO, DONT, WILL, WONT.""" - self.connection.write(IAC + action + option) - - def rfc2217_send_subnegotiation(self, option, value=b''): - """Subnegotiation of RFC 2217 parameters.""" - value = value.replace(IAC, IAC_DOUBLED) - self.connection.write(IAC + SB + COM_PORT_OPTION + option + value + IAC + SE) - - # - check modem lines, needs to be called periodically from user to - # establish polling - - def check_modem_lines(self, force_notification=False): - """\ - read control lines from serial port and compare the last value sent to remote. - send updates on changes. - """ - modemstate = ( - (self.serial.cts and MODEMSTATE_MASK_CTS) | - (self.serial.dsr and MODEMSTATE_MASK_DSR) | - (self.serial.ri and MODEMSTATE_MASK_RI) | - (self.serial.cd and MODEMSTATE_MASK_CD)) - # check what has changed - deltas = modemstate ^ (self.last_modemstate or 0) # when last is None -> 0 - if deltas & MODEMSTATE_MASK_CTS: - modemstate |= MODEMSTATE_MASK_CTS_CHANGE - if deltas & MODEMSTATE_MASK_DSR: - modemstate |= MODEMSTATE_MASK_DSR_CHANGE - if deltas & MODEMSTATE_MASK_RI: - modemstate |= MODEMSTATE_MASK_RI_CHANGE - if deltas & MODEMSTATE_MASK_CD: - modemstate |= MODEMSTATE_MASK_CD_CHANGE - # if new state is different and the mask allows this change, send - # notification. suppress notifications when client is not rfc2217 - if modemstate != self.last_modemstate or force_notification: - if (self._client_is_rfc2217 and (modemstate & self.modemstate_mask)) or force_notification: - self.rfc2217_send_subnegotiation( - SERVER_NOTIFY_MODEMSTATE, - to_bytes([modemstate & self.modemstate_mask])) - if self.logger: - self.logger.info("NOTIFY_MODEMSTATE: {}".format(modemstate)) - # save last state, but forget about deltas. - # otherwise it would also notify about changing deltas which is - # probably not very useful - self.last_modemstate = modemstate & 0xf0 - - # - outgoing data escaping - - def escape(self, data): - """\ - This generator function is for the user. All outgoing data has to be - properly escaped, so that no IAC character in the data stream messes up - the Telnet state machine in the server. - - socket.sendall(escape(data)) - """ - for byte in iterbytes(data): - if byte == IAC: - yield IAC - yield IAC - else: - yield byte - - # - incoming data filter - - def filter(self, data): - """\ - Handle a bunch of incoming bytes. This is a generator. It will yield - all characters not of interest for Telnet/RFC 2217. - - The idea is that the reader thread pushes data from the socket through - this filter: - - for byte in filter(socket.recv(1024)): - # do things like CR/LF conversion/whatever - # and write data to the serial port - serial.write(byte) - - (socket error handling code left as exercise for the reader) - """ - for byte in iterbytes(data): - if self.mode == M_NORMAL: - # interpret as command or as data - if byte == IAC: - self.mode = M_IAC_SEEN - else: - # store data in sub option buffer or pass it to our - # consumer depending on state - if self.suboption is not None: - self.suboption += byte - else: - yield byte - elif self.mode == M_IAC_SEEN: - if byte == IAC: - # interpret as command doubled -> insert character - # itself - if self.suboption is not None: - self.suboption += byte - else: - yield byte - self.mode = M_NORMAL - elif byte == SB: - # sub option start - self.suboption = bytearray() - self.mode = M_NORMAL - elif byte == SE: - # sub option end -> process it now - self._telnet_process_subnegotiation(bytes(self.suboption)) - self.suboption = None - self.mode = M_NORMAL - elif byte in (DO, DONT, WILL, WONT): - # negotiation - self.telnet_command = byte - self.mode = M_NEGOTIATE - else: - # other telnet commands - self._telnet_process_command(byte) - self.mode = M_NORMAL - elif self.mode == M_NEGOTIATE: # DO, DONT, WILL, WONT was received, option now following - self._telnet_negotiate_option(self.telnet_command, byte) - self.mode = M_NORMAL - - # - incoming telnet commands and options - - def _telnet_process_command(self, command): - """Process commands other than DO, DONT, WILL, WONT.""" - # Currently none. RFC2217 only uses negotiation and subnegotiation. - if self.logger: - self.logger.warning("ignoring Telnet command: {!r}".format(command)) - - def _telnet_negotiate_option(self, command, option): - """Process incoming DO, DONT, WILL, WONT.""" - # check our registered telnet options and forward command to them - # they know themselves if they have to answer or not - known = False - for item in self._telnet_options: - # can have more than one match! as some options are duplicated for - # 'us' and 'them' - if item.option == option: - item.process_incoming(command) - known = True - if not known: - # handle unknown options - # only answer to positive requests and deny them - if command == WILL or command == DO: - self.telnet_send_option((DONT if command == WILL else WONT), option) - if self.logger: - self.logger.warning("rejected Telnet option: {!r}".format(option)) - - def _telnet_process_subnegotiation(self, suboption): - """Process subnegotiation, the data between IAC SB and IAC SE.""" - if suboption[0:1] == COM_PORT_OPTION: - if self.logger: - self.logger.debug('received COM_PORT_OPTION: {!r}'.format(suboption)) - if suboption[1:2] == SET_BAUDRATE: - backup = self.serial.baudrate - try: - (baudrate,) = struct.unpack(b"!I", suboption[2:6]) - if baudrate != 0: - self.serial.baudrate = baudrate - except ValueError as e: - if self.logger: - self.logger.error("failed to set baud rate: {}".format(e)) - self.serial.baudrate = backup - else: - if self.logger: - self.logger.info("{} baud rate: {}".format('set' if baudrate else 'get', self.serial.baudrate)) - self.rfc2217_send_subnegotiation(SERVER_SET_BAUDRATE, struct.pack(b"!I", self.serial.baudrate)) - elif suboption[1:2] == SET_DATASIZE: - backup = self.serial.bytesize - try: - (datasize,) = struct.unpack(b"!B", suboption[2:3]) - if datasize != 0: - self.serial.bytesize = datasize - except ValueError as e: - if self.logger: - self.logger.error("failed to set data size: {}".format(e)) - self.serial.bytesize = backup - else: - if self.logger: - self.logger.info("{} data size: {}".format('set' if datasize else 'get', self.serial.bytesize)) - self.rfc2217_send_subnegotiation(SERVER_SET_DATASIZE, struct.pack(b"!B", self.serial.bytesize)) - elif suboption[1:2] == SET_PARITY: - backup = self.serial.parity - try: - parity = struct.unpack(b"!B", suboption[2:3])[0] - if parity != 0: - self.serial.parity = RFC2217_REVERSE_PARITY_MAP[parity] - except ValueError as e: - if self.logger: - self.logger.error("failed to set parity: {}".format(e)) - self.serial.parity = backup - else: - if self.logger: - self.logger.info("{} parity: {}".format('set' if parity else 'get', self.serial.parity)) - self.rfc2217_send_subnegotiation( - SERVER_SET_PARITY, - struct.pack(b"!B", RFC2217_PARITY_MAP[self.serial.parity])) - elif suboption[1:2] == SET_STOPSIZE: - backup = self.serial.stopbits - try: - stopbits = struct.unpack(b"!B", suboption[2:3])[0] - if stopbits != 0: - self.serial.stopbits = RFC2217_REVERSE_STOPBIT_MAP[stopbits] - except ValueError as e: - if self.logger: - self.logger.error("failed to set stop bits: {}".format(e)) - self.serial.stopbits = backup - else: - if self.logger: - self.logger.info("{} stop bits: {}".format('set' if stopbits else 'get', self.serial.stopbits)) - self.rfc2217_send_subnegotiation( - SERVER_SET_STOPSIZE, - struct.pack(b"!B", RFC2217_STOPBIT_MAP[self.serial.stopbits])) - elif suboption[1:2] == SET_CONTROL: - if suboption[2:3] == SET_CONTROL_REQ_FLOW_SETTING: - if self.serial.xonxoff: - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_SW_FLOW_CONTROL) - elif self.serial.rtscts: - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_HW_FLOW_CONTROL) - else: - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_NO_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_USE_NO_FLOW_CONTROL: - self.serial.xonxoff = False - self.serial.rtscts = False - if self.logger: - self.logger.info("changed flow control to None") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_NO_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_USE_SW_FLOW_CONTROL: - self.serial.xonxoff = True - if self.logger: - self.logger.info("changed flow control to XON/XOFF") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_SW_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_USE_HW_FLOW_CONTROL: - self.serial.rtscts = True - if self.logger: - self.logger.info("changed flow control to RTS/CTS") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_HW_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_REQ_BREAK_STATE: - if self.logger: - self.logger.warning("requested break state - not implemented") - pass # XXX needs cached value - elif suboption[2:3] == SET_CONTROL_BREAK_ON: - self.serial.break_condition = True - if self.logger: - self.logger.info("changed BREAK to active") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_BREAK_ON) - elif suboption[2:3] == SET_CONTROL_BREAK_OFF: - self.serial.break_condition = False - if self.logger: - self.logger.info("changed BREAK to inactive") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_BREAK_OFF) - elif suboption[2:3] == SET_CONTROL_REQ_DTR: - if self.logger: - self.logger.warning("requested DTR state - not implemented") - pass # XXX needs cached value - elif suboption[2:3] == SET_CONTROL_DTR_ON: - self.serial.dtr = True - if self.logger: - self.logger.info("changed DTR to active") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_DTR_ON) - elif suboption[2:3] == SET_CONTROL_DTR_OFF: - self.serial.dtr = False - if self.logger: - self.logger.info("changed DTR to inactive") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_DTR_OFF) - elif suboption[2:3] == SET_CONTROL_REQ_RTS: - if self.logger: - self.logger.warning("requested RTS state - not implemented") - pass # XXX needs cached value - #~ self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_ON) - elif suboption[2:3] == SET_CONTROL_RTS_ON: - self.serial.rts = True - if self.logger: - self.logger.info("changed RTS to active") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_ON) - elif suboption[2:3] == SET_CONTROL_RTS_OFF: - self.serial.rts = False - if self.logger: - self.logger.info("changed RTS to inactive") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_OFF) - #~ elif suboption[2:3] == SET_CONTROL_REQ_FLOW_SETTING_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_NO_FLOW_CONTROL_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_SW_FLOW_CONTOL_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_HW_FLOW_CONTOL_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_DCD_FLOW_CONTROL: - #~ elif suboption[2:3] == SET_CONTROL_USE_DTR_FLOW_CONTROL: - #~ elif suboption[2:3] == SET_CONTROL_USE_DSR_FLOW_CONTROL: - elif suboption[1:2] == NOTIFY_LINESTATE: - # client polls for current state - self.rfc2217_send_subnegotiation( - SERVER_NOTIFY_LINESTATE, - to_bytes([0])) # sorry, nothing like that implemented - elif suboption[1:2] == NOTIFY_MODEMSTATE: - if self.logger: - self.logger.info("request for modem state") - # client polls for current state - self.check_modem_lines(force_notification=True) - elif suboption[1:2] == FLOWCONTROL_SUSPEND: - if self.logger: - self.logger.info("suspend") - self._remote_suspend_flow = True - elif suboption[1:2] == FLOWCONTROL_RESUME: - if self.logger: - self.logger.info("resume") - self._remote_suspend_flow = False - elif suboption[1:2] == SET_LINESTATE_MASK: - self.linstate_mask = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("line state mask: 0x{:02x}".format(self.linstate_mask)) - elif suboption[1:2] == SET_MODEMSTATE_MASK: - self.modemstate_mask = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("modem state mask: 0x{:02x}".format(self.modemstate_mask)) - elif suboption[1:2] == PURGE_DATA: - if suboption[2:3] == PURGE_RECEIVE_BUFFER: - self.serial.reset_input_buffer() - if self.logger: - self.logger.info("purge in") - self.rfc2217_send_subnegotiation(SERVER_PURGE_DATA, PURGE_RECEIVE_BUFFER) - elif suboption[2:3] == PURGE_TRANSMIT_BUFFER: - self.serial.reset_output_buffer() - if self.logger: - self.logger.info("purge out") - self.rfc2217_send_subnegotiation(SERVER_PURGE_DATA, PURGE_TRANSMIT_BUFFER) - elif suboption[2:3] == PURGE_BOTH_BUFFERS: - self.serial.reset_input_buffer() - self.serial.reset_output_buffer() - if self.logger: - self.logger.info("purge both") - self.rfc2217_send_subnegotiation(SERVER_PURGE_DATA, PURGE_BOTH_BUFFERS) - else: - if self.logger: - self.logger.error("undefined PURGE_DATA: {!r}".format(list(suboption[2:]))) - else: - if self.logger: - self.logger.error("undefined COM_PORT_OPTION: {!r}".format(list(suboption[1:]))) - else: - if self.logger: - self.logger.warning("unknown subnegotiation: {!r}".format(suboption)) - - -# simple client test -if __name__ == '__main__': - import sys - s = Serial('rfc2217://localhost:7000', 115200) - sys.stdout.write('{}\n'.format(s)) - - sys.stdout.write("write...\n") - s.write(b"hello\n") - s.flush() - sys.stdout.write("read: {}\n".format(s.read(5))) - s.close() diff --git a/extensions/km-plot/deps/serial/rs485.py b/extensions/km-plot/deps/serial/rs485.py deleted file mode 100644 index d7aff6f..0000000 --- a/extensions/km-plot/deps/serial/rs485.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python - -# RS485 support -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -"""\ -The settings for RS485 are stored in a dedicated object that can be applied to -serial ports (where supported). -NOTE: Some implementations may only support a subset of the settings. -""" - -from __future__ import absolute_import - -import time -import serial - - -class RS485Settings(object): - def __init__( - self, - rts_level_for_tx=True, - rts_level_for_rx=False, - loopback=False, - delay_before_tx=None, - delay_before_rx=None): - self.rts_level_for_tx = rts_level_for_tx - self.rts_level_for_rx = rts_level_for_rx - self.loopback = loopback - self.delay_before_tx = delay_before_tx - self.delay_before_rx = delay_before_rx - - -class RS485(serial.Serial): - """\ - A subclass that replaces the write method with one that toggles RTS - according to the RS485 settings. - - NOTE: This may work unreliably on some serial ports (control signals not - synchronized or delayed compared to data). Using delays may be - unreliable (varying times, larger than expected) as the OS may not - support very fine grained delays (no smaller than in the order of - tens of milliseconds). - - NOTE: Some implementations support this natively. Better performance - can be expected when the native version is used. - - NOTE: The loopback property is ignored by this implementation. The actual - behavior depends on the used hardware. - - Usage: - - ser = RS485(...) - ser.rs485_mode = RS485Settings(...) - ser.write(b'hello') - """ - - def __init__(self, *args, **kwargs): - super(RS485, self).__init__(*args, **kwargs) - self._alternate_rs485_settings = None - - def write(self, b): - """Write to port, controlling RTS before and after transmitting.""" - if self._alternate_rs485_settings is not None: - # apply level for TX and optional delay - self.setRTS(self._alternate_rs485_settings.rts_level_for_tx) - if self._alternate_rs485_settings.delay_before_tx is not None: - time.sleep(self._alternate_rs485_settings.delay_before_tx) - # write and wait for data to be written - super(RS485, self).write(b) - super(RS485, self).flush() - # optional delay and apply level for RX - if self._alternate_rs485_settings.delay_before_rx is not None: - time.sleep(self._alternate_rs485_settings.delay_before_rx) - self.setRTS(self._alternate_rs485_settings.rts_level_for_rx) - else: - super(RS485, self).write(b) - - # redirect where the property stores the settings so that underlying Serial - # instance does not see them - @property - def rs485_mode(self): - """\ - Enable RS485 mode and apply new settings, set to None to disable. - See serial.rs485.RS485Settings for more info about the value. - """ - return self._alternate_rs485_settings - - @rs485_mode.setter - def rs485_mode(self, rs485_settings): - self._alternate_rs485_settings = rs485_settings diff --git a/extensions/km-plot/deps/serial/serialcli.py b/extensions/km-plot/deps/serial/serialcli.py deleted file mode 100644 index 4614736..0000000 --- a/extensions/km-plot/deps/serial/serialcli.py +++ /dev/null @@ -1,253 +0,0 @@ -#! python -# -# Backend for .NET/Mono (IronPython), .NET >= 2 -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2008-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -from __future__ import absolute_import - -import System -import System.IO.Ports -from serial.serialutil import * - -# must invoke function with byte array, make a helper to convert strings -# to byte arrays -sab = System.Array[System.Byte] - - -def as_byte_array(string): - return sab([ord(x) for x in string]) # XXX will require adaption when run with a 3.x compatible IronPython - - -class Serial(SerialBase): - """Serial port implementation for .NET/Mono.""" - - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200) - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - try: - self._port_handle = System.IO.Ports.SerialPort(self.portstr) - except Exception as msg: - self._port_handle = None - raise SerialException("could not open port %s: %s" % (self.portstr, msg)) - - # if RTS and/or DTR are not set before open, they default to True - if self._rts_state is None: - self._rts_state = True - if self._dtr_state is None: - self._dtr_state = True - - self._reconfigure_port() - self._port_handle.Open() - self.is_open = True - if not self._dsrdtr: - self._update_dtr_state() - if not self._rtscts: - self._update_rts_state() - self.reset_input_buffer() - - def _reconfigure_port(self): - """Set communication parameters on opened port.""" - if not self._port_handle: - raise SerialException("Can only operate on a valid port handle") - - #~ self._port_handle.ReceivedBytesThreshold = 1 - - if self._timeout is None: - self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout - else: - self._port_handle.ReadTimeout = int(self._timeout * 1000) - - # if self._timeout != 0 and self._interCharTimeout is not None: - # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:] - - if self._write_timeout is None: - self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout - else: - self._port_handle.WriteTimeout = int(self._write_timeout * 1000) - - # Setup the connection info. - try: - self._port_handle.BaudRate = self._baudrate - except IOError as e: - # catch errors from illegal baudrate settings - raise ValueError(str(e)) - - if self._bytesize == FIVEBITS: - self._port_handle.DataBits = 5 - elif self._bytesize == SIXBITS: - self._port_handle.DataBits = 6 - elif self._bytesize == SEVENBITS: - self._port_handle.DataBits = 7 - elif self._bytesize == EIGHTBITS: - self._port_handle.DataBits = 8 - else: - raise ValueError("Unsupported number of data bits: %r" % self._bytesize) - - if self._parity == PARITY_NONE: - self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k - elif self._parity == PARITY_EVEN: - self._port_handle.Parity = System.IO.Ports.Parity.Even - elif self._parity == PARITY_ODD: - self._port_handle.Parity = System.IO.Ports.Parity.Odd - elif self._parity == PARITY_MARK: - self._port_handle.Parity = System.IO.Ports.Parity.Mark - elif self._parity == PARITY_SPACE: - self._port_handle.Parity = System.IO.Ports.Parity.Space - else: - raise ValueError("Unsupported parity mode: %r" % self._parity) - - if self._stopbits == STOPBITS_ONE: - self._port_handle.StopBits = System.IO.Ports.StopBits.One - elif self._stopbits == STOPBITS_ONE_POINT_FIVE: - self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive - elif self._stopbits == STOPBITS_TWO: - self._port_handle.StopBits = System.IO.Ports.StopBits.Two - else: - raise ValueError("Unsupported number of stop bits: %r" % self._stopbits) - - if self._rtscts and self._xonxoff: - self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff - elif self._rtscts: - self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend - elif self._xonxoff: - self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff - else: - self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k - - #~ def __del__(self): - #~ self.close() - - def close(self): - """Close port""" - if self.is_open: - if self._port_handle: - try: - self._port_handle.Close() - except System.IO.Ports.InvalidOperationException: - # ignore errors. can happen for unplugged USB serial devices - pass - self._port_handle = None - self.is_open = False - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def in_waiting(self): - """Return the number of characters currently in the input buffer.""" - if not self.is_open: - raise PortNotOpenError() - return self._port_handle.BytesToRead - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self.is_open: - raise PortNotOpenError() - # must use single byte reads as this is the only way to read - # without applying encodings - data = bytearray() - while size: - try: - data.append(self._port_handle.ReadByte()) - except System.TimeoutException: - break - else: - size -= 1 - return bytes(data) - - def write(self, data): - """Output the given string over the serial port.""" - if not self.is_open: - raise PortNotOpenError() - #~ if not isinstance(data, (bytes, bytearray)): - #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) - try: - # must call overloaded method with byte array argument - # as this is the only one not applying encodings - self._port_handle.Write(as_byte_array(data), 0, len(data)) - except System.TimeoutException: - raise SerialTimeoutException('Write timeout') - return len(data) - - def reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self.is_open: - raise PortNotOpenError() - self._port_handle.DiscardInBuffer() - - def reset_output_buffer(self): - """\ - Clear output buffer, aborting the current output and - discarding all that is in the buffer. - """ - if not self.is_open: - raise PortNotOpenError() - self._port_handle.DiscardOutBuffer() - - def _update_break_state(self): - """ - Set break: Controls TXD. When active, to transmitting is possible. - """ - if not self.is_open: - raise PortNotOpenError() - self._port_handle.BreakState = bool(self._break_state) - - def _update_rts_state(self): - """Set terminal status line: Request To Send""" - if not self.is_open: - raise PortNotOpenError() - self._port_handle.RtsEnable = bool(self._rts_state) - - def _update_dtr_state(self): - """Set terminal status line: Data Terminal Ready""" - if not self.is_open: - raise PortNotOpenError() - self._port_handle.DtrEnable = bool(self._dtr_state) - - @property - def cts(self): - """Read terminal status line: Clear To Send""" - if not self.is_open: - raise PortNotOpenError() - return self._port_handle.CtsHolding - - @property - def dsr(self): - """Read terminal status line: Data Set Ready""" - if not self.is_open: - raise PortNotOpenError() - return self._port_handle.DsrHolding - - @property - def ri(self): - """Read terminal status line: Ring Indicator""" - if not self.is_open: - raise PortNotOpenError() - #~ return self._port_handle.XXX - return False # XXX an error would be better - - @property - def cd(self): - """Read terminal status line: Carrier Detect""" - if not self.is_open: - raise PortNotOpenError() - return self._port_handle.CDHolding - - # - - platform specific - - - - - # none diff --git a/extensions/km-plot/deps/serial/serialjava.py b/extensions/km-plot/deps/serial/serialjava.py deleted file mode 100644 index 0789a78..0000000 --- a/extensions/km-plot/deps/serial/serialjava.py +++ /dev/null @@ -1,251 +0,0 @@ -#!jython -# -# Backend Jython with JavaComm -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2002-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -from __future__ import absolute_import - -from serial.serialutil import * - - -def my_import(name): - mod = __import__(name) - components = name.split('.') - for comp in components[1:]: - mod = getattr(mod, comp) - return mod - - -def detect_java_comm(names): - """try given list of modules and return that imports""" - for name in names: - try: - mod = my_import(name) - mod.SerialPort - return mod - except (ImportError, AttributeError): - pass - raise ImportError("No Java Communications API implementation found") - - -# Java Communications API implementations -# http://mho.republika.pl/java/comm/ - -comm = detect_java_comm([ - 'javax.comm', # Sun/IBM - 'gnu.io', # RXTX -]) - - -def device(portnumber): - """Turn a port number into a device name""" - enum = comm.CommPortIdentifier.getPortIdentifiers() - ports = [] - while enum.hasMoreElements(): - el = enum.nextElement() - if el.getPortType() == comm.CommPortIdentifier.PORT_SERIAL: - ports.append(el) - return ports[portnumber].getName() - - -class Serial(SerialBase): - """\ - Serial port class, implemented with Java Communications API and - thus usable with jython and the appropriate java extension. - """ - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - if type(self._port) == type(''): # strings are taken directly - portId = comm.CommPortIdentifier.getPortIdentifier(self._port) - else: - portId = comm.CommPortIdentifier.getPortIdentifier(device(self._port)) # numbers are transformed to a comport id obj - try: - self.sPort = portId.open("python serial module", 10) - except Exception as msg: - self.sPort = None - raise SerialException("Could not open port: %s" % msg) - self._reconfigurePort() - self._instream = self.sPort.getInputStream() - self._outstream = self.sPort.getOutputStream() - self.is_open = True - - def _reconfigurePort(self): - """Set communication parameters on opened port.""" - if not self.sPort: - raise SerialException("Can only operate on a valid port handle") - - self.sPort.enableReceiveTimeout(30) - if self._bytesize == FIVEBITS: - jdatabits = comm.SerialPort.DATABITS_5 - elif self._bytesize == SIXBITS: - jdatabits = comm.SerialPort.DATABITS_6 - elif self._bytesize == SEVENBITS: - jdatabits = comm.SerialPort.DATABITS_7 - elif self._bytesize == EIGHTBITS: - jdatabits = comm.SerialPort.DATABITS_8 - else: - raise ValueError("unsupported bytesize: %r" % self._bytesize) - - if self._stopbits == STOPBITS_ONE: - jstopbits = comm.SerialPort.STOPBITS_1 - elif self._stopbits == STOPBITS_ONE_POINT_FIVE: - jstopbits = comm.SerialPort.STOPBITS_1_5 - elif self._stopbits == STOPBITS_TWO: - jstopbits = comm.SerialPort.STOPBITS_2 - else: - raise ValueError("unsupported number of stopbits: %r" % self._stopbits) - - if self._parity == PARITY_NONE: - jparity = comm.SerialPort.PARITY_NONE - elif self._parity == PARITY_EVEN: - jparity = comm.SerialPort.PARITY_EVEN - elif self._parity == PARITY_ODD: - jparity = comm.SerialPort.PARITY_ODD - elif self._parity == PARITY_MARK: - jparity = comm.SerialPort.PARITY_MARK - elif self._parity == PARITY_SPACE: - jparity = comm.SerialPort.PARITY_SPACE - else: - raise ValueError("unsupported parity type: %r" % self._parity) - - jflowin = jflowout = 0 - if self._rtscts: - jflowin |= comm.SerialPort.FLOWCONTROL_RTSCTS_IN - jflowout |= comm.SerialPort.FLOWCONTROL_RTSCTS_OUT - if self._xonxoff: - jflowin |= comm.SerialPort.FLOWCONTROL_XONXOFF_IN - jflowout |= comm.SerialPort.FLOWCONTROL_XONXOFF_OUT - - self.sPort.setSerialPortParams(self._baudrate, jdatabits, jstopbits, jparity) - self.sPort.setFlowControlMode(jflowin | jflowout) - - if self._timeout >= 0: - self.sPort.enableReceiveTimeout(int(self._timeout*1000)) - else: - self.sPort.disableReceiveTimeout() - - def close(self): - """Close port""" - if self.is_open: - if self.sPort: - self._instream.close() - self._outstream.close() - self.sPort.close() - self.sPort = None - self.is_open = False - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def in_waiting(self): - """Return the number of characters currently in the input buffer.""" - if not self.sPort: - raise PortNotOpenError() - return self._instream.available() - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self.sPort: - raise PortNotOpenError() - read = bytearray() - if size > 0: - while len(read) < size: - x = self._instream.read() - if x == -1: - if self.timeout >= 0: - break - else: - read.append(x) - return bytes(read) - - def write(self, data): - """Output the given string over the serial port.""" - if not self.sPort: - raise PortNotOpenError() - if not isinstance(data, (bytes, bytearray)): - raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) - self._outstream.write(data) - return len(data) - - def reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self.sPort: - raise PortNotOpenError() - self._instream.skip(self._instream.available()) - - def reset_output_buffer(self): - """\ - Clear output buffer, aborting the current output and - discarding all that is in the buffer. - """ - if not self.sPort: - raise PortNotOpenError() - self._outstream.flush() - - def send_break(self, duration=0.25): - """Send break condition. Timed, returns to idle state after given duration.""" - if not self.sPort: - raise PortNotOpenError() - self.sPort.sendBreak(duration*1000.0) - - def _update_break_state(self): - """Set break: Controls TXD. When active, to transmitting is possible.""" - if self.fd is None: - raise PortNotOpenError() - raise SerialException("The _update_break_state function is not implemented in java.") - - def _update_rts_state(self): - """Set terminal status line: Request To Send""" - if not self.sPort: - raise PortNotOpenError() - self.sPort.setRTS(self._rts_state) - - def _update_dtr_state(self): - """Set terminal status line: Data Terminal Ready""" - if not self.sPort: - raise PortNotOpenError() - self.sPort.setDTR(self._dtr_state) - - @property - def cts(self): - """Read terminal status line: Clear To Send""" - if not self.sPort: - raise PortNotOpenError() - self.sPort.isCTS() - - @property - def dsr(self): - """Read terminal status line: Data Set Ready""" - if not self.sPort: - raise PortNotOpenError() - self.sPort.isDSR() - - @property - def ri(self): - """Read terminal status line: Ring Indicator""" - if not self.sPort: - raise PortNotOpenError() - self.sPort.isRI() - - @property - def cd(self): - """Read terminal status line: Carrier Detect""" - if not self.sPort: - raise PortNotOpenError() - self.sPort.isCD() diff --git a/extensions/km-plot/deps/serial/serialposix.py b/extensions/km-plot/deps/serial/serialposix.py deleted file mode 100644 index 7aceb76..0000000 --- a/extensions/km-plot/deps/serial/serialposix.py +++ /dev/null @@ -1,900 +0,0 @@ -#!/usr/bin/env python -# -# backend for serial IO for POSIX compatible systems, like Linux, OSX -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2020 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -# -# parts based on code from Grant B. Edwards : -# ftp://ftp.visi.com/users/grante/python/PosixSerial.py -# -# references: http://www.easysw.com/~mike/serial/serial.html - -# Collection of port names (was previously used by number_to_device which was -# removed. -# - Linux /dev/ttyS%d (confirmed) -# - cygwin/win32 /dev/com%d (confirmed) -# - openbsd (OpenBSD) /dev/cua%02d -# - bsd*, freebsd* /dev/cuad%d -# - darwin (OS X) /dev/cuad%d -# - netbsd /dev/dty%02d (NetBSD 1.6 testing by Erk) -# - irix (IRIX) /dev/ttyf%d (partially tested) names depending on flow control -# - hp (HP-UX) /dev/tty%dp0 (not tested) -# - sunos (Solaris/SunOS) /dev/tty%c (letters, 'a'..'z') (confirmed) -# - aix (AIX) /dev/tty%d - - -from __future__ import absolute_import - -# pylint: disable=abstract-method -import errno -import fcntl -import os -import select -import struct -import sys -import termios - -import serial -from serial.serialutil import SerialBase, SerialException, to_bytes, \ - PortNotOpenError, SerialTimeoutException, Timeout - - -class PlatformSpecificBase(object): - BAUDRATE_CONSTANTS = {} - - def _set_special_baudrate(self, baudrate): - raise NotImplementedError('non-standard baudrates are not supported on this platform') - - def _set_rs485_mode(self, rs485_settings): - raise NotImplementedError('RS485 not supported on this platform') - - def set_low_latency_mode(self, low_latency_settings): - raise NotImplementedError('Low latency not supported on this platform') - - def _update_break_state(self): - """\ - Set break: Controls TXD. When active, no transmitting is possible. - """ - if self._break_state: - fcntl.ioctl(self.fd, TIOCSBRK) - else: - fcntl.ioctl(self.fd, TIOCCBRK) - - -# some systems support an extra flag to enable the two in POSIX unsupported -# paritiy settings for MARK and SPACE -CMSPAR = 0 # default, for unsupported platforms, override below - -# try to detect the OS so that a device can be selected... -# this code block should supply a device() and set_special_baudrate() function -# for the platform -plat = sys.platform.lower() - -if plat[:5] == 'linux': # Linux (confirmed) # noqa - import array - - # extra termios flags - CMSPAR = 0o10000000000 # Use "stick" (mark/space) parity - - # baudrate ioctls - TCGETS2 = 0x802C542A - TCSETS2 = 0x402C542B - BOTHER = 0o010000 - - # RS485 ioctls - TIOCGRS485 = 0x542E - TIOCSRS485 = 0x542F - SER_RS485_ENABLED = 0b00000001 - SER_RS485_RTS_ON_SEND = 0b00000010 - SER_RS485_RTS_AFTER_SEND = 0b00000100 - SER_RS485_RX_DURING_TX = 0b00010000 - - class PlatformSpecific(PlatformSpecificBase): - BAUDRATE_CONSTANTS = { - 0: 0o000000, # hang up - 50: 0o000001, - 75: 0o000002, - 110: 0o000003, - 134: 0o000004, - 150: 0o000005, - 200: 0o000006, - 300: 0o000007, - 600: 0o000010, - 1200: 0o000011, - 1800: 0o000012, - 2400: 0o000013, - 4800: 0o000014, - 9600: 0o000015, - 19200: 0o000016, - 38400: 0o000017, - 57600: 0o010001, - 115200: 0o010002, - 230400: 0o010003, - 460800: 0o010004, - 500000: 0o010005, - 576000: 0o010006, - 921600: 0o010007, - 1000000: 0o010010, - 1152000: 0o010011, - 1500000: 0o010012, - 2000000: 0o010013, - 2500000: 0o010014, - 3000000: 0o010015, - 3500000: 0o010016, - 4000000: 0o010017 - } - - def set_low_latency_mode(self, low_latency_settings): - buf = array.array('i', [0] * 32) - - try: - # get serial_struct - fcntl.ioctl(self.fd, termios.TIOCGSERIAL, buf) - - # set or unset ASYNC_LOW_LATENCY flag - if low_latency_settings: - buf[4] |= 0x2000 - else: - buf[4] &= ~0x2000 - - # set serial_struct - fcntl.ioctl(self.fd, termios.TIOCSSERIAL, buf) - except IOError as e: - raise ValueError('Failed to update ASYNC_LOW_LATENCY flag to {}: {}'.format(low_latency_settings, e)) - - def _set_special_baudrate(self, baudrate): - # right size is 44 on x86_64, allow for some growth - buf = array.array('i', [0] * 64) - try: - # get serial_struct - fcntl.ioctl(self.fd, TCGETS2, buf) - # set custom speed - buf[2] &= ~termios.CBAUD - buf[2] |= BOTHER - buf[9] = buf[10] = baudrate - - # set serial_struct - fcntl.ioctl(self.fd, TCSETS2, buf) - except IOError as e: - raise ValueError('Failed to set custom baud rate ({}): {}'.format(baudrate, e)) - - def _set_rs485_mode(self, rs485_settings): - buf = array.array('i', [0] * 8) # flags, delaytx, delayrx, padding - try: - fcntl.ioctl(self.fd, TIOCGRS485, buf) - buf[0] |= SER_RS485_ENABLED - if rs485_settings is not None: - if rs485_settings.loopback: - buf[0] |= SER_RS485_RX_DURING_TX - else: - buf[0] &= ~SER_RS485_RX_DURING_TX - if rs485_settings.rts_level_for_tx: - buf[0] |= SER_RS485_RTS_ON_SEND - else: - buf[0] &= ~SER_RS485_RTS_ON_SEND - if rs485_settings.rts_level_for_rx: - buf[0] |= SER_RS485_RTS_AFTER_SEND - else: - buf[0] &= ~SER_RS485_RTS_AFTER_SEND - if rs485_settings.delay_before_tx is not None: - buf[1] = int(rs485_settings.delay_before_tx * 1000) - if rs485_settings.delay_before_rx is not None: - buf[2] = int(rs485_settings.delay_before_rx * 1000) - else: - buf[0] = 0 # clear SER_RS485_ENABLED - fcntl.ioctl(self.fd, TIOCSRS485, buf) - except IOError as e: - raise ValueError('Failed to set RS485 mode: {}'.format(e)) - - -elif plat == 'cygwin': # cygwin/win32 (confirmed) - - class PlatformSpecific(PlatformSpecificBase): - BAUDRATE_CONSTANTS = { - 128000: 0x01003, - 256000: 0x01005, - 500000: 0x01007, - 576000: 0x01008, - 921600: 0x01009, - 1000000: 0x0100a, - 1152000: 0x0100b, - 1500000: 0x0100c, - 2000000: 0x0100d, - 2500000: 0x0100e, - 3000000: 0x0100f - } - - -elif plat[:6] == 'darwin': # OS X - import array - IOSSIOSPEED = 0x80045402 # _IOW('T', 2, speed_t) - - class PlatformSpecific(PlatformSpecificBase): - osx_version = os.uname()[2].split('.') - TIOCSBRK = 0x2000747B # _IO('t', 123) - TIOCCBRK = 0x2000747A # _IO('t', 122) - - # Tiger or above can support arbitrary serial speeds - if int(osx_version[0]) >= 8: - def _set_special_baudrate(self, baudrate): - # use IOKit-specific call to set up high speeds - buf = array.array('i', [baudrate]) - fcntl.ioctl(self.fd, IOSSIOSPEED, buf, 1) - - def _update_break_state(self): - """\ - Set break: Controls TXD. When active, no transmitting is possible. - """ - if self._break_state: - fcntl.ioctl(self.fd, PlatformSpecific.TIOCSBRK) - else: - fcntl.ioctl(self.fd, PlatformSpecific.TIOCCBRK) - -elif plat[:3] == 'bsd' or \ - plat[:7] == 'freebsd' or \ - plat[:6] == 'netbsd' or \ - plat[:7] == 'openbsd': - - class ReturnBaudrate(object): - def __getitem__(self, key): - return key - - class PlatformSpecific(PlatformSpecificBase): - # Only tested on FreeBSD: - # The baud rate may be passed in as - # a literal value. - BAUDRATE_CONSTANTS = ReturnBaudrate() - - TIOCSBRK = 0x2000747B # _IO('t', 123) - TIOCCBRK = 0x2000747A # _IO('t', 122) - - - def _update_break_state(self): - """\ - Set break: Controls TXD. When active, no transmitting is possible. - """ - if self._break_state: - fcntl.ioctl(self.fd, PlatformSpecific.TIOCSBRK) - else: - fcntl.ioctl(self.fd, PlatformSpecific.TIOCCBRK) - -else: - class PlatformSpecific(PlatformSpecificBase): - pass - - -# load some constants for later use. -# try to use values from termios, use defaults from linux otherwise -TIOCMGET = getattr(termios, 'TIOCMGET', 0x5415) -TIOCMBIS = getattr(termios, 'TIOCMBIS', 0x5416) -TIOCMBIC = getattr(termios, 'TIOCMBIC', 0x5417) -TIOCMSET = getattr(termios, 'TIOCMSET', 0x5418) - -# TIOCM_LE = getattr(termios, 'TIOCM_LE', 0x001) -TIOCM_DTR = getattr(termios, 'TIOCM_DTR', 0x002) -TIOCM_RTS = getattr(termios, 'TIOCM_RTS', 0x004) -# TIOCM_ST = getattr(termios, 'TIOCM_ST', 0x008) -# TIOCM_SR = getattr(termios, 'TIOCM_SR', 0x010) - -TIOCM_CTS = getattr(termios, 'TIOCM_CTS', 0x020) -TIOCM_CAR = getattr(termios, 'TIOCM_CAR', 0x040) -TIOCM_RNG = getattr(termios, 'TIOCM_RNG', 0x080) -TIOCM_DSR = getattr(termios, 'TIOCM_DSR', 0x100) -TIOCM_CD = getattr(termios, 'TIOCM_CD', TIOCM_CAR) -TIOCM_RI = getattr(termios, 'TIOCM_RI', TIOCM_RNG) -# TIOCM_OUT1 = getattr(termios, 'TIOCM_OUT1', 0x2000) -# TIOCM_OUT2 = getattr(termios, 'TIOCM_OUT2', 0x4000) -if hasattr(termios, 'TIOCINQ'): - TIOCINQ = termios.TIOCINQ -else: - TIOCINQ = getattr(termios, 'FIONREAD', 0x541B) -TIOCOUTQ = getattr(termios, 'TIOCOUTQ', 0x5411) - -TIOCM_zero_str = struct.pack('I', 0) -TIOCM_RTS_str = struct.pack('I', TIOCM_RTS) -TIOCM_DTR_str = struct.pack('I', TIOCM_DTR) - -TIOCSBRK = getattr(termios, 'TIOCSBRK', 0x5427) -TIOCCBRK = getattr(termios, 'TIOCCBRK', 0x5428) - - -class Serial(SerialBase, PlatformSpecific): - """\ - Serial port class POSIX implementation. Serial port configuration is - done with termios and fcntl. Runs on Linux and many other Un*x like - systems. - """ - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened.""" - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - self.fd = None - # open - try: - self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK) - except OSError as msg: - self.fd = None - raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg)) - #~ fcntl.fcntl(self.fd, fcntl.F_SETFL, 0) # set blocking - - self.pipe_abort_read_r, self.pipe_abort_read_w = None, None - self.pipe_abort_write_r, self.pipe_abort_write_w = None, None - - try: - self._reconfigure_port(force_update=True) - - try: - if not self._dsrdtr: - self._update_dtr_state() - if not self._rtscts: - self._update_rts_state() - except IOError as e: - # ignore Invalid argument and Inappropriate ioctl - if e.errno not in (errno.EINVAL, errno.ENOTTY): - raise - - self._reset_input_buffer() - - self.pipe_abort_read_r, self.pipe_abort_read_w = os.pipe() - self.pipe_abort_write_r, self.pipe_abort_write_w = os.pipe() - fcntl.fcntl(self.pipe_abort_read_r, fcntl.F_SETFL, os.O_NONBLOCK) - fcntl.fcntl(self.pipe_abort_write_r, fcntl.F_SETFL, os.O_NONBLOCK) - except BaseException: - try: - os.close(self.fd) - except Exception: - # ignore any exception when closing the port - # also to keep original exception that happened when setting up - pass - self.fd = None - - if self.pipe_abort_read_w is not None: - os.close(self.pipe_abort_read_w) - self.pipe_abort_read_w = None - if self.pipe_abort_read_r is not None: - os.close(self.pipe_abort_read_r) - self.pipe_abort_read_r = None - if self.pipe_abort_write_w is not None: - os.close(self.pipe_abort_write_w) - self.pipe_abort_write_w = None - if self.pipe_abort_write_r is not None: - os.close(self.pipe_abort_write_r) - self.pipe_abort_write_r = None - - raise - - self.is_open = True - - def _reconfigure_port(self, force_update=False): - """Set communication parameters on opened port.""" - if self.fd is None: - raise SerialException("Can only operate on a valid file descriptor") - - # if exclusive lock is requested, create it before we modify anything else - if self._exclusive is not None: - if self._exclusive: - try: - fcntl.flock(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB) - except IOError as msg: - raise SerialException(msg.errno, "Could not exclusively lock port {}: {}".format(self._port, msg)) - else: - fcntl.flock(self.fd, fcntl.LOCK_UN) - - custom_baud = None - - vmin = vtime = 0 # timeout is done via select - if self._inter_byte_timeout is not None: - vmin = 1 - vtime = int(self._inter_byte_timeout * 10) - try: - orig_attr = termios.tcgetattr(self.fd) - iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr - except termios.error as msg: # if a port is nonexistent but has a /dev file, it'll fail here - raise SerialException("Could not configure port: {}".format(msg)) - # set up raw mode / no echo / binary - cflag |= (termios.CLOCAL | termios.CREAD) - lflag &= ~(termios.ICANON | termios.ECHO | termios.ECHOE | - termios.ECHOK | termios.ECHONL | - termios.ISIG | termios.IEXTEN) # |termios.ECHOPRT - for flag in ('ECHOCTL', 'ECHOKE'): # netbsd workaround for Erk - if hasattr(termios, flag): - lflag &= ~getattr(termios, flag) - - oflag &= ~(termios.OPOST | termios.ONLCR | termios.OCRNL) - iflag &= ~(termios.INLCR | termios.IGNCR | termios.ICRNL | termios.IGNBRK) - if hasattr(termios, 'IUCLC'): - iflag &= ~termios.IUCLC - if hasattr(termios, 'PARMRK'): - iflag &= ~termios.PARMRK - - # setup baud rate - try: - ispeed = ospeed = getattr(termios, 'B{}'.format(self._baudrate)) - except AttributeError: - try: - ispeed = ospeed = self.BAUDRATE_CONSTANTS[self._baudrate] - except KeyError: - #~ raise ValueError('Invalid baud rate: %r' % self._baudrate) - - # See if BOTHER is defined for this platform; if it is, use - # this for a speed not defined in the baudrate constants list. - try: - ispeed = ospeed = BOTHER - except NameError: - # may need custom baud rate, it isn't in our list. - ispeed = ospeed = getattr(termios, 'B38400') - - try: - custom_baud = int(self._baudrate) # store for later - except ValueError: - raise ValueError('Invalid baud rate: {!r}'.format(self._baudrate)) - else: - if custom_baud < 0: - raise ValueError('Invalid baud rate: {!r}'.format(self._baudrate)) - - # setup char len - cflag &= ~termios.CSIZE - if self._bytesize == 8: - cflag |= termios.CS8 - elif self._bytesize == 7: - cflag |= termios.CS7 - elif self._bytesize == 6: - cflag |= termios.CS6 - elif self._bytesize == 5: - cflag |= termios.CS5 - else: - raise ValueError('Invalid char len: {!r}'.format(self._bytesize)) - # setup stop bits - if self._stopbits == serial.STOPBITS_ONE: - cflag &= ~(termios.CSTOPB) - elif self._stopbits == serial.STOPBITS_ONE_POINT_FIVE: - cflag |= (termios.CSTOPB) # XXX same as TWO.. there is no POSIX support for 1.5 - elif self._stopbits == serial.STOPBITS_TWO: - cflag |= (termios.CSTOPB) - else: - raise ValueError('Invalid stop bit specification: {!r}'.format(self._stopbits)) - # setup parity - iflag &= ~(termios.INPCK | termios.ISTRIP) - if self._parity == serial.PARITY_NONE: - cflag &= ~(termios.PARENB | termios.PARODD | CMSPAR) - elif self._parity == serial.PARITY_EVEN: - cflag &= ~(termios.PARODD | CMSPAR) - cflag |= (termios.PARENB) - elif self._parity == serial.PARITY_ODD: - cflag &= ~CMSPAR - cflag |= (termios.PARENB | termios.PARODD) - elif self._parity == serial.PARITY_MARK and CMSPAR: - cflag |= (termios.PARENB | CMSPAR | termios.PARODD) - elif self._parity == serial.PARITY_SPACE and CMSPAR: - cflag |= (termios.PARENB | CMSPAR) - cflag &= ~(termios.PARODD) - else: - raise ValueError('Invalid parity: {!r}'.format(self._parity)) - # setup flow control - # xonxoff - if hasattr(termios, 'IXANY'): - if self._xonxoff: - iflag |= (termios.IXON | termios.IXOFF) # |termios.IXANY) - else: - iflag &= ~(termios.IXON | termios.IXOFF | termios.IXANY) - else: - if self._xonxoff: - iflag |= (termios.IXON | termios.IXOFF) - else: - iflag &= ~(termios.IXON | termios.IXOFF) - # rtscts - if hasattr(termios, 'CRTSCTS'): - if self._rtscts: - cflag |= (termios.CRTSCTS) - else: - cflag &= ~(termios.CRTSCTS) - elif hasattr(termios, 'CNEW_RTSCTS'): # try it with alternate constant name - if self._rtscts: - cflag |= (termios.CNEW_RTSCTS) - else: - cflag &= ~(termios.CNEW_RTSCTS) - # XXX should there be a warning if setting up rtscts (and xonxoff etc) fails?? - - # buffer - # vmin "minimal number of characters to be read. 0 for non blocking" - if vmin < 0 or vmin > 255: - raise ValueError('Invalid vmin: {!r}'.format(vmin)) - cc[termios.VMIN] = vmin - # vtime - if vtime < 0 or vtime > 255: - raise ValueError('Invalid vtime: {!r}'.format(vtime)) - cc[termios.VTIME] = vtime - # activate settings - if force_update or [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] != orig_attr: - termios.tcsetattr( - self.fd, - termios.TCSANOW, - [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]) - - # apply custom baud rate, if any - if custom_baud is not None: - self._set_special_baudrate(custom_baud) - - if self._rs485_mode is not None: - self._set_rs485_mode(self._rs485_mode) - - def close(self): - """Close port""" - if self.is_open: - if self.fd is not None: - os.close(self.fd) - self.fd = None - os.close(self.pipe_abort_read_w) - os.close(self.pipe_abort_read_r) - os.close(self.pipe_abort_write_w) - os.close(self.pipe_abort_write_r) - self.pipe_abort_read_r, self.pipe_abort_read_w = None, None - self.pipe_abort_write_r, self.pipe_abort_write_w = None, None - self.is_open = False - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def in_waiting(self): - """Return the number of bytes currently in the input buffer.""" - #~ s = fcntl.ioctl(self.fd, termios.FIONREAD, TIOCM_zero_str) - s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str) - return struct.unpack('I', s)[0] - - # select based implementation, proved to work on many systems - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self.is_open: - raise PortNotOpenError() - read = bytearray() - timeout = Timeout(self._timeout) - while len(read) < size: - try: - ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left()) - if self.pipe_abort_read_r in ready: - os.read(self.pipe_abort_read_r, 1000) - break - # If select was used with a timeout, and the timeout occurs, it - # returns with empty lists -> thus abort read operation. - # For timeout == 0 (non-blocking operation) also abort when - # there is nothing to read. - if not ready: - break # timeout - buf = os.read(self.fd, size - len(read)) - except OSError as e: - # this is for Python 3.x where select.error is a subclass of - # OSError ignore BlockingIOErrors and EINTR. other errors are shown - # https://www.python.org/dev/peps/pep-0475. - if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): - raise SerialException('read failed: {}'.format(e)) - except select.error as e: - # this is for Python 2.x - # ignore BlockingIOErrors and EINTR. all errors are shown - # see also http://www.python.org/dev/peps/pep-3151/#select - if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): - raise SerialException('read failed: {}'.format(e)) - else: - # read should always return some data as select reported it was - # ready to read when we get to this point. - if not buf: - # Disconnected devices, at least on Linux, show the - # behavior that they are always ready to read immediately - # but reading returns nothing. - raise SerialException( - 'device reports readiness to read but returned no data ' - '(device disconnected or multiple access on port?)') - read.extend(buf) - - if timeout.expired(): - break - return bytes(read) - - def cancel_read(self): - if self.is_open: - os.write(self.pipe_abort_read_w, b"x") - - def cancel_write(self): - if self.is_open: - os.write(self.pipe_abort_write_w, b"x") - - def write(self, data): - """Output the given byte string over the serial port.""" - if not self.is_open: - raise PortNotOpenError() - d = to_bytes(data) - tx_len = length = len(d) - timeout = Timeout(self._write_timeout) - while tx_len > 0: - try: - n = os.write(self.fd, d) - if timeout.is_non_blocking: - # Zero timeout indicates non-blocking - simply return the - # number of bytes of data actually written - return n - elif not timeout.is_infinite: - # when timeout is set, use select to wait for being ready - # with the time left as timeout - if timeout.expired(): - raise SerialTimeoutException('Write timeout') - abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], timeout.time_left()) - if abort: - os.read(self.pipe_abort_write_r, 1000) - break - if not ready: - raise SerialTimeoutException('Write timeout') - else: - assert timeout.time_left() is None - # wait for write operation - abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], None) - if abort: - os.read(self.pipe_abort_write_r, 1) - break - if not ready: - raise SerialException('write failed (select)') - d = d[n:] - tx_len -= n - except SerialException: - raise - except OSError as e: - # this is for Python 3.x where select.error is a subclass of - # OSError ignore BlockingIOErrors and EINTR. other errors are shown - # https://www.python.org/dev/peps/pep-0475. - if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): - raise SerialException('write failed: {}'.format(e)) - except select.error as e: - # this is for Python 2.x - # ignore BlockingIOErrors and EINTR. all errors are shown - # see also http://www.python.org/dev/peps/pep-3151/#select - if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): - raise SerialException('write failed: {}'.format(e)) - if not timeout.is_non_blocking and timeout.expired(): - raise SerialTimeoutException('Write timeout') - return length - len(d) - - def flush(self): - """\ - Flush of file like objects. In this case, wait until all data - is written. - """ - if not self.is_open: - raise PortNotOpenError() - termios.tcdrain(self.fd) - - def _reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - termios.tcflush(self.fd, termios.TCIFLUSH) - - def reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self.is_open: - raise PortNotOpenError() - self._reset_input_buffer() - - def reset_output_buffer(self): - """\ - Clear output buffer, aborting the current output and discarding all - that is in the buffer. - """ - if not self.is_open: - raise PortNotOpenError() - termios.tcflush(self.fd, termios.TCOFLUSH) - - def send_break(self, duration=0.25): - """\ - Send break condition. Timed, returns to idle state after given - duration. - """ - if not self.is_open: - raise PortNotOpenError() - termios.tcsendbreak(self.fd, int(duration / 0.25)) - - def _update_rts_state(self): - """Set terminal status line: Request To Send""" - if self._rts_state: - fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str) - else: - fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str) - - def _update_dtr_state(self): - """Set terminal status line: Data Terminal Ready""" - if self._dtr_state: - fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str) - else: - fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str) - - @property - def cts(self): - """Read terminal status line: Clear To Send""" - if not self.is_open: - raise PortNotOpenError() - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I', s)[0] & TIOCM_CTS != 0 - - @property - def dsr(self): - """Read terminal status line: Data Set Ready""" - if not self.is_open: - raise PortNotOpenError() - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I', s)[0] & TIOCM_DSR != 0 - - @property - def ri(self): - """Read terminal status line: Ring Indicator""" - if not self.is_open: - raise PortNotOpenError() - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I', s)[0] & TIOCM_RI != 0 - - @property - def cd(self): - """Read terminal status line: Carrier Detect""" - if not self.is_open: - raise PortNotOpenError() - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I', s)[0] & TIOCM_CD != 0 - - # - - platform specific - - - - - - @property - def out_waiting(self): - """Return the number of bytes currently in the output buffer.""" - #~ s = fcntl.ioctl(self.fd, termios.FIONREAD, TIOCM_zero_str) - s = fcntl.ioctl(self.fd, TIOCOUTQ, TIOCM_zero_str) - return struct.unpack('I', s)[0] - - def fileno(self): - """\ - For easier use of the serial port instance with select. - WARNING: this function is not portable to different platforms! - """ - if not self.is_open: - raise PortNotOpenError() - return self.fd - - def set_input_flow_control(self, enable=True): - """\ - Manually control flow - when software flow control is enabled. - This will send XON (true) or XOFF (false) to the other device. - WARNING: this function is not portable to different platforms! - """ - if not self.is_open: - raise PortNotOpenError() - if enable: - termios.tcflow(self.fd, termios.TCION) - else: - termios.tcflow(self.fd, termios.TCIOFF) - - def set_output_flow_control(self, enable=True): - """\ - Manually control flow of outgoing data - when hardware or software flow - control is enabled. - WARNING: this function is not portable to different platforms! - """ - if not self.is_open: - raise PortNotOpenError() - if enable: - termios.tcflow(self.fd, termios.TCOON) - else: - termios.tcflow(self.fd, termios.TCOOFF) - - def nonblocking(self): - """DEPRECATED - has no use""" - import warnings - warnings.warn("nonblocking() has no effect, already nonblocking", DeprecationWarning) - - -class PosixPollSerial(Serial): - """\ - Poll based read implementation. Not all systems support poll properly. - However this one has better handling of errors, such as a device - disconnecting while it's in use (e.g. USB-serial unplugged). - """ - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self.is_open: - raise PortNotOpenError() - read = bytearray() - timeout = Timeout(self._timeout) - poll = select.poll() - poll.register(self.fd, select.POLLIN | select.POLLERR | select.POLLHUP | select.POLLNVAL) - poll.register(self.pipe_abort_read_r, select.POLLIN | select.POLLERR | select.POLLHUP | select.POLLNVAL) - if size > 0: - while len(read) < size: - # print "\tread(): size",size, "have", len(read) #debug - # wait until device becomes ready to read (or something fails) - for fd, event in poll.poll(None if timeout.is_infinite else (timeout.time_left() * 1000)): - if fd == self.pipe_abort_read_r: - break - if event & (select.POLLERR | select.POLLHUP | select.POLLNVAL): - raise SerialException('device reports error (poll)') - # we don't care if it is select.POLLIN or timeout, that's - # handled below - if fd == self.pipe_abort_read_r: - os.read(self.pipe_abort_read_r, 1000) - break - buf = os.read(self.fd, size - len(read)) - read.extend(buf) - if timeout.expired() \ - or (self._inter_byte_timeout is not None and self._inter_byte_timeout > 0) and not buf: - break # early abort on timeout - return bytes(read) - - -class VTIMESerial(Serial): - """\ - Implement timeout using vtime of tty device instead of using select. - This means that no inter character timeout can be specified and that - the error handling is degraded. - - Overall timeout is disabled when inter-character timeout is used. - - Note that this implementation does NOT support cancel_read(), it will - just ignore that. - """ - - def _reconfigure_port(self, force_update=True): - """Set communication parameters on opened port.""" - super(VTIMESerial, self)._reconfigure_port() - fcntl.fcntl(self.fd, fcntl.F_SETFL, 0) # clear O_NONBLOCK - - if self._inter_byte_timeout is not None: - vmin = 1 - vtime = int(self._inter_byte_timeout * 10) - elif self._timeout is None: - vmin = 1 - vtime = 0 - else: - vmin = 0 - vtime = int(self._timeout * 10) - try: - orig_attr = termios.tcgetattr(self.fd) - iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr - except termios.error as msg: # if a port is nonexistent but has a /dev file, it'll fail here - raise serial.SerialException("Could not configure port: {}".format(msg)) - - if vtime < 0 or vtime > 255: - raise ValueError('Invalid vtime: {!r}'.format(vtime)) - cc[termios.VTIME] = vtime - cc[termios.VMIN] = vmin - - termios.tcsetattr( - self.fd, - termios.TCSANOW, - [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]) - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self.is_open: - raise PortNotOpenError() - read = bytearray() - while len(read) < size: - buf = os.read(self.fd, size - len(read)) - if not buf: - break - read.extend(buf) - return bytes(read) - - # hack to make hasattr return false - cancel_read = property() diff --git a/extensions/km-plot/deps/serial/serialutil.py b/extensions/km-plot/deps/serial/serialutil.py deleted file mode 100644 index 789219e..0000000 --- a/extensions/km-plot/deps/serial/serialutil.py +++ /dev/null @@ -1,697 +0,0 @@ -#! python -# -# Base class and support functions used by various backends. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2020 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -from __future__ import absolute_import - -import io -import time - -# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)`` -# isn't returning the contents (very unfortunate). Therefore we need special -# cases and test for it. Ensure that there is a ``memoryview`` object for older -# Python versions. This is easier than making every test dependent on its -# existence. -try: - memoryview -except (NameError, AttributeError): - # implementation does not matter as we do not really use it. - # it just must not inherit from something else we might care for. - class memoryview(object): # pylint: disable=redefined-builtin,invalid-name - pass - -try: - unicode -except (NameError, AttributeError): - unicode = str # for Python 3, pylint: disable=redefined-builtin,invalid-name - -try: - basestring -except (NameError, AttributeError): - basestring = (str,) # for Python 3, pylint: disable=redefined-builtin,invalid-name - - -# "for byte in data" fails for python3 as it returns ints instead of bytes -def iterbytes(b): - """Iterate over bytes, returning bytes instead of ints (python3)""" - if isinstance(b, memoryview): - b = b.tobytes() - i = 0 - while True: - a = b[i:i + 1] - i += 1 - if a: - yield a - else: - break - - -# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11' -# so a simple ``bytes(sequence)`` doesn't work for all versions -def to_bytes(seq): - """convert a sequence to a bytes type""" - if isinstance(seq, bytes): - return seq - elif isinstance(seq, bytearray): - return bytes(seq) - elif isinstance(seq, memoryview): - return seq.tobytes() - elif isinstance(seq, unicode): - raise TypeError('unicode strings are not supported, please encode to bytes: {!r}'.format(seq)) - else: - # handle list of integers and bytes (one or more items) for Python 2 and 3 - return bytes(bytearray(seq)) - - -# create control bytes -XON = to_bytes([17]) -XOFF = to_bytes([19]) - -CR = to_bytes([13]) -LF = to_bytes([10]) - - -PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S' -STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2) -FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8) - -PARITY_NAMES = { - PARITY_NONE: 'None', - PARITY_EVEN: 'Even', - PARITY_ODD: 'Odd', - PARITY_MARK: 'Mark', - PARITY_SPACE: 'Space', -} - - -class SerialException(IOError): - """Base class for serial port related exceptions.""" - - -class SerialTimeoutException(SerialException): - """Write timeouts give an exception""" - - -class PortNotOpenError(SerialException): - """Port is not open""" - def __init__(self): - super(PortNotOpenError, self).__init__('Attempting to use a port that is not open') - - -class Timeout(object): - """\ - Abstraction for timeout operations. Using time.monotonic() if available - or time.time() in all other cases. - - The class can also be initialized with 0 or None, in order to support - non-blocking and fully blocking I/O operations. The attributes - is_non_blocking and is_infinite are set accordingly. - """ - if hasattr(time, 'monotonic'): - # Timeout implementation with time.monotonic(). This function is only - # supported by Python 3.3 and above. It returns a time in seconds - # (float) just as time.time(), but is not affected by system clock - # adjustments. - TIME = time.monotonic - else: - # Timeout implementation with time.time(). This is compatible with all - # Python versions but has issues if the clock is adjusted while the - # timeout is running. - TIME = time.time - - def __init__(self, duration): - """Initialize a timeout with given duration""" - self.is_infinite = (duration is None) - self.is_non_blocking = (duration == 0) - self.duration = duration - if duration is not None: - self.target_time = self.TIME() + duration - else: - self.target_time = None - - def expired(self): - """Return a boolean, telling if the timeout has expired""" - return self.target_time is not None and self.time_left() <= 0 - - def time_left(self): - """Return how many seconds are left until the timeout expires""" - if self.is_non_blocking: - return 0 - elif self.is_infinite: - return None - else: - delta = self.target_time - self.TIME() - if delta > self.duration: - # clock jumped, recalculate - self.target_time = self.TIME() + self.duration - return self.duration - else: - return max(0, delta) - - def restart(self, duration): - """\ - Restart a timeout, only supported if a timeout was already set up - before. - """ - self.duration = duration - self.target_time = self.TIME() + duration - - -class SerialBase(io.RawIOBase): - """\ - Serial port base class. Provides __init__ function and properties to - get/set port settings. - """ - - # default values, may be overridden in subclasses that do not support all values - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, - 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, - 3000000, 3500000, 4000000) - BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS) - PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE) - STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO) - - def __init__(self, - port=None, - baudrate=9600, - bytesize=EIGHTBITS, - parity=PARITY_NONE, - stopbits=STOPBITS_ONE, - timeout=None, - xonxoff=False, - rtscts=False, - write_timeout=None, - dsrdtr=False, - inter_byte_timeout=None, - exclusive=None, - **kwargs): - """\ - Initialize comm port object. If a "port" is given, then the port will be - opened immediately. Otherwise a Serial port object in closed state - is returned. - """ - - self.is_open = False - self.portstr = None - self.name = None - # correct values are assigned below through properties - self._port = None - self._baudrate = None - self._bytesize = None - self._parity = None - self._stopbits = None - self._timeout = None - self._write_timeout = None - self._xonxoff = None - self._rtscts = None - self._dsrdtr = None - self._inter_byte_timeout = None - self._rs485_mode = None # disabled by default - self._rts_state = True - self._dtr_state = True - self._break_state = False - self._exclusive = None - - # assign values using get/set methods using the properties feature - self.port = port - self.baudrate = baudrate - self.bytesize = bytesize - self.parity = parity - self.stopbits = stopbits - self.timeout = timeout - self.write_timeout = write_timeout - self.xonxoff = xonxoff - self.rtscts = rtscts - self.dsrdtr = dsrdtr - self.inter_byte_timeout = inter_byte_timeout - self.exclusive = exclusive - - # watch for backward compatible kwargs - if 'writeTimeout' in kwargs: - self.write_timeout = kwargs.pop('writeTimeout') - if 'interCharTimeout' in kwargs: - self.inter_byte_timeout = kwargs.pop('interCharTimeout') - if kwargs: - raise ValueError('unexpected keyword arguments: {!r}'.format(kwargs)) - - if port is not None: - self.open() - - # - - - - - - - - - - - - - - - - - - - - - - - - - - # to be implemented by subclasses: - # def open(self): - # def close(self): - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def port(self): - """\ - Get the current port setting. The value that was passed on init or using - setPort() is passed back. - """ - return self._port - - @port.setter - def port(self, port): - """\ - Change the port. - """ - if port is not None and not isinstance(port, basestring): - raise ValueError('"port" must be None or a string, not {}'.format(type(port))) - was_open = self.is_open - if was_open: - self.close() - self.portstr = port - self._port = port - self.name = self.portstr - if was_open: - self.open() - - @property - def baudrate(self): - """Get the current baud rate setting.""" - return self._baudrate - - @baudrate.setter - def baudrate(self, baudrate): - """\ - Change baud rate. It raises a ValueError if the port is open and the - baud rate is not possible. If the port is closed, then the value is - accepted and the exception is raised when the port is opened. - """ - try: - b = int(baudrate) - except TypeError: - raise ValueError("Not a valid baudrate: {!r}".format(baudrate)) - else: - if b < 0: - raise ValueError("Not a valid baudrate: {!r}".format(baudrate)) - self._baudrate = b - if self.is_open: - self._reconfigure_port() - - @property - def bytesize(self): - """Get the current byte size setting.""" - return self._bytesize - - @bytesize.setter - def bytesize(self, bytesize): - """Change byte size.""" - if bytesize not in self.BYTESIZES: - raise ValueError("Not a valid byte size: {!r}".format(bytesize)) - self._bytesize = bytesize - if self.is_open: - self._reconfigure_port() - - @property - def exclusive(self): - """Get the current exclusive access setting.""" - return self._exclusive - - @exclusive.setter - def exclusive(self, exclusive): - """Change the exclusive access setting.""" - self._exclusive = exclusive - if self.is_open: - self._reconfigure_port() - - @property - def parity(self): - """Get the current parity setting.""" - return self._parity - - @parity.setter - def parity(self, parity): - """Change parity setting.""" - if parity not in self.PARITIES: - raise ValueError("Not a valid parity: {!r}".format(parity)) - self._parity = parity - if self.is_open: - self._reconfigure_port() - - @property - def stopbits(self): - """Get the current stop bits setting.""" - return self._stopbits - - @stopbits.setter - def stopbits(self, stopbits): - """Change stop bits size.""" - if stopbits not in self.STOPBITS: - raise ValueError("Not a valid stop bit size: {!r}".format(stopbits)) - self._stopbits = stopbits - if self.is_open: - self._reconfigure_port() - - @property - def timeout(self): - """Get the current timeout setting.""" - return self._timeout - - @timeout.setter - def timeout(self, timeout): - """Change timeout setting.""" - if timeout is not None: - try: - timeout + 1 # test if it's a number, will throw a TypeError if not... - except TypeError: - raise ValueError("Not a valid timeout: {!r}".format(timeout)) - if timeout < 0: - raise ValueError("Not a valid timeout: {!r}".format(timeout)) - self._timeout = timeout - if self.is_open: - self._reconfigure_port() - - @property - def write_timeout(self): - """Get the current timeout setting.""" - return self._write_timeout - - @write_timeout.setter - def write_timeout(self, timeout): - """Change timeout setting.""" - if timeout is not None: - if timeout < 0: - raise ValueError("Not a valid timeout: {!r}".format(timeout)) - try: - timeout + 1 # test if it's a number, will throw a TypeError if not... - except TypeError: - raise ValueError("Not a valid timeout: {!r}".format(timeout)) - - self._write_timeout = timeout - if self.is_open: - self._reconfigure_port() - - @property - def inter_byte_timeout(self): - """Get the current inter-character timeout setting.""" - return self._inter_byte_timeout - - @inter_byte_timeout.setter - def inter_byte_timeout(self, ic_timeout): - """Change inter-byte timeout setting.""" - if ic_timeout is not None: - if ic_timeout < 0: - raise ValueError("Not a valid timeout: {!r}".format(ic_timeout)) - try: - ic_timeout + 1 # test if it's a number, will throw a TypeError if not... - except TypeError: - raise ValueError("Not a valid timeout: {!r}".format(ic_timeout)) - - self._inter_byte_timeout = ic_timeout - if self.is_open: - self._reconfigure_port() - - @property - def xonxoff(self): - """Get the current XON/XOFF setting.""" - return self._xonxoff - - @xonxoff.setter - def xonxoff(self, xonxoff): - """Change XON/XOFF setting.""" - self._xonxoff = xonxoff - if self.is_open: - self._reconfigure_port() - - @property - def rtscts(self): - """Get the current RTS/CTS flow control setting.""" - return self._rtscts - - @rtscts.setter - def rtscts(self, rtscts): - """Change RTS/CTS flow control setting.""" - self._rtscts = rtscts - if self.is_open: - self._reconfigure_port() - - @property - def dsrdtr(self): - """Get the current DSR/DTR flow control setting.""" - return self._dsrdtr - - @dsrdtr.setter - def dsrdtr(self, dsrdtr=None): - """Change DsrDtr flow control setting.""" - if dsrdtr is None: - # if not set, keep backwards compatibility and follow rtscts setting - self._dsrdtr = self._rtscts - else: - # if defined independently, follow its value - self._dsrdtr = dsrdtr - if self.is_open: - self._reconfigure_port() - - @property - def rts(self): - return self._rts_state - - @rts.setter - def rts(self, value): - self._rts_state = value - if self.is_open: - self._update_rts_state() - - @property - def dtr(self): - return self._dtr_state - - @dtr.setter - def dtr(self, value): - self._dtr_state = value - if self.is_open: - self._update_dtr_state() - - @property - def break_condition(self): - return self._break_state - - @break_condition.setter - def break_condition(self, value): - self._break_state = value - if self.is_open: - self._update_break_state() - - # - - - - - - - - - - - - - - - - - - - - - - - - - # functions useful for RS-485 adapters - - @property - def rs485_mode(self): - """\ - Enable RS485 mode and apply new settings, set to None to disable. - See serial.rs485.RS485Settings for more info about the value. - """ - return self._rs485_mode - - @rs485_mode.setter - def rs485_mode(self, rs485_settings): - self._rs485_mode = rs485_settings - if self.is_open: - self._reconfigure_port() - - # - - - - - - - - - - - - - - - - - - - - - - - - - - _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff', - 'dsrdtr', 'rtscts', 'timeout', 'write_timeout', - 'inter_byte_timeout') - - def get_settings(self): - """\ - Get current port settings as a dictionary. For use with - apply_settings(). - """ - return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS]) - - def apply_settings(self, d): - """\ - Apply stored settings from a dictionary returned from - get_settings(). It's allowed to delete keys from the dictionary. These - values will simply left unchanged. - """ - for key in self._SAVED_SETTINGS: - if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value - setattr(self, key, d[key]) # set non "_" value to use properties write function - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def __repr__(self): - """String representation of the current port settings and its state.""" - return '{name}(port={p.portstr!r}, ' \ - 'baudrate={p.baudrate!r}, bytesize={p.bytesize!r}, parity={p.parity!r}, ' \ - 'stopbits={p.stopbits!r}, timeout={p.timeout!r}, xonxoff={p.xonxoff!r}, ' \ - 'rtscts={p.rtscts!r}, dsrdtr={p.dsrdtr!r})'.format( - name=self.__class__.__name__, id=id(self), p=self) - - # - - - - - - - - - - - - - - - - - - - - - - - - - # compatibility with io library - # pylint: disable=invalid-name,missing-docstring - - def readable(self): - return True - - def writable(self): - return True - - def seekable(self): - return False - - def readinto(self, b): - data = self.read(len(b)) - n = len(data) - try: - b[:n] = data - except TypeError as err: - import array - if not isinstance(b, array.array): - raise err - b[:n] = array.array('b', data) - return n - - # - - - - - - - - - - - - - - - - - - - - - - - - - # context manager - - def __enter__(self): - if self._port is not None and not self.is_open: - self.open() - return self - - def __exit__(self, *args, **kwargs): - self.close() - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def send_break(self, duration=0.25): - """\ - Send break condition. Timed, returns to idle state after given - duration. - """ - if not self.is_open: - raise PortNotOpenError() - self.break_condition = True - time.sleep(duration) - self.break_condition = False - - # - - - - - - - - - - - - - - - - - - - - - - - - - # backwards compatibility / deprecated functions - - def flushInput(self): - self.reset_input_buffer() - - def flushOutput(self): - self.reset_output_buffer() - - def inWaiting(self): - return self.in_waiting - - def sendBreak(self, duration=0.25): - self.send_break(duration) - - def setRTS(self, value=1): - self.rts = value - - def setDTR(self, value=1): - self.dtr = value - - def getCTS(self): - return self.cts - - def getDSR(self): - return self.dsr - - def getRI(self): - return self.ri - - def getCD(self): - return self.cd - - def setPort(self, port): - self.port = port - - @property - def writeTimeout(self): - return self.write_timeout - - @writeTimeout.setter - def writeTimeout(self, timeout): - self.write_timeout = timeout - - @property - def interCharTimeout(self): - return self.inter_byte_timeout - - @interCharTimeout.setter - def interCharTimeout(self, interCharTimeout): - self.inter_byte_timeout = interCharTimeout - - def getSettingsDict(self): - return self.get_settings() - - def applySettingsDict(self, d): - self.apply_settings(d) - - def isOpen(self): - return self.is_open - - # - - - - - - - - - - - - - - - - - - - - - - - - - # additional functionality - - def read_all(self): - """\ - Read all bytes currently available in the buffer of the OS. - """ - return self.read(self.in_waiting) - - def read_until(self, expected=LF, size=None): - """\ - Read until an expected sequence is found ('\n' by default), the size - is exceeded or until timeout occurs. - """ - lenterm = len(expected) - line = bytearray() - timeout = Timeout(self._timeout) - while True: - c = self.read(1) - if c: - line += c - if line[-lenterm:] == expected: - break - if size is not None and len(line) >= size: - break - else: - break - if timeout.expired(): - break - return bytes(line) - - def iread_until(self, *args, **kwargs): - """\ - Read lines, implemented as generator. It will raise StopIteration on - timeout (empty read). - """ - while True: - line = self.read_until(*args, **kwargs) - if not line: - break - yield line - - -# - - - - - - - - - - - - - - - - - - - - - - - - - -if __name__ == '__main__': - import sys - s = SerialBase() - sys.stdout.write('port name: {}\n'.format(s.name)) - sys.stdout.write('baud rates: {}\n'.format(s.BAUDRATES)) - sys.stdout.write('byte sizes: {}\n'.format(s.BYTESIZES)) - sys.stdout.write('parities: {}\n'.format(s.PARITIES)) - sys.stdout.write('stop bits: {}\n'.format(s.STOPBITS)) - sys.stdout.write('{}\n'.format(s)) diff --git a/extensions/km-plot/deps/serial/serialwin32.py b/extensions/km-plot/deps/serial/serialwin32.py deleted file mode 100644 index e7da929..0000000 --- a/extensions/km-plot/deps/serial/serialwin32.py +++ /dev/null @@ -1,477 +0,0 @@ -#! python -# -# backend for Windows ("win32" incl. 32/64 bit support) -# -# (C) 2001-2020 Chris Liechti -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# SPDX-License-Identifier: BSD-3-Clause -# -# Initial patch to use ctypes by Giovanni Bajo - -from __future__ import absolute_import - -# pylint: disable=invalid-name,too-few-public-methods -import ctypes -import time -from serial import win32 - -import serial -from serial.serialutil import SerialBase, SerialException, to_bytes, PortNotOpenError, SerialTimeoutException - - -class Serial(SerialBase): - """Serial port implementation for Win32 based on ctypes.""" - - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200) - - def __init__(self, *args, **kwargs): - self._port_handle = None - self._overlapped_read = None - self._overlapped_write = None - super(Serial, self).__init__(*args, **kwargs) - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - # the "\\.\COMx" format is required for devices other than COM1-COM8 - # not all versions of windows seem to support this properly - # so that the first few ports are used with the DOS device name - port = self.name - try: - if port.upper().startswith('COM') and int(port[3:]) > 8: - port = '\\\\.\\' + port - except ValueError: - # for like COMnotanumber - pass - self._port_handle = win32.CreateFile( - port, - win32.GENERIC_READ | win32.GENERIC_WRITE, - 0, # exclusive access - None, # no security - win32.OPEN_EXISTING, - win32.FILE_ATTRIBUTE_NORMAL | win32.FILE_FLAG_OVERLAPPED, - 0) - if self._port_handle == win32.INVALID_HANDLE_VALUE: - self._port_handle = None # 'cause __del__ is called anyway - raise SerialException("could not open port {!r}: {!r}".format(self.portstr, ctypes.WinError())) - - try: - self._overlapped_read = win32.OVERLAPPED() - self._overlapped_read.hEvent = win32.CreateEvent(None, 1, 0, None) - self._overlapped_write = win32.OVERLAPPED() - #~ self._overlapped_write.hEvent = win32.CreateEvent(None, 1, 0, None) - self._overlapped_write.hEvent = win32.CreateEvent(None, 0, 0, None) - - # Setup a 4k buffer - win32.SetupComm(self._port_handle, 4096, 4096) - - # Save original timeout values: - self._orgTimeouts = win32.COMMTIMEOUTS() - win32.GetCommTimeouts(self._port_handle, ctypes.byref(self._orgTimeouts)) - - self._reconfigure_port() - - # Clear buffers: - # Remove anything that was there - win32.PurgeComm( - self._port_handle, - win32.PURGE_TXCLEAR | win32.PURGE_TXABORT | - win32.PURGE_RXCLEAR | win32.PURGE_RXABORT) - except: - try: - self._close() - except: - # ignore any exception when closing the port - # also to keep original exception that happened when setting up - pass - self._port_handle = None - raise - else: - self.is_open = True - - def _reconfigure_port(self): - """Set communication parameters on opened port.""" - if not self._port_handle: - raise SerialException("Can only operate on a valid port handle") - - # Set Windows timeout values - # timeouts is a tuple with the following items: - # (ReadIntervalTimeout,ReadTotalTimeoutMultiplier, - # ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier, - # WriteTotalTimeoutConstant) - timeouts = win32.COMMTIMEOUTS() - if self._timeout is None: - pass # default of all zeros is OK - elif self._timeout == 0: - timeouts.ReadIntervalTimeout = win32.MAXDWORD - else: - timeouts.ReadTotalTimeoutConstant = max(int(self._timeout * 1000), 1) - if self._timeout != 0 and self._inter_byte_timeout is not None: - timeouts.ReadIntervalTimeout = max(int(self._inter_byte_timeout * 1000), 1) - - if self._write_timeout is None: - pass - elif self._write_timeout == 0: - timeouts.WriteTotalTimeoutConstant = win32.MAXDWORD - else: - timeouts.WriteTotalTimeoutConstant = max(int(self._write_timeout * 1000), 1) - win32.SetCommTimeouts(self._port_handle, ctypes.byref(timeouts)) - - win32.SetCommMask(self._port_handle, win32.EV_ERR) - - # Setup the connection info. - # Get state and modify it: - comDCB = win32.DCB() - win32.GetCommState(self._port_handle, ctypes.byref(comDCB)) - comDCB.BaudRate = self._baudrate - - if self._bytesize == serial.FIVEBITS: - comDCB.ByteSize = 5 - elif self._bytesize == serial.SIXBITS: - comDCB.ByteSize = 6 - elif self._bytesize == serial.SEVENBITS: - comDCB.ByteSize = 7 - elif self._bytesize == serial.EIGHTBITS: - comDCB.ByteSize = 8 - else: - raise ValueError("Unsupported number of data bits: {!r}".format(self._bytesize)) - - if self._parity == serial.PARITY_NONE: - comDCB.Parity = win32.NOPARITY - comDCB.fParity = 0 # Disable Parity Check - elif self._parity == serial.PARITY_EVEN: - comDCB.Parity = win32.EVENPARITY - comDCB.fParity = 1 # Enable Parity Check - elif self._parity == serial.PARITY_ODD: - comDCB.Parity = win32.ODDPARITY - comDCB.fParity = 1 # Enable Parity Check - elif self._parity == serial.PARITY_MARK: - comDCB.Parity = win32.MARKPARITY - comDCB.fParity = 1 # Enable Parity Check - elif self._parity == serial.PARITY_SPACE: - comDCB.Parity = win32.SPACEPARITY - comDCB.fParity = 1 # Enable Parity Check - else: - raise ValueError("Unsupported parity mode: {!r}".format(self._parity)) - - if self._stopbits == serial.STOPBITS_ONE: - comDCB.StopBits = win32.ONESTOPBIT - elif self._stopbits == serial.STOPBITS_ONE_POINT_FIVE: - comDCB.StopBits = win32.ONE5STOPBITS - elif self._stopbits == serial.STOPBITS_TWO: - comDCB.StopBits = win32.TWOSTOPBITS - else: - raise ValueError("Unsupported number of stop bits: {!r}".format(self._stopbits)) - - comDCB.fBinary = 1 # Enable Binary Transmission - # Char. w/ Parity-Err are replaced with 0xff (if fErrorChar is set to TRUE) - if self._rs485_mode is None: - if self._rtscts: - comDCB.fRtsControl = win32.RTS_CONTROL_HANDSHAKE - else: - comDCB.fRtsControl = win32.RTS_CONTROL_ENABLE if self._rts_state else win32.RTS_CONTROL_DISABLE - comDCB.fOutxCtsFlow = self._rtscts - else: - # checks for unsupported settings - # XXX verify if platform really does not have a setting for those - if not self._rs485_mode.rts_level_for_tx: - raise ValueError( - 'Unsupported value for RS485Settings.rts_level_for_tx: {!r} (only True is allowed)'.format( - self._rs485_mode.rts_level_for_tx,)) - if self._rs485_mode.rts_level_for_rx: - raise ValueError( - 'Unsupported value for RS485Settings.rts_level_for_rx: {!r} (only False is allowed)'.format( - self._rs485_mode.rts_level_for_rx,)) - if self._rs485_mode.delay_before_tx is not None: - raise ValueError( - 'Unsupported value for RS485Settings.delay_before_tx: {!r} (only None is allowed)'.format( - self._rs485_mode.delay_before_tx,)) - if self._rs485_mode.delay_before_rx is not None: - raise ValueError( - 'Unsupported value for RS485Settings.delay_before_rx: {!r} (only None is allowed)'.format( - self._rs485_mode.delay_before_rx,)) - if self._rs485_mode.loopback: - raise ValueError( - 'Unsupported value for RS485Settings.loopback: {!r} (only False is allowed)'.format( - self._rs485_mode.loopback,)) - comDCB.fRtsControl = win32.RTS_CONTROL_TOGGLE - comDCB.fOutxCtsFlow = 0 - - if self._dsrdtr: - comDCB.fDtrControl = win32.DTR_CONTROL_HANDSHAKE - else: - comDCB.fDtrControl = win32.DTR_CONTROL_ENABLE if self._dtr_state else win32.DTR_CONTROL_DISABLE - comDCB.fOutxDsrFlow = self._dsrdtr - comDCB.fOutX = self._xonxoff - comDCB.fInX = self._xonxoff - comDCB.fNull = 0 - comDCB.fErrorChar = 0 - comDCB.fAbortOnError = 0 - comDCB.XonChar = serial.XON - comDCB.XoffChar = serial.XOFF - - if not win32.SetCommState(self._port_handle, ctypes.byref(comDCB)): - raise SerialException( - 'Cannot configure port, something went wrong. ' - 'Original message: {!r}'.format(ctypes.WinError())) - - #~ def __del__(self): - #~ self.close() - - def _close(self): - """internal close port helper""" - if self._port_handle is not None: - # Restore original timeout values: - win32.SetCommTimeouts(self._port_handle, self._orgTimeouts) - if self._overlapped_read is not None: - self.cancel_read() - win32.CloseHandle(self._overlapped_read.hEvent) - self._overlapped_read = None - if self._overlapped_write is not None: - self.cancel_write() - win32.CloseHandle(self._overlapped_write.hEvent) - self._overlapped_write = None - win32.CloseHandle(self._port_handle) - self._port_handle = None - - def close(self): - """Close port""" - if self.is_open: - self._close() - self.is_open = False - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def in_waiting(self): - """Return the number of bytes currently in the input buffer.""" - flags = win32.DWORD() - comstat = win32.COMSTAT() - if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)): - raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError())) - return comstat.cbInQue - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self.is_open: - raise PortNotOpenError() - if size > 0: - win32.ResetEvent(self._overlapped_read.hEvent) - flags = win32.DWORD() - comstat = win32.COMSTAT() - if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)): - raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError())) - n = min(comstat.cbInQue, size) if self.timeout == 0 else size - if n > 0: - buf = ctypes.create_string_buffer(n) - rc = win32.DWORD() - read_ok = win32.ReadFile( - self._port_handle, - buf, - n, - ctypes.byref(rc), - ctypes.byref(self._overlapped_read)) - if not read_ok and win32.GetLastError() not in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): - raise SerialException("ReadFile failed ({!r})".format(ctypes.WinError())) - result_ok = win32.GetOverlappedResult( - self._port_handle, - ctypes.byref(self._overlapped_read), - ctypes.byref(rc), - True) - if not result_ok: - if win32.GetLastError() != win32.ERROR_OPERATION_ABORTED: - raise SerialException("GetOverlappedResult failed ({!r})".format(ctypes.WinError())) - read = buf.raw[:rc.value] - else: - read = bytes() - else: - read = bytes() - return bytes(read) - - def write(self, data): - """Output the given byte string over the serial port.""" - if not self.is_open: - raise PortNotOpenError() - #~ if not isinstance(data, (bytes, bytearray)): - #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) - # convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview - data = to_bytes(data) - if data: - #~ win32event.ResetEvent(self._overlapped_write.hEvent) - n = win32.DWORD() - success = win32.WriteFile(self._port_handle, data, len(data), ctypes.byref(n), self._overlapped_write) - if self._write_timeout != 0: # if blocking (None) or w/ write timeout (>0) - if not success and win32.GetLastError() not in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): - raise SerialException("WriteFile failed ({!r})".format(ctypes.WinError())) - - # Wait for the write to complete. - #~ win32.WaitForSingleObject(self._overlapped_write.hEvent, win32.INFINITE) - win32.GetOverlappedResult(self._port_handle, self._overlapped_write, ctypes.byref(n), True) - if win32.GetLastError() == win32.ERROR_OPERATION_ABORTED: - return n.value # canceled IO is no error - if n.value != len(data): - raise SerialTimeoutException('Write timeout') - return n.value - else: - errorcode = win32.ERROR_SUCCESS if success else win32.GetLastError() - if errorcode in (win32.ERROR_INVALID_USER_BUFFER, win32.ERROR_NOT_ENOUGH_MEMORY, - win32.ERROR_OPERATION_ABORTED): - return 0 - elif errorcode in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): - # no info on true length provided by OS function in async mode - return len(data) - else: - raise SerialException("WriteFile failed ({!r})".format(ctypes.WinError())) - else: - return 0 - - def flush(self): - """\ - Flush of file like objects. In this case, wait until all data - is written. - """ - while self.out_waiting: - time.sleep(0.05) - # XXX could also use WaitCommEvent with mask EV_TXEMPTY, but it would - # require overlapped IO and it's also only possible to set a single mask - # on the port--- - - def reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self.is_open: - raise PortNotOpenError() - win32.PurgeComm(self._port_handle, win32.PURGE_RXCLEAR | win32.PURGE_RXABORT) - - def reset_output_buffer(self): - """\ - Clear output buffer, aborting the current output and discarding all - that is in the buffer. - """ - if not self.is_open: - raise PortNotOpenError() - win32.PurgeComm(self._port_handle, win32.PURGE_TXCLEAR | win32.PURGE_TXABORT) - - def _update_break_state(self): - """Set break: Controls TXD. When active, to transmitting is possible.""" - if not self.is_open: - raise PortNotOpenError() - if self._break_state: - win32.SetCommBreak(self._port_handle) - else: - win32.ClearCommBreak(self._port_handle) - - def _update_rts_state(self): - """Set terminal status line: Request To Send""" - if self._rts_state: - win32.EscapeCommFunction(self._port_handle, win32.SETRTS) - else: - win32.EscapeCommFunction(self._port_handle, win32.CLRRTS) - - def _update_dtr_state(self): - """Set terminal status line: Data Terminal Ready""" - if self._dtr_state: - win32.EscapeCommFunction(self._port_handle, win32.SETDTR) - else: - win32.EscapeCommFunction(self._port_handle, win32.CLRDTR) - - def _GetCommModemStatus(self): - if not self.is_open: - raise PortNotOpenError() - stat = win32.DWORD() - win32.GetCommModemStatus(self._port_handle, ctypes.byref(stat)) - return stat.value - - @property - def cts(self): - """Read terminal status line: Clear To Send""" - return win32.MS_CTS_ON & self._GetCommModemStatus() != 0 - - @property - def dsr(self): - """Read terminal status line: Data Set Ready""" - return win32.MS_DSR_ON & self._GetCommModemStatus() != 0 - - @property - def ri(self): - """Read terminal status line: Ring Indicator""" - return win32.MS_RING_ON & self._GetCommModemStatus() != 0 - - @property - def cd(self): - """Read terminal status line: Carrier Detect""" - return win32.MS_RLSD_ON & self._GetCommModemStatus() != 0 - - # - - platform specific - - - - - - def set_buffer_size(self, rx_size=4096, tx_size=None): - """\ - Recommend a buffer size to the driver (device driver can ignore this - value). Must be called after the port is opened. - """ - if tx_size is None: - tx_size = rx_size - win32.SetupComm(self._port_handle, rx_size, tx_size) - - def set_output_flow_control(self, enable=True): - """\ - Manually control flow - when software flow control is enabled. - This will do the same as if XON (true) or XOFF (false) are received - from the other device and control the transmission accordingly. - WARNING: this function is not portable to different platforms! - """ - if not self.is_open: - raise PortNotOpenError() - if enable: - win32.EscapeCommFunction(self._port_handle, win32.SETXON) - else: - win32.EscapeCommFunction(self._port_handle, win32.SETXOFF) - - @property - def out_waiting(self): - """Return how many bytes the in the outgoing buffer""" - flags = win32.DWORD() - comstat = win32.COMSTAT() - if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)): - raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError())) - return comstat.cbOutQue - - def _cancel_overlapped_io(self, overlapped): - """Cancel a blocking read operation, may be called from other thread""" - # check if read operation is pending - rc = win32.DWORD() - err = win32.GetOverlappedResult( - self._port_handle, - ctypes.byref(overlapped), - ctypes.byref(rc), - False) - if not err and win32.GetLastError() in (win32.ERROR_IO_PENDING, win32.ERROR_IO_INCOMPLETE): - # cancel, ignoring any errors (e.g. it may just have finished on its own) - win32.CancelIoEx(self._port_handle, overlapped) - - def cancel_read(self): - """Cancel a blocking read operation, may be called from other thread""" - self._cancel_overlapped_io(self._overlapped_read) - - def cancel_write(self): - """Cancel a blocking write operation, may be called from other thread""" - self._cancel_overlapped_io(self._overlapped_write) - - @SerialBase.exclusive.setter - def exclusive(self, exclusive): - """Change the exclusive access setting.""" - if exclusive is not None and not exclusive: - raise ValueError('win32 only supports exclusive access (not: {})'.format(exclusive)) - else: - serial.SerialBase.exclusive.__set__(self, exclusive) diff --git a/extensions/km-plot/deps/serial/threaded/__init__.py b/extensions/km-plot/deps/serial/threaded/__init__.py deleted file mode 100644 index b8940b6..0000000 --- a/extensions/km-plot/deps/serial/threaded/__init__.py +++ /dev/null @@ -1,297 +0,0 @@ -#!/usr/bin/env python3 -# -# Working with threading and pySerial -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015-2016 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -"""\ -Support threading with serial ports. -""" -from __future__ import absolute_import - -import serial -import threading - - -class Protocol(object): - """\ - Protocol as used by the ReaderThread. This base class provides empty - implementations of all methods. - """ - - def connection_made(self, transport): - """Called when reader thread is started""" - - def data_received(self, data): - """Called with snippets received from the serial port""" - - def connection_lost(self, exc): - """\ - Called when the serial port is closed or the reader loop terminated - otherwise. - """ - if isinstance(exc, Exception): - raise exc - - -class Packetizer(Protocol): - """ - Read binary packets from serial port. Packets are expected to be terminated - with a TERMINATOR byte (null byte by default). - - The class also keeps track of the transport. - """ - - TERMINATOR = b'\0' - - def __init__(self): - self.buffer = bytearray() - self.transport = None - - def connection_made(self, transport): - """Store transport""" - self.transport = transport - - def connection_lost(self, exc): - """Forget transport""" - self.transport = None - super(Packetizer, self).connection_lost(exc) - - def data_received(self, data): - """Buffer received data, find TERMINATOR, call handle_packet""" - self.buffer.extend(data) - while self.TERMINATOR in self.buffer: - packet, self.buffer = self.buffer.split(self.TERMINATOR, 1) - self.handle_packet(packet) - - def handle_packet(self, packet): - """Process packets - to be overridden by subclassing""" - raise NotImplementedError('please implement functionality in handle_packet') - - -class FramedPacket(Protocol): - """ - Read binary packets. Packets are expected to have a start and stop marker. - - The class also keeps track of the transport. - """ - - START = b'(' - STOP = b')' - - def __init__(self): - self.packet = bytearray() - self.in_packet = False - self.transport = None - - def connection_made(self, transport): - """Store transport""" - self.transport = transport - - def connection_lost(self, exc): - """Forget transport""" - self.transport = None - self.in_packet = False - del self.packet[:] - super(FramedPacket, self).connection_lost(exc) - - def data_received(self, data): - """Find data enclosed in START/STOP, call handle_packet""" - for byte in serial.iterbytes(data): - if byte == self.START: - self.in_packet = True - elif byte == self.STOP: - self.in_packet = False - self.handle_packet(bytes(self.packet)) # make read-only copy - del self.packet[:] - elif self.in_packet: - self.packet.extend(byte) - else: - self.handle_out_of_packet_data(byte) - - def handle_packet(self, packet): - """Process packets - to be overridden by subclassing""" - raise NotImplementedError('please implement functionality in handle_packet') - - def handle_out_of_packet_data(self, data): - """Process data that is received outside of packets""" - pass - - -class LineReader(Packetizer): - """ - Read and write (Unicode) lines from/to serial port. - The encoding is applied. - """ - - TERMINATOR = b'\r\n' - ENCODING = 'utf-8' - UNICODE_HANDLING = 'replace' - - def handle_packet(self, packet): - self.handle_line(packet.decode(self.ENCODING, self.UNICODE_HANDLING)) - - def handle_line(self, line): - """Process one line - to be overridden by subclassing""" - raise NotImplementedError('please implement functionality in handle_line') - - def write_line(self, text): - """ - Write text to the transport. ``text`` is a Unicode string and the encoding - is applied before sending ans also the newline is append. - """ - # + is not the best choice but bytes does not support % or .format in py3 and we want a single write call - self.transport.write(text.encode(self.ENCODING, self.UNICODE_HANDLING) + self.TERMINATOR) - - -class ReaderThread(threading.Thread): - """\ - Implement a serial port read loop and dispatch to a Protocol instance (like - the asyncio.Protocol) but do it with threads. - - Calls to close() will close the serial port but it is also possible to just - stop() this thread and continue the serial port instance otherwise. - """ - - def __init__(self, serial_instance, protocol_factory): - """\ - Initialize thread. - - Note that the serial_instance' timeout is set to one second! - Other settings are not changed. - """ - super(ReaderThread, self).__init__() - self.daemon = True - self.serial = serial_instance - self.protocol_factory = protocol_factory - self.alive = True - self._lock = threading.Lock() - self._connection_made = threading.Event() - self.protocol = None - - def stop(self): - """Stop the reader thread""" - self.alive = False - if hasattr(self.serial, 'cancel_read'): - self.serial.cancel_read() - self.join(2) - - def run(self): - """Reader loop""" - if not hasattr(self.serial, 'cancel_read'): - self.serial.timeout = 1 - self.protocol = self.protocol_factory() - try: - self.protocol.connection_made(self) - except Exception as e: - self.alive = False - self.protocol.connection_lost(e) - self._connection_made.set() - return - error = None - self._connection_made.set() - while self.alive and self.serial.is_open: - try: - # read all that is there or wait for one byte (blocking) - data = self.serial.read(self.serial.in_waiting or 1) - except serial.SerialException as e: - # probably some I/O problem such as disconnected USB serial - # adapters -> exit - error = e - break - else: - if data: - # make a separated try-except for called user code - try: - self.protocol.data_received(data) - except Exception as e: - error = e - break - self.alive = False - self.protocol.connection_lost(error) - self.protocol = None - - def write(self, data): - """Thread safe writing (uses lock)""" - with self._lock: - return self.serial.write(data) - - def close(self): - """Close the serial port and exit reader thread (uses lock)""" - # use the lock to let other threads finish writing - with self._lock: - # first stop reading, so that closing can be done on idle port - self.stop() - self.serial.close() - - def connect(self): - """ - Wait until connection is set up and return the transport and protocol - instances. - """ - if self.alive: - self._connection_made.wait() - if not self.alive: - raise RuntimeError('connection_lost already called') - return (self, self.protocol) - else: - raise RuntimeError('already stopped') - - # - - context manager, returns protocol - - def __enter__(self): - """\ - Enter context handler. May raise RuntimeError in case the connection - could not be created. - """ - self.start() - self._connection_made.wait() - if not self.alive: - raise RuntimeError('connection_lost already called') - return self.protocol - - def __exit__(self, exc_type, exc_val, exc_tb): - """Leave context: close port""" - self.close() - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - # pylint: disable=wrong-import-position - import sys - import time - import traceback - - #~ PORT = 'spy:///dev/ttyUSB0' - PORT = 'loop://' - - class PrintLines(LineReader): - def connection_made(self, transport): - super(PrintLines, self).connection_made(transport) - sys.stdout.write('port opened\n') - self.write_line('hello world') - - def handle_line(self, data): - sys.stdout.write('line received: {!r}\n'.format(data)) - - def connection_lost(self, exc): - if exc: - traceback.print_exc(exc) - sys.stdout.write('port closed\n') - - ser = serial.serial_for_url(PORT, baudrate=115200, timeout=1) - with ReaderThread(ser, PrintLines) as protocol: - protocol.write_line('hello') - time.sleep(2) - - # alternative usage - ser = serial.serial_for_url(PORT, baudrate=115200, timeout=1) - t = ReaderThread(ser, PrintLines) - t.start() - transport, protocol = t.connect() - protocol.write_line('hello') - time.sleep(2) - t.close() diff --git a/extensions/km-plot/deps/serial/tools/__init__.py b/extensions/km-plot/deps/serial/tools/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/km-plot/deps/serial/tools/hexlify_codec.py b/extensions/km-plot/deps/serial/tools/hexlify_codec.py deleted file mode 100644 index bd8f6b0..0000000 --- a/extensions/km-plot/deps/serial/tools/hexlify_codec.py +++ /dev/null @@ -1,126 +0,0 @@ -#! python -# -# This is a codec to create and decode hexdumps with spaces between characters. used by miniterm. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015-2016 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -"""\ -Python 'hex' Codec - 2-digit hex with spaces content transfer encoding. - -Encode and decode may be a bit missleading at first sight... - -The textual representation is a hex dump: e.g. "40 41" -The "encoded" data of this is the binary form, e.g. b"@A" - -Therefore decoding is binary to text and thus converting binary data to hex dump. - -""" - -from __future__ import absolute_import - -import codecs -import serial - - -try: - unicode -except (NameError, AttributeError): - unicode = str # for Python 3, pylint: disable=redefined-builtin,invalid-name - - -HEXDIGITS = '0123456789ABCDEF' - - -# Codec APIs - -def hex_encode(data, errors='strict'): - """'40 41 42' -> b'@ab'""" - return (serial.to_bytes([int(h, 16) for h in data.split()]), len(data)) - - -def hex_decode(data, errors='strict'): - """b'@ab' -> '40 41 42'""" - return (unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data))), len(data)) - - -class Codec(codecs.Codec): - def encode(self, data, errors='strict'): - """'40 41 42' -> b'@ab'""" - return serial.to_bytes([int(h, 16) for h in data.split()]) - - def decode(self, data, errors='strict'): - """b'@ab' -> '40 41 42'""" - return unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data))) - - -class IncrementalEncoder(codecs.IncrementalEncoder): - """Incremental hex encoder""" - - def __init__(self, errors='strict'): - self.errors = errors - self.state = 0 - - def reset(self): - self.state = 0 - - def getstate(self): - return self.state - - def setstate(self, state): - self.state = state - - def encode(self, data, final=False): - """\ - Incremental encode, keep track of digits and emit a byte when a pair - of hex digits is found. The space is optional unless the error - handling is defined to be 'strict'. - """ - state = self.state - encoded = [] - for c in data.upper(): - if c in HEXDIGITS: - z = HEXDIGITS.index(c) - if state: - encoded.append(z + (state & 0xf0)) - state = 0 - else: - state = 0x100 + (z << 4) - elif c == ' ': # allow spaces to separate values - if state and self.errors == 'strict': - raise UnicodeError('odd number of hex digits') - state = 0 - else: - if self.errors == 'strict': - raise UnicodeError('non-hex digit found: {!r}'.format(c)) - self.state = state - return serial.to_bytes(encoded) - - -class IncrementalDecoder(codecs.IncrementalDecoder): - """Incremental decoder""" - def decode(self, data, final=False): - return unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data))) - - -class StreamWriter(Codec, codecs.StreamWriter): - """Combination of hexlify codec and StreamWriter""" - - -class StreamReader(Codec, codecs.StreamReader): - """Combination of hexlify codec and StreamReader""" - - -def getregentry(): - """encodings module API""" - return codecs.CodecInfo( - name='hexlify', - encode=hex_encode, - decode=hex_decode, - incrementalencoder=IncrementalEncoder, - incrementaldecoder=IncrementalDecoder, - streamwriter=StreamWriter, - streamreader=StreamReader, - #~ _is_text_encoding=True, - ) diff --git a/extensions/km-plot/deps/serial/tools/list_ports.py b/extensions/km-plot/deps/serial/tools/list_ports.py deleted file mode 100644 index 0d7e3d4..0000000 --- a/extensions/km-plot/deps/serial/tools/list_ports.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python -# -# Serial port enumeration. Console tool and backend selection. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2011-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -"""\ -This module will provide a function called comports that returns an -iterable (generator or list) that will enumerate available com ports. Note that -on some systems non-existent ports may be listed. - -Additionally a grep function is supplied that can be used to search for ports -based on their descriptions or hardware ID. -""" - -from __future__ import absolute_import - -import sys -import os -import re - -# chose an implementation, depending on os -#~ if sys.platform == 'cli': -#~ else: -if os.name == 'nt': # sys.platform == 'win32': - from serial.tools.list_ports_windows import comports -elif os.name == 'posix': - from serial.tools.list_ports_posix import comports -#~ elif os.name == 'java': -else: - raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name)) - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def grep(regexp, include_links=False): - """\ - Search for ports using a regular expression. Port name, description and - hardware ID are searched. The function returns an iterable that returns the - same tuples as comport() would do. - """ - r = re.compile(regexp, re.I) - for info in comports(include_links): - port, desc, hwid = info - if r.search(port) or r.search(desc) or r.search(hwid): - yield info - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def main(): - import argparse - - parser = argparse.ArgumentParser(description='Serial port enumeration') - - parser.add_argument( - 'regexp', - nargs='?', - help='only show ports that match this regex') - - parser.add_argument( - '-v', '--verbose', - action='store_true', - help='show more messages') - - parser.add_argument( - '-q', '--quiet', - action='store_true', - help='suppress all messages') - - parser.add_argument( - '-n', - type=int, - help='only output the N-th entry') - - parser.add_argument( - '-s', '--include-links', - action='store_true', - help='include entries that are symlinks to real devices') - - args = parser.parse_args() - - hits = 0 - # get iteraror w/ or w/o filter - if args.regexp: - if not args.quiet: - sys.stderr.write("Filtered list with regexp: {!r}\n".format(args.regexp)) - iterator = sorted(grep(args.regexp, include_links=args.include_links)) - else: - iterator = sorted(comports(include_links=args.include_links)) - # list them - for n, (port, desc, hwid) in enumerate(iterator, 1): - if args.n is None or args.n == n: - sys.stdout.write("{:20}\n".format(port)) - if args.verbose: - sys.stdout.write(" desc: {}\n".format(desc)) - sys.stdout.write(" hwid: {}\n".format(hwid)) - hits += 1 - if not args.quiet: - if hits: - sys.stderr.write("{} ports found\n".format(hits)) - else: - sys.stderr.write("no ports found\n") - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - main() diff --git a/extensions/km-plot/deps/serial/tools/list_ports_common.py b/extensions/km-plot/deps/serial/tools/list_ports_common.py deleted file mode 100644 index 617f3dc..0000000 --- a/extensions/km-plot/deps/serial/tools/list_ports_common.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python -# -# This is a helper module for the various platform dependent list_port -# implementations. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -from __future__ import absolute_import - -import re -import glob -import os -import os.path - - -def numsplit(text): - """\ - Convert string into a list of texts and numbers in order to support a - natural sorting. - """ - result = [] - for group in re.split(r'(\d+)', text): - if group: - try: - group = int(group) - except ValueError: - pass - result.append(group) - return result - - -class ListPortInfo(object): - """Info collection base class for serial ports""" - - def __init__(self, device, skip_link_detection=False): - self.device = device - self.name = os.path.basename(device) - self.description = 'n/a' - self.hwid = 'n/a' - # USB specific data - self.vid = None - self.pid = None - self.serial_number = None - self.location = None - self.manufacturer = None - self.product = None - self.interface = None - # special handling for links - if not skip_link_detection and device is not None and os.path.islink(device): - self.hwid = 'LINK={}'.format(os.path.realpath(device)) - - def usb_description(self): - """return a short string to name the port based on USB info""" - if self.interface is not None: - return '{} - {}'.format(self.product, self.interface) - elif self.product is not None: - return self.product - else: - return self.name - - def usb_info(self): - """return a string with USB related information about device""" - return 'USB VID:PID={:04X}:{:04X}{}{}'.format( - self.vid or 0, - self.pid or 0, - ' SER={}'.format(self.serial_number) if self.serial_number is not None else '', - ' LOCATION={}'.format(self.location) if self.location is not None else '') - - def apply_usb_info(self): - """update description and hwid from USB data""" - self.description = self.usb_description() - self.hwid = self.usb_info() - - def __eq__(self, other): - return isinstance(other, ListPortInfo) and self.device == other.device - - def __hash__(self): - return hash(self.device) - - def __lt__(self, other): - if not isinstance(other, ListPortInfo): - raise TypeError('unorderable types: {}() and {}()'.format( - type(self).__name__, - type(other).__name__)) - return numsplit(self.device) < numsplit(other.device) - - def __str__(self): - return '{} - {}'.format(self.device, self.description) - - def __getitem__(self, index): - """Item access: backwards compatible -> (port, desc, hwid)""" - if index == 0: - return self.device - elif index == 1: - return self.description - elif index == 2: - return self.hwid - else: - raise IndexError('{} > 2'.format(index)) - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def list_links(devices): - """\ - search all /dev devices and look for symlinks to known ports already - listed in devices. - """ - links = [] - for device in glob.glob('/dev/*'): - if os.path.islink(device) and os.path.realpath(device) in devices: - links.append(device) - return links - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - print(ListPortInfo('dummy')) diff --git a/extensions/km-plot/deps/serial/tools/list_ports_linux.py b/extensions/km-plot/deps/serial/tools/list_ports_linux.py deleted file mode 100644 index c8c1cfc..0000000 --- a/extensions/km-plot/deps/serial/tools/list_ports_linux.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python -# -# This is a module that gathers a list of serial ports including details on -# GNU/Linux systems. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2011-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -from __future__ import absolute_import - -import glob -import os -from serial.tools import list_ports_common - - -class SysFS(list_ports_common.ListPortInfo): - """Wrapper for easy sysfs access and device info""" - - def __init__(self, device): - super(SysFS, self).__init__(device) - # special handling for links - if device is not None and os.path.islink(device): - device = os.path.realpath(device) - is_link = True - else: - is_link = False - self.usb_device_path = None - if os.path.exists('/sys/class/tty/{}/device'.format(self.name)): - self.device_path = os.path.realpath('/sys/class/tty/{}/device'.format(self.name)) - self.subsystem = os.path.basename(os.path.realpath(os.path.join(self.device_path, 'subsystem'))) - else: - self.device_path = None - self.subsystem = None - # check device type - if self.subsystem == 'usb-serial': - self.usb_interface_path = os.path.dirname(self.device_path) - elif self.subsystem == 'usb': - self.usb_interface_path = self.device_path - else: - self.usb_interface_path = None - # fill-in info for USB devices - if self.usb_interface_path is not None: - self.usb_device_path = os.path.dirname(self.usb_interface_path) - - try: - num_if = int(self.read_line(self.usb_device_path, 'bNumInterfaces')) - except ValueError: - num_if = 1 - - self.vid = int(self.read_line(self.usb_device_path, 'idVendor'), 16) - self.pid = int(self.read_line(self.usb_device_path, 'idProduct'), 16) - self.serial_number = self.read_line(self.usb_device_path, 'serial') - if num_if > 1: # multi interface devices like FT4232 - self.location = os.path.basename(self.usb_interface_path) - else: - self.location = os.path.basename(self.usb_device_path) - - self.manufacturer = self.read_line(self.usb_device_path, 'manufacturer') - self.product = self.read_line(self.usb_device_path, 'product') - self.interface = self.read_line(self.usb_interface_path, 'interface') - - if self.subsystem in ('usb', 'usb-serial'): - self.apply_usb_info() - #~ elif self.subsystem in ('pnp', 'amba'): # PCI based devices, raspi - elif self.subsystem == 'pnp': # PCI based devices - self.description = self.name - self.hwid = self.read_line(self.device_path, 'id') - elif self.subsystem == 'amba': # raspi - self.description = self.name - self.hwid = os.path.basename(self.device_path) - - if is_link: - self.hwid += ' LINK={}'.format(device) - - def read_line(self, *args): - """\ - Helper function to read a single line from a file. - One or more parameters are allowed, they are joined with os.path.join. - Returns None on errors.. - """ - try: - with open(os.path.join(*args)) as f: - line = f.readline().strip() - return line - except IOError: - return None - - -def comports(include_links=False): - devices = glob.glob('/dev/ttyS*') # built-in serial ports - devices.extend(glob.glob('/dev/ttyUSB*')) # usb-serial with own driver - devices.extend(glob.glob('/dev/ttyXRUSB*')) # xr-usb-serial port exar (DELL Edge 3001) - devices.extend(glob.glob('/dev/ttyACM*')) # usb-serial with CDC-ACM profile - devices.extend(glob.glob('/dev/ttyAMA*')) # ARM internal port (raspi) - devices.extend(glob.glob('/dev/rfcomm*')) # BT serial devices - devices.extend(glob.glob('/dev/ttyAP*')) # Advantech multi-port serial controllers - if include_links: - devices.extend(list_ports_common.list_links(devices)) - return [info - for info in [SysFS(d) for d in devices] - if info.subsystem != "platform"] # hide non-present internal serial ports - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - for info in sorted(comports()): - print("{0}: {0.subsystem}".format(info)) diff --git a/extensions/km-plot/deps/serial/tools/list_ports_osx.py b/extensions/km-plot/deps/serial/tools/list_ports_osx.py deleted file mode 100644 index 51b4e8c..0000000 --- a/extensions/km-plot/deps/serial/tools/list_ports_osx.py +++ /dev/null @@ -1,299 +0,0 @@ -#!/usr/bin/env python -# -# This is a module that gathers a list of serial ports including details on OSX -# -# code originally from https://github.com/makerbot/pyserial/tree/master/serial/tools -# with contributions from cibomahto, dgs3, FarMcKon, tedbrandston -# and modifications by cliechti, hoihu, hardkrash -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2013-2020 -# -# SPDX-License-Identifier: BSD-3-Clause - - -# List all of the callout devices in OS/X by querying IOKit. - -# See the following for a reference of how to do this: -# http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html#//apple_ref/doc/uid/TP30000384-CIHGEAFD - -# More help from darwin_hid.py - -# Also see the 'IORegistryExplorer' for an idea of what we are actually searching - -from __future__ import absolute_import - -import ctypes - -from serial.tools import list_ports_common - -iokit = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/IOKit.framework/IOKit') -cf = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation') - -# kIOMasterPortDefault is no longer exported in BigSur but no biggie, using NULL works just the same -kIOMasterPortDefault = 0 # WAS: ctypes.c_void_p.in_dll(iokit, "kIOMasterPortDefault") -kCFAllocatorDefault = ctypes.c_void_p.in_dll(cf, "kCFAllocatorDefault") - -kCFStringEncodingMacRoman = 0 -kCFStringEncodingUTF8 = 0x08000100 - -# defined in `IOKit/usb/USBSpec.h` -kUSBVendorString = 'USB Vendor Name' -kUSBSerialNumberString = 'USB Serial Number' - -# `io_name_t` defined as `typedef char io_name_t[128];` -# in `device/device_types.h` -io_name_size = 128 - -# defined in `mach/kern_return.h` -KERN_SUCCESS = 0 -# kern_return_t defined as `typedef int kern_return_t;` in `mach/i386/kern_return.h` -kern_return_t = ctypes.c_int - -iokit.IOServiceMatching.restype = ctypes.c_void_p - -iokit.IOServiceGetMatchingServices.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] -iokit.IOServiceGetMatchingServices.restype = kern_return_t - -iokit.IORegistryEntryGetParentEntry.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] -iokit.IOServiceGetMatchingServices.restype = kern_return_t - -iokit.IORegistryEntryCreateCFProperty.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint32] -iokit.IORegistryEntryCreateCFProperty.restype = ctypes.c_void_p - -iokit.IORegistryEntryGetPath.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] -iokit.IORegistryEntryGetPath.restype = kern_return_t - -iokit.IORegistryEntryGetName.argtypes = [ctypes.c_void_p, ctypes.c_void_p] -iokit.IORegistryEntryGetName.restype = kern_return_t - -iokit.IOObjectGetClass.argtypes = [ctypes.c_void_p, ctypes.c_void_p] -iokit.IOObjectGetClass.restype = kern_return_t - -iokit.IOObjectRelease.argtypes = [ctypes.c_void_p] - - -cf.CFStringCreateWithCString.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int32] -cf.CFStringCreateWithCString.restype = ctypes.c_void_p - -cf.CFStringGetCStringPtr.argtypes = [ctypes.c_void_p, ctypes.c_uint32] -cf.CFStringGetCStringPtr.restype = ctypes.c_char_p - -cf.CFStringGetCString.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_long, ctypes.c_uint32] -cf.CFStringGetCString.restype = ctypes.c_bool - -cf.CFNumberGetValue.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_void_p] -cf.CFNumberGetValue.restype = ctypes.c_void_p - -# void CFRelease ( CFTypeRef cf ); -cf.CFRelease.argtypes = [ctypes.c_void_p] -cf.CFRelease.restype = None - -# CFNumber type defines -kCFNumberSInt8Type = 1 -kCFNumberSInt16Type = 2 -kCFNumberSInt32Type = 3 -kCFNumberSInt64Type = 4 - - -def get_string_property(device_type, property): - """ - Search the given device for the specified string property - - @param device_type Type of Device - @param property String to search for - @return Python string containing the value, or None if not found. - """ - key = cf.CFStringCreateWithCString( - kCFAllocatorDefault, - property.encode("utf-8"), - kCFStringEncodingUTF8) - - CFContainer = iokit.IORegistryEntryCreateCFProperty( - device_type, - key, - kCFAllocatorDefault, - 0) - output = None - - if CFContainer: - output = cf.CFStringGetCStringPtr(CFContainer, 0) - if output is not None: - output = output.decode('utf-8') - else: - buffer = ctypes.create_string_buffer(io_name_size); - success = cf.CFStringGetCString(CFContainer, ctypes.byref(buffer), io_name_size, kCFStringEncodingUTF8) - if success: - output = buffer.value.decode('utf-8') - cf.CFRelease(CFContainer) - return output - - -def get_int_property(device_type, property, cf_number_type): - """ - Search the given device for the specified string property - - @param device_type Device to search - @param property String to search for - @param cf_number_type CFType number - - @return Python string containing the value, or None if not found. - """ - key = cf.CFStringCreateWithCString( - kCFAllocatorDefault, - property.encode("utf-8"), - kCFStringEncodingUTF8) - - CFContainer = iokit.IORegistryEntryCreateCFProperty( - device_type, - key, - kCFAllocatorDefault, - 0) - - if CFContainer: - if (cf_number_type == kCFNumberSInt32Type): - number = ctypes.c_uint32() - elif (cf_number_type == kCFNumberSInt16Type): - number = ctypes.c_uint16() - cf.CFNumberGetValue(CFContainer, cf_number_type, ctypes.byref(number)) - cf.CFRelease(CFContainer) - return number.value - return None - -def IORegistryEntryGetName(device): - devicename = ctypes.create_string_buffer(io_name_size); - res = iokit.IORegistryEntryGetName(device, ctypes.byref(devicename)) - if res != KERN_SUCCESS: - return None - # this works in python2 but may not be valid. Also I don't know if - # this encoding is guaranteed. It may be dependent on system locale. - return devicename.value.decode('utf-8') - -def IOObjectGetClass(device): - classname = ctypes.create_string_buffer(io_name_size) - iokit.IOObjectGetClass(device, ctypes.byref(classname)) - return classname.value - -def GetParentDeviceByType(device, parent_type): - """ Find the first parent of a device that implements the parent_type - @param IOService Service to inspect - @return Pointer to the parent type, or None if it was not found. - """ - # First, try to walk up the IOService tree to find a parent of this device that is a IOUSBDevice. - parent_type = parent_type.encode('utf-8') - while IOObjectGetClass(device) != parent_type: - parent = ctypes.c_void_p() - response = iokit.IORegistryEntryGetParentEntry( - device, - "IOService".encode("utf-8"), - ctypes.byref(parent)) - # If we weren't able to find a parent for the device, we're done. - if response != KERN_SUCCESS: - return None - device = parent - return device - - -def GetIOServicesByType(service_type): - """ - returns iterator over specified service_type - """ - serial_port_iterator = ctypes.c_void_p() - - iokit.IOServiceGetMatchingServices( - kIOMasterPortDefault, - iokit.IOServiceMatching(service_type.encode('utf-8')), - ctypes.byref(serial_port_iterator)) - - services = [] - while iokit.IOIteratorIsValid(serial_port_iterator): - service = iokit.IOIteratorNext(serial_port_iterator) - if not service: - break - services.append(service) - iokit.IOObjectRelease(serial_port_iterator) - return services - - -def location_to_string(locationID): - """ - helper to calculate port and bus number from locationID - """ - loc = ['{}-'.format(locationID >> 24)] - while locationID & 0xf00000: - if len(loc) > 1: - loc.append('.') - loc.append('{}'.format((locationID >> 20) & 0xf)) - locationID <<= 4 - return ''.join(loc) - - -class SuitableSerialInterface(object): - pass - - -def scan_interfaces(): - """ - helper function to scan USB interfaces - returns a list of SuitableSerialInterface objects with name and id attributes - """ - interfaces = [] - for service in GetIOServicesByType('IOSerialBSDClient'): - device = get_string_property(service, "IOCalloutDevice") - if device: - usb_device = GetParentDeviceByType(service, "IOUSBInterface") - if usb_device: - name = get_string_property(usb_device, "USB Interface Name") or None - locationID = get_int_property(usb_device, "locationID", kCFNumberSInt32Type) or '' - i = SuitableSerialInterface() - i.id = locationID - i.name = name - interfaces.append(i) - return interfaces - - -def search_for_locationID_in_interfaces(serial_interfaces, locationID): - for interface in serial_interfaces: - if (interface.id == locationID): - return interface.name - return None - - -def comports(include_links=False): - # XXX include_links is currently ignored. are links in /dev even supported here? - # Scan for all iokit serial ports - services = GetIOServicesByType('IOSerialBSDClient') - ports = [] - serial_interfaces = scan_interfaces() - for service in services: - # First, add the callout device file. - device = get_string_property(service, "IOCalloutDevice") - if device: - info = list_ports_common.ListPortInfo(device) - # If the serial port is implemented by IOUSBDevice - # NOTE IOUSBDevice was deprecated as of 10.11 and finally on Apple Silicon - # devices has been completely removed. Thanks to @oskay for this patch. - usb_device = GetParentDeviceByType(service, "IOUSBHostDevice") - if not usb_device: - usb_device = GetParentDeviceByType(service, "IOUSBDevice") - if usb_device: - # fetch some useful informations from properties - info.vid = get_int_property(usb_device, "idVendor", kCFNumberSInt16Type) - info.pid = get_int_property(usb_device, "idProduct", kCFNumberSInt16Type) - info.serial_number = get_string_property(usb_device, kUSBSerialNumberString) - # We know this is a usb device, so the - # IORegistryEntryName should always be aliased to the - # usb product name string descriptor. - info.product = IORegistryEntryGetName(usb_device) or 'n/a' - info.manufacturer = get_string_property(usb_device, kUSBVendorString) - locationID = get_int_property(usb_device, "locationID", kCFNumberSInt32Type) - info.location = location_to_string(locationID) - info.interface = search_for_locationID_in_interfaces(serial_interfaces, locationID) - info.apply_usb_info() - ports.append(info) - return ports - -# test -if __name__ == '__main__': - for port, desc, hwid in sorted(comports()): - print("{}: {} [{}]".format(port, desc, hwid)) diff --git a/extensions/km-plot/deps/serial/tools/list_ports_posix.py b/extensions/km-plot/deps/serial/tools/list_ports_posix.py deleted file mode 100644 index 79bc8ed..0000000 --- a/extensions/km-plot/deps/serial/tools/list_ports_posix.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python -# -# This is a module that gathers a list of serial ports on POSIXy systems. -# For some specific implementations, see also list_ports_linux, list_ports_osx -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2011-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -"""\ -The ``comports`` function is expected to return an iterable that yields tuples -of 3 strings: port name, human readable description and a hardware ID. - -As currently no method is known to get the second two strings easily, they are -currently just identical to the port name. -""" - -from __future__ import absolute_import - -import glob -import sys -import os -from serial.tools import list_ports_common - -# try to detect the OS so that a device can be selected... -plat = sys.platform.lower() - -if plat[:5] == 'linux': # Linux (confirmed) # noqa - from serial.tools.list_ports_linux import comports - -elif plat[:6] == 'darwin': # OS X (confirmed) - from serial.tools.list_ports_osx import comports - -elif plat == 'cygwin': # cygwin/win32 - # cygwin accepts /dev/com* in many contexts - # (such as 'open' call, explicit 'ls'), but 'glob.glob' - # and bare 'ls' do not; so use /dev/ttyS* instead - def comports(include_links=False): - devices = glob.glob('/dev/ttyS*') - if include_links: - devices.extend(list_ports_common.list_links(devices)) - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:7] == 'openbsd': # OpenBSD - def comports(include_links=False): - devices = glob.glob('/dev/cua*') - if include_links: - devices.extend(list_ports_common.list_links(devices)) - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:3] == 'bsd' or plat[:7] == 'freebsd': - def comports(include_links=False): - devices = glob.glob('/dev/cua*[!.init][!.lock]') - if include_links: - devices.extend(list_ports_common.list_links(devices)) - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:6] == 'netbsd': # NetBSD - def comports(include_links=False): - """scan for available ports. return a list of device names.""" - devices = glob.glob('/dev/dty*') - if include_links: - devices.extend(list_ports_common.list_links(devices)) - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:4] == 'irix': # IRIX - def comports(include_links=False): - """scan for available ports. return a list of device names.""" - devices = glob.glob('/dev/ttyf*') - if include_links: - devices.extend(list_ports_common.list_links(devices)) - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:2] == 'hp': # HP-UX (not tested) - def comports(include_links=False): - """scan for available ports. return a list of device names.""" - devices = glob.glob('/dev/tty*p0') - if include_links: - devices.extend(list_ports_common.list_links(devices)) - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:5] == 'sunos': # Solaris/SunOS - def comports(include_links=False): - """scan for available ports. return a list of device names.""" - devices = glob.glob('/dev/tty*c') - if include_links: - devices.extend(list_ports_common.list_links(devices)) - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:3] == 'aix': # AIX - def comports(include_links=False): - """scan for available ports. return a list of device names.""" - devices = glob.glob('/dev/tty*') - if include_links: - devices.extend(list_ports_common.list_links(devices)) - return [list_ports_common.ListPortInfo(d) for d in devices] - -else: - # platform detection has failed... - import serial - sys.stderr.write("""\ -don't know how to enumerate ttys on this system. -! I you know how the serial ports are named send this information to -! the author of this module: - -sys.platform = {!r} -os.name = {!r} -pySerial version = {} - -also add the naming scheme of the serial ports and with a bit luck you can get -this module running... -""".format(sys.platform, os.name, serial.VERSION)) - raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name)) - -# test -if __name__ == '__main__': - for port, desc, hwid in sorted(comports()): - print("{}: {} [{}]".format(port, desc, hwid)) diff --git a/extensions/km-plot/deps/serial/tools/list_ports_windows.py b/extensions/km-plot/deps/serial/tools/list_ports_windows.py deleted file mode 100644 index 0b4a5b1..0000000 --- a/extensions/km-plot/deps/serial/tools/list_ports_windows.py +++ /dev/null @@ -1,427 +0,0 @@ -#! python -# -# Enumerate serial ports on Windows including a human readable description -# and hardware information. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2016 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -from __future__ import absolute_import - -# pylint: disable=invalid-name,too-few-public-methods -import re -import ctypes -from ctypes.wintypes import BOOL -from ctypes.wintypes import HWND -from ctypes.wintypes import DWORD -from ctypes.wintypes import WORD -from ctypes.wintypes import LONG -from ctypes.wintypes import ULONG -from ctypes.wintypes import HKEY -from ctypes.wintypes import BYTE -import serial -from serial.win32 import ULONG_PTR -from serial.tools import list_ports_common - - -def ValidHandle(value, func, arguments): - if value == 0: - raise ctypes.WinError() - return value - - -NULL = 0 -HDEVINFO = ctypes.c_void_p -LPCTSTR = ctypes.c_wchar_p -PCTSTR = ctypes.c_wchar_p -PTSTR = ctypes.c_wchar_p -LPDWORD = PDWORD = ctypes.POINTER(DWORD) -#~ LPBYTE = PBYTE = ctypes.POINTER(BYTE) -LPBYTE = PBYTE = ctypes.c_void_p # XXX avoids error about types - -ACCESS_MASK = DWORD -REGSAM = ACCESS_MASK - - -class GUID(ctypes.Structure): - _fields_ = [ - ('Data1', DWORD), - ('Data2', WORD), - ('Data3', WORD), - ('Data4', BYTE * 8), - ] - - def __str__(self): - return "{{{:08x}-{:04x}-{:04x}-{}-{}}}".format( - self.Data1, - self.Data2, - self.Data3, - ''.join(["{:02x}".format(d) for d in self.Data4[:2]]), - ''.join(["{:02x}".format(d) for d in self.Data4[2:]]), - ) - - -class SP_DEVINFO_DATA(ctypes.Structure): - _fields_ = [ - ('cbSize', DWORD), - ('ClassGuid', GUID), - ('DevInst', DWORD), - ('Reserved', ULONG_PTR), - ] - - def __str__(self): - return "ClassGuid:{} DevInst:{}".format(self.ClassGuid, self.DevInst) - - -PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA) - -PSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p - -setupapi = ctypes.windll.LoadLibrary("setupapi") -SetupDiDestroyDeviceInfoList = setupapi.SetupDiDestroyDeviceInfoList -SetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO] -SetupDiDestroyDeviceInfoList.restype = BOOL - -SetupDiClassGuidsFromName = setupapi.SetupDiClassGuidsFromNameW -SetupDiClassGuidsFromName.argtypes = [PCTSTR, ctypes.POINTER(GUID), DWORD, PDWORD] -SetupDiClassGuidsFromName.restype = BOOL - -SetupDiEnumDeviceInfo = setupapi.SetupDiEnumDeviceInfo -SetupDiEnumDeviceInfo.argtypes = [HDEVINFO, DWORD, PSP_DEVINFO_DATA] -SetupDiEnumDeviceInfo.restype = BOOL - -SetupDiGetClassDevs = setupapi.SetupDiGetClassDevsW -SetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD] -SetupDiGetClassDevs.restype = HDEVINFO -SetupDiGetClassDevs.errcheck = ValidHandle - -SetupDiGetDeviceRegistryProperty = setupapi.SetupDiGetDeviceRegistryPropertyW -SetupDiGetDeviceRegistryProperty.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD] -SetupDiGetDeviceRegistryProperty.restype = BOOL - -SetupDiGetDeviceInstanceId = setupapi.SetupDiGetDeviceInstanceIdW -SetupDiGetDeviceInstanceId.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, PTSTR, DWORD, PDWORD] -SetupDiGetDeviceInstanceId.restype = BOOL - -SetupDiOpenDevRegKey = setupapi.SetupDiOpenDevRegKey -SetupDiOpenDevRegKey.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM] -SetupDiOpenDevRegKey.restype = HKEY - -advapi32 = ctypes.windll.LoadLibrary("Advapi32") -RegCloseKey = advapi32.RegCloseKey -RegCloseKey.argtypes = [HKEY] -RegCloseKey.restype = LONG - -RegQueryValueEx = advapi32.RegQueryValueExW -RegQueryValueEx.argtypes = [HKEY, LPCTSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD] -RegQueryValueEx.restype = LONG - -cfgmgr32 = ctypes.windll.LoadLibrary("Cfgmgr32") -CM_Get_Parent = cfgmgr32.CM_Get_Parent -CM_Get_Parent.argtypes = [PDWORD, DWORD, ULONG] -CM_Get_Parent.restype = LONG - -CM_Get_Device_IDW = cfgmgr32.CM_Get_Device_IDW -CM_Get_Device_IDW.argtypes = [DWORD, PTSTR, ULONG, ULONG] -CM_Get_Device_IDW.restype = LONG - -CM_MapCrToWin32Err = cfgmgr32.CM_MapCrToWin32Err -CM_MapCrToWin32Err.argtypes = [DWORD, DWORD] -CM_MapCrToWin32Err.restype = DWORD - - -DIGCF_PRESENT = 2 -DIGCF_DEVICEINTERFACE = 16 -INVALID_HANDLE_VALUE = 0 -ERROR_INSUFFICIENT_BUFFER = 122 -ERROR_NOT_FOUND = 1168 -SPDRP_HARDWAREID = 1 -SPDRP_FRIENDLYNAME = 12 -SPDRP_LOCATION_PATHS = 35 -SPDRP_MFG = 11 -DICS_FLAG_GLOBAL = 1 -DIREG_DEV = 0x00000001 -KEY_READ = 0x20019 - - -MAX_USB_DEVICE_TREE_TRAVERSAL_DEPTH = 5 - - -def get_parent_serial_number(child_devinst, child_vid, child_pid, depth=0, last_serial_number=None): - """ Get the serial number of the parent of a device. - - Args: - child_devinst: The device instance handle to get the parent serial number of. - child_vid: The vendor ID of the child device. - child_pid: The product ID of the child device. - depth: The current iteration depth of the USB device tree. - """ - - # If the traversal depth is beyond the max, abandon attempting to find the serial number. - if depth > MAX_USB_DEVICE_TREE_TRAVERSAL_DEPTH: - return '' if not last_serial_number else last_serial_number - - # Get the parent device instance. - devinst = DWORD() - ret = CM_Get_Parent(ctypes.byref(devinst), child_devinst, 0) - - if ret: - win_error = CM_MapCrToWin32Err(DWORD(ret), DWORD(0)) - - # If there is no parent available, the child was the root device. We cannot traverse - # further. - if win_error == ERROR_NOT_FOUND: - return '' if not last_serial_number else last_serial_number - - raise ctypes.WinError(win_error) - - # Get the ID of the parent device and parse it for vendor ID, product ID, and serial number. - parentHardwareID = ctypes.create_unicode_buffer(250) - - ret = CM_Get_Device_IDW( - devinst, - parentHardwareID, - ctypes.sizeof(parentHardwareID) - 1, - 0) - - if ret: - raise ctypes.WinError(CM_MapCrToWin32Err(DWORD(ret), DWORD(0))) - - parentHardwareID_str = parentHardwareID.value - m = re.search(r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(&MI_(\d{2}))?(\\(.*))?', - parentHardwareID_str, - re.I) - - # return early if we have no matches (likely malformed serial, traversed too far) - if not m: - return '' if not last_serial_number else last_serial_number - - vid = None - pid = None - serial_number = None - if m.group(1): - vid = int(m.group(1), 16) - if m.group(3): - pid = int(m.group(3), 16) - if m.group(7): - serial_number = m.group(7) - - # store what we found as a fallback for malformed serial values up the chain - found_serial_number = serial_number - - # Check that the USB serial number only contains alpha-numeric characters. It may be a windows - # device ID (ephemeral ID). - if serial_number and not re.match(r'^\w+$', serial_number): - serial_number = None - - if not vid or not pid: - # If pid and vid are not available at this device level, continue to the parent. - return get_parent_serial_number(devinst, child_vid, child_pid, depth + 1, found_serial_number) - - if pid != child_pid or vid != child_vid: - # If the VID or PID has changed, we are no longer looking at the same physical device. The - # serial number is unknown. - return '' if not last_serial_number else last_serial_number - - # In this case, the vid and pid of the parent device are identical to the child. However, if - # there still isn't a serial number available, continue to the next parent. - if not serial_number: - return get_parent_serial_number(devinst, child_vid, child_pid, depth + 1, found_serial_number) - - # Finally, the VID and PID are identical to the child and a serial number is present, so return - # it. - return serial_number - - -def iterate_comports(): - """Return a generator that yields descriptions for serial ports""" - PortsGUIDs = (GUID * 8)() # so far only seen one used, so hope 8 are enough... - ports_guids_size = DWORD() - if not SetupDiClassGuidsFromName( - "Ports", - PortsGUIDs, - ctypes.sizeof(PortsGUIDs), - ctypes.byref(ports_guids_size)): - raise ctypes.WinError() - - ModemsGUIDs = (GUID * 8)() # so far only seen one used, so hope 8 are enough... - modems_guids_size = DWORD() - if not SetupDiClassGuidsFromName( - "Modem", - ModemsGUIDs, - ctypes.sizeof(ModemsGUIDs), - ctypes.byref(modems_guids_size)): - raise ctypes.WinError() - - GUIDs = PortsGUIDs[:ports_guids_size.value] + ModemsGUIDs[:modems_guids_size.value] - - # repeat for all possible GUIDs - for index in range(len(GUIDs)): - bInterfaceNumber = None - g_hdi = SetupDiGetClassDevs( - ctypes.byref(GUIDs[index]), - None, - NULL, - DIGCF_PRESENT) # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports - - devinfo = SP_DEVINFO_DATA() - devinfo.cbSize = ctypes.sizeof(devinfo) - index = 0 - while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)): - index += 1 - - # get the real com port name - hkey = SetupDiOpenDevRegKey( - g_hdi, - ctypes.byref(devinfo), - DICS_FLAG_GLOBAL, - 0, - DIREG_DEV, # DIREG_DRV for SW info - KEY_READ) - port_name_buffer = ctypes.create_unicode_buffer(250) - port_name_length = ULONG(ctypes.sizeof(port_name_buffer)) - RegQueryValueEx( - hkey, - "PortName", - None, - None, - ctypes.byref(port_name_buffer), - ctypes.byref(port_name_length)) - RegCloseKey(hkey) - - # unfortunately does this method also include parallel ports. - # we could check for names starting with COM or just exclude LPT - # and hope that other "unknown" names are serial ports... - if port_name_buffer.value.startswith('LPT'): - continue - - # hardware ID - szHardwareID = ctypes.create_unicode_buffer(250) - # try to get ID that includes serial number - if not SetupDiGetDeviceInstanceId( - g_hdi, - ctypes.byref(devinfo), - #~ ctypes.byref(szHardwareID), - szHardwareID, - ctypes.sizeof(szHardwareID) - 1, - None): - # fall back to more generic hardware ID if that would fail - if not SetupDiGetDeviceRegistryProperty( - g_hdi, - ctypes.byref(devinfo), - SPDRP_HARDWAREID, - None, - ctypes.byref(szHardwareID), - ctypes.sizeof(szHardwareID) - 1, - None): - # Ignore ERROR_INSUFFICIENT_BUFFER - if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: - raise ctypes.WinError() - # stringify - szHardwareID_str = szHardwareID.value - - info = list_ports_common.ListPortInfo(port_name_buffer.value, skip_link_detection=True) - - # in case of USB, make a more readable string, similar to that form - # that we also generate on other platforms - if szHardwareID_str.startswith('USB'): - m = re.search(r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(&MI_(\d{2}))?(\\(.*))?', szHardwareID_str, re.I) - if m: - info.vid = int(m.group(1), 16) - if m.group(3): - info.pid = int(m.group(3), 16) - if m.group(5): - bInterfaceNumber = int(m.group(5)) - - # Check that the USB serial number only contains alpha-numeric characters. It - # may be a windows device ID (ephemeral ID) for composite devices. - if m.group(7) and re.match(r'^\w+$', m.group(7)): - info.serial_number = m.group(7) - else: - info.serial_number = get_parent_serial_number(devinfo.DevInst, info.vid, info.pid) - - # calculate a location string - loc_path_str = ctypes.create_unicode_buffer(250) - if SetupDiGetDeviceRegistryProperty( - g_hdi, - ctypes.byref(devinfo), - SPDRP_LOCATION_PATHS, - None, - ctypes.byref(loc_path_str), - ctypes.sizeof(loc_path_str) - 1, - None): - m = re.finditer(r'USBROOT\((\w+)\)|#USB\((\w+)\)', loc_path_str.value) - location = [] - for g in m: - if g.group(1): - location.append('{:d}'.format(int(g.group(1)) + 1)) - else: - if len(location) > 1: - location.append('.') - else: - location.append('-') - location.append(g.group(2)) - if bInterfaceNumber is not None: - location.append(':{}.{}'.format( - 'x', # XXX how to determine correct bConfigurationValue? - bInterfaceNumber)) - if location: - info.location = ''.join(location) - info.hwid = info.usb_info() - elif szHardwareID_str.startswith('FTDIBUS'): - m = re.search(r'VID_([0-9a-f]{4})\+PID_([0-9a-f]{4})(\+(\w+))?', szHardwareID_str, re.I) - if m: - info.vid = int(m.group(1), 16) - info.pid = int(m.group(2), 16) - if m.group(4): - info.serial_number = m.group(4) - # USB location is hidden by FDTI driver :( - info.hwid = info.usb_info() - else: - info.hwid = szHardwareID_str - - # friendly name - szFriendlyName = ctypes.create_unicode_buffer(250) - if SetupDiGetDeviceRegistryProperty( - g_hdi, - ctypes.byref(devinfo), - SPDRP_FRIENDLYNAME, - #~ SPDRP_DEVICEDESC, - None, - ctypes.byref(szFriendlyName), - ctypes.sizeof(szFriendlyName) - 1, - None): - info.description = szFriendlyName.value - #~ else: - # Ignore ERROR_INSUFFICIENT_BUFFER - #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: - #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value)) - # ignore errors and still include the port in the list, friendly name will be same as port name - - # manufacturer - szManufacturer = ctypes.create_unicode_buffer(250) - if SetupDiGetDeviceRegistryProperty( - g_hdi, - ctypes.byref(devinfo), - SPDRP_MFG, - #~ SPDRP_DEVICEDESC, - None, - ctypes.byref(szManufacturer), - ctypes.sizeof(szManufacturer) - 1, - None): - info.manufacturer = szManufacturer.value - yield info - SetupDiDestroyDeviceInfoList(g_hdi) - - -def comports(include_links=False): - """Return a list of info objects about serial ports""" - return list(iterate_comports()) - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - for port, desc, hwid in sorted(comports()): - print("{}: {} [{}]".format(port, desc, hwid)) diff --git a/extensions/km-plot/deps/serial/tools/miniterm.py b/extensions/km-plot/deps/serial/tools/miniterm.py deleted file mode 100644 index 2cceff6..0000000 --- a/extensions/km-plot/deps/serial/tools/miniterm.py +++ /dev/null @@ -1,1042 +0,0 @@ -#!/usr/bin/env python -# -# Very simple serial terminal -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C)2002-2020 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -from __future__ import absolute_import - -import codecs -import os -import sys -import threading - -import serial -from serial.tools.list_ports import comports -from serial.tools import hexlify_codec - -# pylint: disable=wrong-import-order,wrong-import-position - -codecs.register(lambda c: hexlify_codec.getregentry() if c == 'hexlify' else None) - -try: - raw_input -except NameError: - # pylint: disable=redefined-builtin,invalid-name - raw_input = input # in python3 it's "raw" - unichr = chr - - -def key_description(character): - """generate a readable description for a key""" - ascii_code = ord(character) - if ascii_code < 32: - return 'Ctrl+{:c}'.format(ord('@') + ascii_code) - else: - return repr(character) - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -class ConsoleBase(object): - """OS abstraction for console (input/output codec, no echo)""" - - def __init__(self): - if sys.version_info >= (3, 0): - self.byte_output = sys.stdout.buffer - else: - self.byte_output = sys.stdout - self.output = sys.stdout - - def setup(self): - """Set console to read single characters, no echo""" - - def cleanup(self): - """Restore default console settings""" - - def getkey(self): - """Read a single key from the console""" - return None - - def write_bytes(self, byte_string): - """Write bytes (already encoded)""" - self.byte_output.write(byte_string) - self.byte_output.flush() - - def write(self, text): - """Write string""" - self.output.write(text) - self.output.flush() - - def cancel(self): - """Cancel getkey operation""" - - # - - - - - - - - - - - - - - - - - - - - - - - - - # context manager: - # switch terminal temporary to normal mode (e.g. to get user input) - - def __enter__(self): - self.cleanup() - return self - - def __exit__(self, *args, **kwargs): - self.setup() - - -if os.name == 'nt': # noqa - import msvcrt - import ctypes - import platform - - class Out(object): - """file-like wrapper that uses os.write""" - - def __init__(self, fd): - self.fd = fd - - def flush(self): - pass - - def write(self, s): - os.write(self.fd, s) - - class Console(ConsoleBase): - fncodes = { - ';': '\1bOP', # F1 - '<': '\1bOQ', # F2 - '=': '\1bOR', # F3 - '>': '\1bOS', # F4 - '?': '\1b[15~', # F5 - '@': '\1b[17~', # F6 - 'A': '\1b[18~', # F7 - 'B': '\1b[19~', # F8 - 'C': '\1b[20~', # F9 - 'D': '\1b[21~', # F10 - } - navcodes = { - 'H': '\x1b[A', # UP - 'P': '\x1b[B', # DOWN - 'K': '\x1b[D', # LEFT - 'M': '\x1b[C', # RIGHT - 'G': '\x1b[H', # HOME - 'O': '\x1b[F', # END - 'R': '\x1b[2~', # INSERT - 'S': '\x1b[3~', # DELETE - 'I': '\x1b[5~', # PGUP - 'Q': '\x1b[6~', # PGDN - } - - def __init__(self): - super(Console, self).__init__() - self._saved_ocp = ctypes.windll.kernel32.GetConsoleOutputCP() - self._saved_icp = ctypes.windll.kernel32.GetConsoleCP() - ctypes.windll.kernel32.SetConsoleOutputCP(65001) - ctypes.windll.kernel32.SetConsoleCP(65001) - # ANSI handling available through SetConsoleMode since Windows 10 v1511 - # https://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-win10th2-1 - if platform.release() == '10' and int(platform.version().split('.')[2]) > 10586: - ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 - import ctypes.wintypes as wintypes - if not hasattr(wintypes, 'LPDWORD'): # PY2 - wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD) - SetConsoleMode = ctypes.windll.kernel32.SetConsoleMode - GetConsoleMode = ctypes.windll.kernel32.GetConsoleMode - GetStdHandle = ctypes.windll.kernel32.GetStdHandle - mode = wintypes.DWORD() - GetConsoleMode(GetStdHandle(-11), ctypes.byref(mode)) - if (mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0: - SetConsoleMode(GetStdHandle(-11), mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING) - self._saved_cm = mode - self.output = codecs.getwriter('UTF-8')(Out(sys.stdout.fileno()), 'replace') - # the change of the code page is not propagated to Python, manually fix it - sys.stderr = codecs.getwriter('UTF-8')(Out(sys.stderr.fileno()), 'replace') - sys.stdout = self.output - self.output.encoding = 'UTF-8' # needed for input - - def __del__(self): - ctypes.windll.kernel32.SetConsoleOutputCP(self._saved_ocp) - ctypes.windll.kernel32.SetConsoleCP(self._saved_icp) - try: - ctypes.windll.kernel32.SetConsoleMode(ctypes.windll.kernel32.GetStdHandle(-11), self._saved_cm) - except AttributeError: # in case no _saved_cm - pass - - def getkey(self): - while True: - z = msvcrt.getwch() - if z == unichr(13): - return unichr(10) - elif z is unichr(0) or z is unichr(0xe0): - try: - code = msvcrt.getwch() - if z is unichr(0): - return self.fncodes[code] - else: - return self.navcodes[code] - except KeyError: - pass - else: - return z - - def cancel(self): - # CancelIo, CancelSynchronousIo do not seem to work when using - # getwch, so instead, send a key to the window with the console - hwnd = ctypes.windll.kernel32.GetConsoleWindow() - ctypes.windll.user32.PostMessageA(hwnd, 0x100, 0x0d, 0) - -elif os.name == 'posix': - import atexit - import termios - import fcntl - - class Console(ConsoleBase): - def __init__(self): - super(Console, self).__init__() - self.fd = sys.stdin.fileno() - self.old = termios.tcgetattr(self.fd) - atexit.register(self.cleanup) - if sys.version_info < (3, 0): - self.enc_stdin = codecs.getreader(sys.stdin.encoding)(sys.stdin) - else: - self.enc_stdin = sys.stdin - - def setup(self): - new = termios.tcgetattr(self.fd) - new[3] = new[3] & ~termios.ICANON & ~termios.ECHO & ~termios.ISIG - new[6][termios.VMIN] = 1 - new[6][termios.VTIME] = 0 - termios.tcsetattr(self.fd, termios.TCSANOW, new) - - def getkey(self): - c = self.enc_stdin.read(1) - if c == unichr(0x7f): - c = unichr(8) # map the BS key (which yields DEL) to backspace - return c - - def cancel(self): - fcntl.ioctl(self.fd, termios.TIOCSTI, b'\0') - - def cleanup(self): - termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old) - -else: - raise NotImplementedError( - 'Sorry no implementation for your platform ({}) available.'.format(sys.platform)) - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -class Transform(object): - """do-nothing: forward all data unchanged""" - def rx(self, text): - """text received from serial port""" - return text - - def tx(self, text): - """text to be sent to serial port""" - return text - - def echo(self, text): - """text to be sent but displayed on console""" - return text - - -class CRLF(Transform): - """ENTER sends CR+LF""" - - def tx(self, text): - return text.replace('\n', '\r\n') - - -class CR(Transform): - """ENTER sends CR""" - - def rx(self, text): - return text.replace('\r', '\n') - - def tx(self, text): - return text.replace('\n', '\r') - - -class LF(Transform): - """ENTER sends LF""" - - -class NoTerminal(Transform): - """remove typical terminal control codes from input""" - - REPLACEMENT_MAP = dict((x, 0x2400 + x) for x in range(32) if unichr(x) not in '\r\n\b\t') - REPLACEMENT_MAP.update( - { - 0x7F: 0x2421, # DEL - 0x9B: 0x2425, # CSI - }) - - def rx(self, text): - return text.translate(self.REPLACEMENT_MAP) - - echo = rx - - -class NoControls(NoTerminal): - """Remove all control codes, incl. CR+LF""" - - REPLACEMENT_MAP = dict((x, 0x2400 + x) for x in range(32)) - REPLACEMENT_MAP.update( - { - 0x20: 0x2423, # visual space - 0x7F: 0x2421, # DEL - 0x9B: 0x2425, # CSI - }) - - -class Printable(Transform): - """Show decimal code for all non-ASCII characters and replace most control codes""" - - def rx(self, text): - r = [] - for c in text: - if ' ' <= c < '\x7f' or c in '\r\n\b\t': - r.append(c) - elif c < ' ': - r.append(unichr(0x2400 + ord(c))) - else: - r.extend(unichr(0x2080 + ord(d) - 48) for d in '{:d}'.format(ord(c))) - r.append(' ') - return ''.join(r) - - echo = rx - - -class Colorize(Transform): - """Apply different colors for received and echo""" - - def __init__(self): - # XXX make it configurable, use colorama? - self.input_color = '\x1b[37m' - self.echo_color = '\x1b[31m' - - def rx(self, text): - return self.input_color + text - - def echo(self, text): - return self.echo_color + text - - -class DebugIO(Transform): - """Print what is sent and received""" - - def rx(self, text): - sys.stderr.write(' [RX:{!r}] '.format(text)) - sys.stderr.flush() - return text - - def tx(self, text): - sys.stderr.write(' [TX:{!r}] '.format(text)) - sys.stderr.flush() - return text - - -# other ideas: -# - add date/time for each newline -# - insert newline after: a) timeout b) packet end character - -EOL_TRANSFORMATIONS = { - 'crlf': CRLF, - 'cr': CR, - 'lf': LF, -} - -TRANSFORMATIONS = { - 'direct': Transform, # no transformation - 'default': NoTerminal, - 'nocontrol': NoControls, - 'printable': Printable, - 'colorize': Colorize, - 'debug': DebugIO, -} - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def ask_for_port(): - """\ - Show a list of ports and ask the user for a choice. To make selection - easier on systems with long device names, also allow the input of an - index. - """ - sys.stderr.write('\n--- Available ports:\n') - ports = [] - for n, (port, desc, hwid) in enumerate(sorted(comports()), 1): - sys.stderr.write('--- {:2}: {:20} {!r}\n'.format(n, port, desc)) - ports.append(port) - while True: - port = raw_input('--- Enter port index or full name: ') - try: - index = int(port) - 1 - if not 0 <= index < len(ports): - sys.stderr.write('--- Invalid index!\n') - continue - except ValueError: - pass - else: - port = ports[index] - return port - - -class Miniterm(object): - """\ - Terminal application. Copy data from serial port to console and vice versa. - Handle special keys from the console to show menu etc. - """ - - def __init__(self, serial_instance, echo=False, eol='crlf', filters=()): - self.console = Console() - self.serial = serial_instance - self.echo = echo - self.raw = False - self.input_encoding = 'UTF-8' - self.output_encoding = 'UTF-8' - self.eol = eol - self.filters = filters - self.update_transformations() - self.exit_character = unichr(0x1d) # GS/CTRL+] - self.menu_character = unichr(0x14) # Menu: CTRL+T - self.alive = None - self._reader_alive = None - self.receiver_thread = None - self.rx_decoder = None - self.tx_decoder = None - - def _start_reader(self): - """Start reader thread""" - self._reader_alive = True - # start serial->console thread - self.receiver_thread = threading.Thread(target=self.reader, name='rx') - self.receiver_thread.daemon = True - self.receiver_thread.start() - - def _stop_reader(self): - """Stop reader thread only, wait for clean exit of thread""" - self._reader_alive = False - if hasattr(self.serial, 'cancel_read'): - self.serial.cancel_read() - self.receiver_thread.join() - - def start(self): - """start worker threads""" - self.alive = True - self._start_reader() - # enter console->serial loop - self.transmitter_thread = threading.Thread(target=self.writer, name='tx') - self.transmitter_thread.daemon = True - self.transmitter_thread.start() - self.console.setup() - - def stop(self): - """set flag to stop worker threads""" - self.alive = False - - def join(self, transmit_only=False): - """wait for worker threads to terminate""" - self.transmitter_thread.join() - if not transmit_only: - if hasattr(self.serial, 'cancel_read'): - self.serial.cancel_read() - self.receiver_thread.join() - - def close(self): - self.serial.close() - - def update_transformations(self): - """take list of transformation classes and instantiate them for rx and tx""" - transformations = [EOL_TRANSFORMATIONS[self.eol]] + [TRANSFORMATIONS[f] - for f in self.filters] - self.tx_transformations = [t() for t in transformations] - self.rx_transformations = list(reversed(self.tx_transformations)) - - def set_rx_encoding(self, encoding, errors='replace'): - """set encoding for received data""" - self.input_encoding = encoding - self.rx_decoder = codecs.getincrementaldecoder(encoding)(errors) - - def set_tx_encoding(self, encoding, errors='replace'): - """set encoding for transmitted data""" - self.output_encoding = encoding - self.tx_encoder = codecs.getincrementalencoder(encoding)(errors) - - def dump_port_settings(self): - """Write current settings to sys.stderr""" - sys.stderr.write("\n--- Settings: {p.name} {p.baudrate},{p.bytesize},{p.parity},{p.stopbits}\n".format( - p=self.serial)) - sys.stderr.write('--- RTS: {:8} DTR: {:8} BREAK: {:8}\n'.format( - ('active' if self.serial.rts else 'inactive'), - ('active' if self.serial.dtr else 'inactive'), - ('active' if self.serial.break_condition else 'inactive'))) - try: - sys.stderr.write('--- CTS: {:8} DSR: {:8} RI: {:8} CD: {:8}\n'.format( - ('active' if self.serial.cts else 'inactive'), - ('active' if self.serial.dsr else 'inactive'), - ('active' if self.serial.ri else 'inactive'), - ('active' if self.serial.cd else 'inactive'))) - except serial.SerialException: - # on RFC 2217 ports, it can happen if no modem state notification was - # yet received. ignore this error. - pass - sys.stderr.write('--- software flow control: {}\n'.format('active' if self.serial.xonxoff else 'inactive')) - sys.stderr.write('--- hardware flow control: {}\n'.format('active' if self.serial.rtscts else 'inactive')) - sys.stderr.write('--- serial input encoding: {}\n'.format(self.input_encoding)) - sys.stderr.write('--- serial output encoding: {}\n'.format(self.output_encoding)) - sys.stderr.write('--- EOL: {}\n'.format(self.eol.upper())) - sys.stderr.write('--- filters: {}\n'.format(' '.join(self.filters))) - - def reader(self): - """loop and copy serial->console""" - try: - while self.alive and self._reader_alive: - # read all that is there or wait for one byte - data = self.serial.read(self.serial.in_waiting or 1) - if data: - if self.raw: - self.console.write_bytes(data) - else: - text = self.rx_decoder.decode(data) - for transformation in self.rx_transformations: - text = transformation.rx(text) - self.console.write(text) - except serial.SerialException: - self.alive = False - self.console.cancel() - raise # XXX handle instead of re-raise? - - def writer(self): - """\ - Loop and copy console->serial until self.exit_character character is - found. When self.menu_character is found, interpret the next key - locally. - """ - menu_active = False - try: - while self.alive: - try: - c = self.console.getkey() - except KeyboardInterrupt: - c = '\x03' - if not self.alive: - break - if menu_active: - self.handle_menu_key(c) - menu_active = False - elif c == self.menu_character: - menu_active = True # next char will be for menu - elif c == self.exit_character: - self.stop() # exit app - break - else: - #~ if self.raw: - text = c - for transformation in self.tx_transformations: - text = transformation.tx(text) - self.serial.write(self.tx_encoder.encode(text)) - if self.echo: - echo_text = c - for transformation in self.tx_transformations: - echo_text = transformation.echo(echo_text) - self.console.write(echo_text) - except: - self.alive = False - raise - - def handle_menu_key(self, c): - """Implement a simple menu / settings""" - if c == self.menu_character or c == self.exit_character: - # Menu/exit character again -> send itself - self.serial.write(self.tx_encoder.encode(c)) - if self.echo: - self.console.write(c) - elif c == '\x15': # CTRL+U -> upload file - self.upload_file() - elif c in '\x08hH?': # CTRL+H, h, H, ? -> Show help - sys.stderr.write(self.get_help_text()) - elif c == '\x12': # CTRL+R -> Toggle RTS - self.serial.rts = not self.serial.rts - sys.stderr.write('--- RTS {} ---\n'.format('active' if self.serial.rts else 'inactive')) - elif c == '\x04': # CTRL+D -> Toggle DTR - self.serial.dtr = not self.serial.dtr - sys.stderr.write('--- DTR {} ---\n'.format('active' if self.serial.dtr else 'inactive')) - elif c == '\x02': # CTRL+B -> toggle BREAK condition - self.serial.break_condition = not self.serial.break_condition - sys.stderr.write('--- BREAK {} ---\n'.format('active' if self.serial.break_condition else 'inactive')) - elif c == '\x05': # CTRL+E -> toggle local echo - self.echo = not self.echo - sys.stderr.write('--- local echo {} ---\n'.format('active' if self.echo else 'inactive')) - elif c == '\x06': # CTRL+F -> edit filters - self.change_filter() - elif c == '\x0c': # CTRL+L -> EOL mode - modes = list(EOL_TRANSFORMATIONS) # keys - eol = modes.index(self.eol) + 1 - if eol >= len(modes): - eol = 0 - self.eol = modes[eol] - sys.stderr.write('--- EOL: {} ---\n'.format(self.eol.upper())) - self.update_transformations() - elif c == '\x01': # CTRL+A -> set encoding - self.change_encoding() - elif c == '\x09': # CTRL+I -> info - self.dump_port_settings() - #~ elif c == '\x01': # CTRL+A -> cycle escape mode - #~ elif c == '\x0c': # CTRL+L -> cycle linefeed mode - elif c in 'pP': # P -> change port - self.change_port() - elif c in 'zZ': # S -> suspend / open port temporarily - self.suspend_port() - elif c in 'bB': # B -> change baudrate - self.change_baudrate() - elif c == '8': # 8 -> change to 8 bits - self.serial.bytesize = serial.EIGHTBITS - self.dump_port_settings() - elif c == '7': # 7 -> change to 8 bits - self.serial.bytesize = serial.SEVENBITS - self.dump_port_settings() - elif c in 'eE': # E -> change to even parity - self.serial.parity = serial.PARITY_EVEN - self.dump_port_settings() - elif c in 'oO': # O -> change to odd parity - self.serial.parity = serial.PARITY_ODD - self.dump_port_settings() - elif c in 'mM': # M -> change to mark parity - self.serial.parity = serial.PARITY_MARK - self.dump_port_settings() - elif c in 'sS': # S -> change to space parity - self.serial.parity = serial.PARITY_SPACE - self.dump_port_settings() - elif c in 'nN': # N -> change to no parity - self.serial.parity = serial.PARITY_NONE - self.dump_port_settings() - elif c == '1': # 1 -> change to 1 stop bits - self.serial.stopbits = serial.STOPBITS_ONE - self.dump_port_settings() - elif c == '2': # 2 -> change to 2 stop bits - self.serial.stopbits = serial.STOPBITS_TWO - self.dump_port_settings() - elif c == '3': # 3 -> change to 1.5 stop bits - self.serial.stopbits = serial.STOPBITS_ONE_POINT_FIVE - self.dump_port_settings() - elif c in 'xX': # X -> change software flow control - self.serial.xonxoff = (c == 'X') - self.dump_port_settings() - elif c in 'rR': # R -> change hardware flow control - self.serial.rtscts = (c == 'R') - self.dump_port_settings() - elif c in 'qQ': - self.stop() # Q -> exit app - else: - sys.stderr.write('--- unknown menu character {} --\n'.format(key_description(c))) - - def upload_file(self): - """Ask user for filenname and send its contents""" - sys.stderr.write('\n--- File to upload: ') - sys.stderr.flush() - with self.console: - filename = sys.stdin.readline().rstrip('\r\n') - if filename: - try: - with open(filename, 'rb') as f: - sys.stderr.write('--- Sending file {} ---\n'.format(filename)) - while True: - block = f.read(1024) - if not block: - break - self.serial.write(block) - # Wait for output buffer to drain. - self.serial.flush() - sys.stderr.write('.') # Progress indicator. - sys.stderr.write('\n--- File {} sent ---\n'.format(filename)) - except IOError as e: - sys.stderr.write('--- ERROR opening file {}: {} ---\n'.format(filename, e)) - - def change_filter(self): - """change the i/o transformations""" - sys.stderr.write('\n--- Available Filters:\n') - sys.stderr.write('\n'.join( - '--- {:<10} = {.__doc__}'.format(k, v) - for k, v in sorted(TRANSFORMATIONS.items()))) - sys.stderr.write('\n--- Enter new filter name(s) [{}]: '.format(' '.join(self.filters))) - with self.console: - new_filters = sys.stdin.readline().lower().split() - if new_filters: - for f in new_filters: - if f not in TRANSFORMATIONS: - sys.stderr.write('--- unknown filter: {!r}\n'.format(f)) - break - else: - self.filters = new_filters - self.update_transformations() - sys.stderr.write('--- filters: {}\n'.format(' '.join(self.filters))) - - def change_encoding(self): - """change encoding on the serial port""" - sys.stderr.write('\n--- Enter new encoding name [{}]: '.format(self.input_encoding)) - with self.console: - new_encoding = sys.stdin.readline().strip() - if new_encoding: - try: - codecs.lookup(new_encoding) - except LookupError: - sys.stderr.write('--- invalid encoding name: {}\n'.format(new_encoding)) - else: - self.set_rx_encoding(new_encoding) - self.set_tx_encoding(new_encoding) - sys.stderr.write('--- serial input encoding: {}\n'.format(self.input_encoding)) - sys.stderr.write('--- serial output encoding: {}\n'.format(self.output_encoding)) - - def change_baudrate(self): - """change the baudrate""" - sys.stderr.write('\n--- Baudrate: ') - sys.stderr.flush() - with self.console: - backup = self.serial.baudrate - try: - self.serial.baudrate = int(sys.stdin.readline().strip()) - except ValueError as e: - sys.stderr.write('--- ERROR setting baudrate: {} ---\n'.format(e)) - self.serial.baudrate = backup - else: - self.dump_port_settings() - - def change_port(self): - """Have a conversation with the user to change the serial port""" - with self.console: - try: - port = ask_for_port() - except KeyboardInterrupt: - port = None - if port and port != self.serial.port: - # reader thread needs to be shut down - self._stop_reader() - # save settings - settings = self.serial.getSettingsDict() - try: - new_serial = serial.serial_for_url(port, do_not_open=True) - # restore settings and open - new_serial.applySettingsDict(settings) - new_serial.rts = self.serial.rts - new_serial.dtr = self.serial.dtr - new_serial.open() - new_serial.break_condition = self.serial.break_condition - except Exception as e: - sys.stderr.write('--- ERROR opening new port: {} ---\n'.format(e)) - new_serial.close() - else: - self.serial.close() - self.serial = new_serial - sys.stderr.write('--- Port changed to: {} ---\n'.format(self.serial.port)) - # and restart the reader thread - self._start_reader() - - def suspend_port(self): - """\ - open port temporarily, allow reconnect, exit and port change to get - out of the loop - """ - # reader thread needs to be shut down - self._stop_reader() - self.serial.close() - sys.stderr.write('\n--- Port closed: {} ---\n'.format(self.serial.port)) - do_change_port = False - while not self.serial.is_open: - sys.stderr.write('--- Quit: {exit} | p: port change | any other key to reconnect ---\n'.format( - exit=key_description(self.exit_character))) - k = self.console.getkey() - if k == self.exit_character: - self.stop() # exit app - break - elif k in 'pP': - do_change_port = True - break - try: - self.serial.open() - except Exception as e: - sys.stderr.write('--- ERROR opening port: {} ---\n'.format(e)) - if do_change_port: - self.change_port() - else: - # and restart the reader thread - self._start_reader() - sys.stderr.write('--- Port opened: {} ---\n'.format(self.serial.port)) - - def get_help_text(self): - """return the help text""" - # help text, starts with blank line! - return """ ---- pySerial ({version}) - miniterm - help ---- ---- {exit:8} Exit program (alias {menu} Q) ---- {menu:8} Menu escape key, followed by: ---- Menu keys: ---- {menu:7} Send the menu character itself to remote ---- {exit:7} Send the exit character itself to remote ---- {info:7} Show info ---- {upload:7} Upload file (prompt will be shown) ---- {repr:7} encoding ---- {filter:7} edit filters ---- Toggles: ---- {rts:7} RTS {dtr:7} DTR {brk:7} BREAK ---- {echo:7} echo {eol:7} EOL ---- ---- Port settings ({menu} followed by the following): ---- p change port ---- 7 8 set data bits ---- N E O S M change parity (None, Even, Odd, Space, Mark) ---- 1 2 3 set stop bits (1, 2, 1.5) ---- b change baud rate ---- x X disable/enable software flow control ---- r R disable/enable hardware flow control -""".format(version=getattr(serial, 'VERSION', 'unknown version'), - exit=key_description(self.exit_character), - menu=key_description(self.menu_character), - rts=key_description('\x12'), - dtr=key_description('\x04'), - brk=key_description('\x02'), - echo=key_description('\x05'), - info=key_description('\x09'), - upload=key_description('\x15'), - repr=key_description('\x01'), - filter=key_description('\x06'), - eol=key_description('\x0c')) - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# default args can be used to override when calling main() from an other script -# e.g to create a miniterm-my-device.py -def main(default_port=None, default_baudrate=9600, default_rts=None, default_dtr=None): - """Command line tool, entry point""" - - import argparse - - parser = argparse.ArgumentParser( - description='Miniterm - A simple terminal program for the serial port.') - - parser.add_argument( - 'port', - nargs='?', - help='serial port name ("-" to show port list)', - default=default_port) - - parser.add_argument( - 'baudrate', - nargs='?', - type=int, - help='set baud rate, default: %(default)s', - default=default_baudrate) - - group = parser.add_argument_group('port settings') - - group.add_argument( - '--parity', - choices=['N', 'E', 'O', 'S', 'M'], - type=lambda c: c.upper(), - help='set parity, one of {N E O S M}, default: N', - default='N') - - group.add_argument( - '--rtscts', - action='store_true', - help='enable RTS/CTS flow control (default off)', - default=False) - - group.add_argument( - '--xonxoff', - action='store_true', - help='enable software flow control (default off)', - default=False) - - group.add_argument( - '--rts', - type=int, - help='set initial RTS line state (possible values: 0, 1)', - default=default_rts) - - group.add_argument( - '--dtr', - type=int, - help='set initial DTR line state (possible values: 0, 1)', - default=default_dtr) - - group.add_argument( - '--non-exclusive', - dest='exclusive', - action='store_false', - help='disable locking for native ports', - default=True) - - group.add_argument( - '--ask', - action='store_true', - help='ask again for port when open fails', - default=False) - - group = parser.add_argument_group('data handling') - - group.add_argument( - '-e', '--echo', - action='store_true', - help='enable local echo (default off)', - default=False) - - group.add_argument( - '--encoding', - dest='serial_port_encoding', - metavar='CODEC', - help='set the encoding for the serial port (e.g. hexlify, Latin1, UTF-8), default: %(default)s', - default='UTF-8') - - group.add_argument( - '-f', '--filter', - action='append', - metavar='NAME', - help='add text transformation', - default=[]) - - group.add_argument( - '--eol', - choices=['CR', 'LF', 'CRLF'], - type=lambda c: c.upper(), - help='end of line mode', - default='CRLF') - - group.add_argument( - '--raw', - action='store_true', - help='Do no apply any encodings/transformations', - default=False) - - group = parser.add_argument_group('hotkeys') - - group.add_argument( - '--exit-char', - type=int, - metavar='NUM', - help='Unicode of special character that is used to exit the application, default: %(default)s', - default=0x1d) # GS/CTRL+] - - group.add_argument( - '--menu-char', - type=int, - metavar='NUM', - help='Unicode code of special character that is used to control miniterm (menu), default: %(default)s', - default=0x14) # Menu: CTRL+T - - group = parser.add_argument_group('diagnostics') - - group.add_argument( - '-q', '--quiet', - action='store_true', - help='suppress non-error messages', - default=False) - - group.add_argument( - '--develop', - action='store_true', - help='show Python traceback on error', - default=False) - - args = parser.parse_args() - - if args.menu_char == args.exit_char: - parser.error('--exit-char can not be the same as --menu-char') - - if args.filter: - if 'help' in args.filter: - sys.stderr.write('Available filters:\n') - sys.stderr.write('\n'.join( - '{:<10} = {.__doc__}'.format(k, v) - for k, v in sorted(TRANSFORMATIONS.items()))) - sys.stderr.write('\n') - sys.exit(1) - filters = args.filter - else: - filters = ['default'] - - while True: - # no port given on command line -> ask user now - if args.port is None or args.port == '-': - try: - args.port = ask_for_port() - except KeyboardInterrupt: - sys.stderr.write('\n') - parser.error('user aborted and port is not given') - else: - if not args.port: - parser.error('port is not given') - try: - serial_instance = serial.serial_for_url( - args.port, - args.baudrate, - parity=args.parity, - rtscts=args.rtscts, - xonxoff=args.xonxoff, - do_not_open=True) - - if not hasattr(serial_instance, 'cancel_read'): - # enable timeout for alive flag polling if cancel_read is not available - serial_instance.timeout = 1 - - if args.dtr is not None: - if not args.quiet: - sys.stderr.write('--- forcing DTR {}\n'.format('active' if args.dtr else 'inactive')) - serial_instance.dtr = args.dtr - if args.rts is not None: - if not args.quiet: - sys.stderr.write('--- forcing RTS {}\n'.format('active' if args.rts else 'inactive')) - serial_instance.rts = args.rts - - if isinstance(serial_instance, serial.Serial): - serial_instance.exclusive = args.exclusive - - serial_instance.open() - except serial.SerialException as e: - sys.stderr.write('could not open port {!r}: {}\n'.format(args.port, e)) - if args.develop: - raise - if not args.ask: - sys.exit(1) - else: - args.port = '-' - else: - break - - miniterm = Miniterm( - serial_instance, - echo=args.echo, - eol=args.eol.lower(), - filters=filters) - miniterm.exit_character = unichr(args.exit_char) - miniterm.menu_character = unichr(args.menu_char) - miniterm.raw = args.raw - miniterm.set_rx_encoding(args.serial_port_encoding) - miniterm.set_tx_encoding(args.serial_port_encoding) - - if not args.quiet: - sys.stderr.write('--- Miniterm on {p.name} {p.baudrate},{p.bytesize},{p.parity},{p.stopbits} ---\n'.format( - p=miniterm.serial)) - sys.stderr.write('--- Quit: {} | Menu: {} | Help: {} followed by {} ---\n'.format( - key_description(miniterm.exit_character), - key_description(miniterm.menu_character), - key_description(miniterm.menu_character), - key_description('\x08'))) - - miniterm.start() - try: - miniterm.join(True) - except KeyboardInterrupt: - pass - if not args.quiet: - sys.stderr.write('\n--- exit ---\n') - miniterm.join() - miniterm.close() - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -if __name__ == '__main__': - main() diff --git a/extensions/km-plot/deps/serial/urlhandler/__init__.py b/extensions/km-plot/deps/serial/urlhandler/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extensions/km-plot/deps/serial/urlhandler/protocol_alt.py b/extensions/km-plot/deps/serial/urlhandler/protocol_alt.py deleted file mode 100644 index 2e666ca..0000000 --- a/extensions/km-plot/deps/serial/urlhandler/protocol_alt.py +++ /dev/null @@ -1,57 +0,0 @@ -#! python -# -# This module implements a special URL handler that allows selecting an -# alternate implementation provided by some backends. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -# -# URL format: alt://port[?option[=value][&option[=value]]] -# options: -# - class=X used class named X instead of Serial -# -# example: -# use poll based implementation on Posix (Linux): -# python -m serial.tools.miniterm alt:///dev/ttyUSB0?class=PosixPollSerial - -from __future__ import absolute_import - -try: - import urlparse -except ImportError: - import urllib.parse as urlparse - -import serial - - -def serial_class_for_url(url): - """extract host and port from an URL string""" - parts = urlparse.urlsplit(url) - if parts.scheme != 'alt': - raise serial.SerialException( - 'expected a string in the form "alt://port[?option[=value][&option[=value]]]": ' - 'not starting with alt:// ({!r})'.format(parts.scheme)) - class_name = 'Serial' - try: - for option, values in urlparse.parse_qs(parts.query, True).items(): - if option == 'class': - class_name = values[0] - else: - raise ValueError('unknown option: {!r}'.format(option)) - except ValueError as e: - raise serial.SerialException( - 'expected a string in the form ' - '"alt://port[?option[=value][&option[=value]]]": {!r}'.format(e)) - if not hasattr(serial, class_name): - raise ValueError('unknown class: {!r}'.format(class_name)) - cls = getattr(serial, class_name) - if not issubclass(cls, serial.Serial): - raise ValueError('class {!r} is not an instance of Serial'.format(class_name)) - return (''.join([parts.netloc, parts.path]), cls) - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -if __name__ == '__main__': - s = serial.serial_for_url('alt:///dev/ttyS0?class=PosixPollSerial') - print(s) diff --git a/extensions/km-plot/deps/serial/urlhandler/protocol_cp2110.py b/extensions/km-plot/deps/serial/urlhandler/protocol_cp2110.py deleted file mode 100644 index 44ad4eb..0000000 --- a/extensions/km-plot/deps/serial/urlhandler/protocol_cp2110.py +++ /dev/null @@ -1,258 +0,0 @@ -#! python -# -# Backend for Silicon Labs CP2110/4 HID-to-UART devices. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2015 Chris Liechti -# (C) 2019 Google LLC -# -# SPDX-License-Identifier: BSD-3-Clause - -# This backend implements support for HID-to-UART devices manufactured -# by Silicon Labs and marketed as CP2110 and CP2114. The -# implementation is (mostly) OS-independent and in userland. It relies -# on cython-hidapi (https://github.com/trezor/cython-hidapi). - -# The HID-to-UART protocol implemented by CP2110/4 is described in the -# AN434 document from Silicon Labs: -# https://www.silabs.com/documents/public/application-notes/AN434-CP2110-4-Interface-Specification.pdf - -# TODO items: - -# - rtscts support is configured for hardware flow control, but the -# signaling is missing (AN434 suggests this is done through GPIO). -# - Cancelling reads and writes is not supported. -# - Baudrate validation is not implemented, as it depends on model and configuration. - -import struct -import threading - -try: - import urlparse -except ImportError: - import urllib.parse as urlparse - -try: - import Queue -except ImportError: - import queue as Queue - -import hid # hidapi - -import serial -from serial.serialutil import SerialBase, SerialException, PortNotOpenError, to_bytes, Timeout - - -# Report IDs and related constant -_REPORT_GETSET_UART_ENABLE = 0x41 -_DISABLE_UART = 0x00 -_ENABLE_UART = 0x01 - -_REPORT_SET_PURGE_FIFOS = 0x43 -_PURGE_TX_FIFO = 0x01 -_PURGE_RX_FIFO = 0x02 - -_REPORT_GETSET_UART_CONFIG = 0x50 - -_REPORT_SET_TRANSMIT_LINE_BREAK = 0x51 -_REPORT_SET_STOP_LINE_BREAK = 0x52 - - -class Serial(SerialBase): - # This is not quite correct. AN343 specifies that the minimum - # baudrate is different between CP2110 and CP2114, and it's halved - # when using non-8-bit symbols. - BAUDRATES = (300, 375, 600, 1200, 1800, 2400, 4800, 9600, 19200, - 38400, 57600, 115200, 230400, 460800, 500000, 576000, - 921600, 1000000) - - def __init__(self, *args, **kwargs): - self._hid_handle = None - self._read_buffer = None - self._thread = None - super(Serial, self).__init__(*args, **kwargs) - - def open(self): - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - - self._read_buffer = Queue.Queue() - - self._hid_handle = hid.device() - try: - portpath = self.from_url(self.portstr) - self._hid_handle.open_path(portpath) - except OSError as msg: - raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg)) - - try: - self._reconfigure_port() - except: - try: - self._hid_handle.close() - except: - pass - self._hid_handle = None - raise - else: - self.is_open = True - self._thread = threading.Thread(target=self._hid_read_loop) - self._thread.setDaemon(True) - self._thread.setName('pySerial CP2110 reader thread for {}'.format(self._port)) - self._thread.start() - - def from_url(self, url): - parts = urlparse.urlsplit(url) - if parts.scheme != "cp2110": - raise SerialException( - 'expected a string in the forms ' - '"cp2110:///dev/hidraw9" or "cp2110://0001:0023:00": ' - 'not starting with cp2110:// {{!r}}'.format(parts.scheme)) - if parts.netloc: # cp2100://BUS:DEVICE:ENDPOINT, for libusb - return parts.netloc.encode('utf-8') - return parts.path.encode('utf-8') - - def close(self): - self.is_open = False - if self._thread: - self._thread.join(1) # read timeout is 0.1 - self._thread = None - self._hid_handle.close() - self._hid_handle = None - - def _reconfigure_port(self): - parity_value = None - if self._parity == serial.PARITY_NONE: - parity_value = 0x00 - elif self._parity == serial.PARITY_ODD: - parity_value = 0x01 - elif self._parity == serial.PARITY_EVEN: - parity_value = 0x02 - elif self._parity == serial.PARITY_MARK: - parity_value = 0x03 - elif self._parity == serial.PARITY_SPACE: - parity_value = 0x04 - else: - raise ValueError('Invalid parity: {!r}'.format(self._parity)) - - if self.rtscts: - flow_control_value = 0x01 - else: - flow_control_value = 0x00 - - data_bits_value = None - if self._bytesize == 5: - data_bits_value = 0x00 - elif self._bytesize == 6: - data_bits_value = 0x01 - elif self._bytesize == 7: - data_bits_value = 0x02 - elif self._bytesize == 8: - data_bits_value = 0x03 - else: - raise ValueError('Invalid char len: {!r}'.format(self._bytesize)) - - stop_bits_value = None - if self._stopbits == serial.STOPBITS_ONE: - stop_bits_value = 0x00 - elif self._stopbits == serial.STOPBITS_ONE_POINT_FIVE: - stop_bits_value = 0x01 - elif self._stopbits == serial.STOPBITS_TWO: - stop_bits_value = 0x01 - else: - raise ValueError('Invalid stop bit specification: {!r}'.format(self._stopbits)) - - configuration_report = struct.pack( - '>BLBBBB', - _REPORT_GETSET_UART_CONFIG, - self._baudrate, - parity_value, - flow_control_value, - data_bits_value, - stop_bits_value) - - self._hid_handle.send_feature_report(configuration_report) - - self._hid_handle.send_feature_report( - bytes((_REPORT_GETSET_UART_ENABLE, _ENABLE_UART))) - self._update_break_state() - - @property - def in_waiting(self): - return self._read_buffer.qsize() - - def reset_input_buffer(self): - if not self.is_open: - raise PortNotOpenError() - self._hid_handle.send_feature_report( - bytes((_REPORT_SET_PURGE_FIFOS, _PURGE_RX_FIFO))) - # empty read buffer - while self._read_buffer.qsize(): - self._read_buffer.get(False) - - def reset_output_buffer(self): - if not self.is_open: - raise PortNotOpenError() - self._hid_handle.send_feature_report( - bytes((_REPORT_SET_PURGE_FIFOS, _PURGE_TX_FIFO))) - - def _update_break_state(self): - if not self._hid_handle: - raise PortNotOpenError() - - if self._break_state: - self._hid_handle.send_feature_report( - bytes((_REPORT_SET_TRANSMIT_LINE_BREAK, 0))) - else: - # Note that while AN434 states "There are no data bytes in - # the payload other than the Report ID", either hidapi or - # Linux does not seem to send the report otherwise. - self._hid_handle.send_feature_report( - bytes((_REPORT_SET_STOP_LINE_BREAK, 0))) - - def read(self, size=1): - if not self.is_open: - raise PortNotOpenError() - - data = bytearray() - try: - timeout = Timeout(self._timeout) - while len(data) < size: - if self._thread is None: - raise SerialException('connection failed (reader thread died)') - buf = self._read_buffer.get(True, timeout.time_left()) - if buf is None: - return bytes(data) - data += buf - if timeout.expired(): - break - except Queue.Empty: # -> timeout - pass - return bytes(data) - - def write(self, data): - if not self.is_open: - raise PortNotOpenError() - data = to_bytes(data) - tx_len = len(data) - while tx_len > 0: - to_be_sent = min(tx_len, 0x3F) - report = to_bytes([to_be_sent]) + data[:to_be_sent] - self._hid_handle.write(report) - - data = data[to_be_sent:] - tx_len = len(data) - - def _hid_read_loop(self): - try: - while self.is_open: - data = self._hid_handle.read(64, timeout_ms=100) - if not data: - continue - data_len = data.pop(0) - assert data_len == len(data) - self._read_buffer.put(bytearray(data)) - finally: - self._thread = None diff --git a/extensions/km-plot/deps/serial/urlhandler/protocol_hwgrep.py b/extensions/km-plot/deps/serial/urlhandler/protocol_hwgrep.py deleted file mode 100644 index 1a288c9..0000000 --- a/extensions/km-plot/deps/serial/urlhandler/protocol_hwgrep.py +++ /dev/null @@ -1,91 +0,0 @@ -#! python -# -# This module implements a special URL handler that uses the port listing to -# find ports by searching the string descriptions. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2011-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -# -# URL format: hwgrep://&