init. Not working due to the malunction of PySimpleGUI lib
This commit is contained in:
7
PySimpleGUI/CONTRIBUTING.md
Normal file
7
PySimpleGUI/CONTRIBUTING.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
## Contributing to PySimpleGUI
|
||||||
|
|
||||||
|
We are happy to receive issues describing bug reports and feature requests! If your bug report relates to a security vulnerability, please do not file a public issue, and please instead reach out to us at issues@PySimpleGUI.com.
|
||||||
|
|
||||||
|
We do not accept (and do not wish to receive) contributions of user-created or third-party code, including patches, pull requests, or code snippets incorporated into submitted issues. Please do not send us any such code! Bug reports and feature requests should not include any source code.
|
||||||
|
|
||||||
|
If you nonetheless submit any user-created or third-party code to us, (1) you assign to us all rights and title in or relating to the code; and (2) to the extent any such assignment is not fully effective, you hereby grant to us a royalty-free, perpetual, irrevocable, worldwide, unlimited, sublicensable, transferrable license under all intellectual property rights embodied therein or relating thereto, to exploit the code in any manner we choose, including to incorporate the code into PySimpleGUI and to redistribute it under any terms at our discretion.
|
||||||
591
PySimpleGUI/LICENSE.txt
Normal file
591
PySimpleGUI/LICENSE.txt
Normal file
@ -0,0 +1,591 @@
|
|||||||
|
PySimpleGUI License Agreement
|
||||||
|
|
||||||
|
Version 1.1, Last updated: March 26, 2024
|
||||||
|
|
||||||
|
This PySimpleGUI License Agreement (the "Agreement") governs the use,
|
||||||
|
reproduction, distribution, modification and all other exploitation of
|
||||||
|
PySimpleGUI. The Agreement is made by and between PySimpleSoft, Inc.
|
||||||
|
("Licensor") and the person or legal entity using PySimpleGUI hereunder
|
||||||
|
("Licensee" and, together with Licensor, the "Parties").
|
||||||
|
|
||||||
|
If you are using PySimpleGUI on behalf of a legal entity such as an employer,
|
||||||
|
then "Licensee" means that legal entity, and you represent and warrant that you
|
||||||
|
have the authority and capacity to enter into this Agreement on behalf of
|
||||||
|
Licensee.
|
||||||
|
|
||||||
|
"PySimpleGUI" consists of the following materials:
|
||||||
|
* the PySimpleGUI software library, version 5.0 or later (the "Library");
|
||||||
|
* the PySimpleGUI Library documentation (the "Documentation");
|
||||||
|
* sample programs demonstrating use of the Library (the "Demo Programs"); and
|
||||||
|
* utility programs relating to PySimpleGUI (the "Utilities").
|
||||||
|
|
||||||
|
PySimpleGUI may require you to obtain and use third-party software which is
|
||||||
|
distributed under separate license terms. Any such software is not considered
|
||||||
|
"PySimpleGUI" hereunder and is subject solely to such separate license terms.
|
||||||
|
|
||||||
|
PySimpleGUI is made available to Licensee pursuant to this Agreement for the
|
||||||
|
purpose of (1) pursuant to Section 1.2, enabling Authorized Developers to use
|
||||||
|
the Library in connection with developing Licensee Applications, and to use the
|
||||||
|
Documentation, the Demo Programs and the Utilities in connection therewith; and
|
||||||
|
(2) pursuant to Section 1.3, enabling End Users of the Licensee Applications to
|
||||||
|
execute the Library as a dependency of the Licensee Applications; each as
|
||||||
|
defined and more fully set forth herein and subject to the limitations set
|
||||||
|
forth herein.
|
||||||
|
|
||||||
|
Licensor agrees to license PySimpleGUI to Licensee only in accordance with the
|
||||||
|
terms of this Agreement. By using PySimpleGUI, Licensee agrees to be bound by
|
||||||
|
the terms of this Agreement. If you do not agree to the terms of this
|
||||||
|
Agreement, you may not copy, use, distribute, modify or otherwise attempt to
|
||||||
|
exploit PySimpleGUI.
|
||||||
|
|
||||||
|
Licensee acknowledges that Licensor may from time to time update or modify this
|
||||||
|
Agreement, by publishing a new version of this Agreement on Licensor's website.
|
||||||
|
Licensee may continue to use the version of PySimpleGUI that it previously
|
||||||
|
obtained under the prior version of this Agreement, but any version of
|
||||||
|
PySimpleGUI received or used thereafter shall be subject to the updated version
|
||||||
|
of this Agreement.
|
||||||
|
|
||||||
|
Accordingly, in consideration of the mutual covenants set forth herein, the
|
||||||
|
receipt and sufficiency of which is hereby acknowledged, the Parties agree as
|
||||||
|
follows.
|
||||||
|
|
||||||
|
1. Authorized Developers; License Grants; Limitations.
|
||||||
|
|
||||||
|
1.1. Definitions. As used herein:
|
||||||
|
|
||||||
|
* "Authorized Developer" means any individual person who has registered on
|
||||||
|
Licensor's site at https://PySimpleGUI.com (the "Site") to develop one or
|
||||||
|
more of Licensee's own applications which make use of the Library as a
|
||||||
|
dependency in accordance with Section 1.5 (collectively, "Licensee
|
||||||
|
Applications") and is either (1) a Hobbyist Developer; or (2) a Commercial
|
||||||
|
Developer who has purchased an active PySimpleGUI paid license hereunder
|
||||||
|
which is fully paid up pursuant to Section 3.
|
||||||
|
|
||||||
|
* "Hobbyist Developer" means any individual who uses PySimpleGUI for
|
||||||
|
development purposes solely for either or both of the following: (1) personal
|
||||||
|
(e.g., not on behalf of an employer or other third party), Non-Commercial
|
||||||
|
purposes; or (2) Non-Commercial educational or learning purposes (1 and 2
|
||||||
|
together, the "Permitted No-cost Purposes").
|
||||||
|
|
||||||
|
* "Commercial Developer" means any individual who uses PySimpleGUI for
|
||||||
|
development purposes who is not a Hobbyist Developer.
|
||||||
|
|
||||||
|
As used in this Section 1, "Non-Commercial" means use which is both (1) not on
|
||||||
|
behalf or for the benefit of any company or other organization; and (2) not
|
||||||
|
involving the receipt of any commercial advantage or monetary compensation. If
|
||||||
|
you have questions about whether your contemplated use is "Non-Commercial,"
|
||||||
|
please contact us at license@pysimplegui.com.
|
||||||
|
|
||||||
|
For the avoidance of doubt:
|
||||||
|
|
||||||
|
* Only Authorized Developers (e.g., Hobbyist Developers and Commercial
|
||||||
|
Developers who satisfy the requirements for Authorized Developers) may use
|
||||||
|
PySimpleGUI for development purposes.
|
||||||
|
|
||||||
|
* A Hobbyist Developer may not use PySimpleGUI for any development purpose
|
||||||
|
other than the Permitted No-cost Purposes.
|
||||||
|
|
||||||
|
* Only Commercial Developers may use PySimpleGUI to develop Licensee
|
||||||
|
Applications for any commercial purpose; for the benefit of, on behalf of or
|
||||||
|
on computer hardware belonging to an employing company or other organization;
|
||||||
|
or for commercial educational purposes, such as the development of a paid
|
||||||
|
training course.
|
||||||
|
|
||||||
|
If you have questions about whether your contemplated Licensee Application
|
||||||
|
would be a Permitted No-cost Purpose subject to a Hobbyist Developer license,
|
||||||
|
please contact us at license@pysimplegui.com.
|
||||||
|
|
||||||
|
1.2. Development License Grants. Subject to the terms and conditions of this
|
||||||
|
Agreement:
|
||||||
|
|
||||||
|
1.2.1. Library. Licensor grants Licensee a limited, personal, revocable,
|
||||||
|
non-exclusive, non-sublicensable, non-transferable license during the Term (1)
|
||||||
|
for its Authorized Developers to internally install, use, reproduce and modify
|
||||||
|
the Library to develop Licensee Applications; and (2) to redistribute the
|
||||||
|
Library to recipients of its Licensee Applications ("End Users"); provided,
|
||||||
|
that such redistribution may not include publishing the source code of the
|
||||||
|
Library (in modified or unmodified form) in a publicly accessible website or
|
||||||
|
repository or in other publicly accessible form.
|
||||||
|
|
||||||
|
1.2.2. Documentation. Licensor grants Licensee a limited, personal, revocable,
|
||||||
|
non-exclusive, non-sublicensable, non-transferable license during the Term for
|
||||||
|
its Authorized Developers to internally access, use, and reproduce a reasonable
|
||||||
|
number of copies of the Documentation for the sole purpose of facilitating the
|
||||||
|
use of the Library by Licensee Applications in accordance with this Agreement.
|
||||||
|
For the avoidance of doubt, Licensee may not modify or redistribute the
|
||||||
|
Documentation.
|
||||||
|
|
||||||
|
1.2.3. Demo Programs. Licensor grants Licensee a limited, personal, revocable,
|
||||||
|
non-exclusive, non-sublicensable, non-transferable license during the Term to
|
||||||
|
install, use, execute, reproduce and modify the Demo Programs, and to
|
||||||
|
incorporate modified portions of the Demo Programs into the Licensee
|
||||||
|
Applications; provided, that (1) the Demo Programs may not be used for any
|
||||||
|
purposes other than in connection with the use of the Library; and (2) the Demo
|
||||||
|
Programs may not be (individually or as a whole) redistributed in unmodified
|
||||||
|
form or as a program with substantially similar functionality to the Demo
|
||||||
|
Programs.
|
||||||
|
|
||||||
|
1.2.4. Utilities. Licensor grants Licensee a limited, personal, revocable,
|
||||||
|
non-exclusive, non-sublicensable, non-transferable license during the Term to
|
||||||
|
install, use, execute, reproduce and modify the Utilities, but not to
|
||||||
|
distribute or publish the Utilities or any modified version.
|
||||||
|
|
||||||
|
1.2.5. Developer Key Required. The licenses granted in this Section 1.2 may
|
||||||
|
only be exercised by Authorized Developers. For Hobbyist Developers, these
|
||||||
|
licenses may only be exercised within the period of time during which each such
|
||||||
|
Hobbyist Developer has a then-active Developer Key pursuant to Section 3.
|
||||||
|
Licensor may in its discretion permit recipients of PySimpleGUI to make limited
|
||||||
|
use of it for a limited trial period without a Developer Key.
|
||||||
|
|
||||||
|
1.2.6. Limitations for Hobbyist Developers. For Hobbyist Developers, the
|
||||||
|
licenses granted in this Section 1.2 may only be exercised for the Permitted
|
||||||
|
No-cost Purposes.
|
||||||
|
|
||||||
|
1.2.7. Limitations on Modification of the Library. Licensee's right to modify
|
||||||
|
the Library pursuant to this Section 1.2 is further limited as follows: (a)
|
||||||
|
Licensee may not modify or extend the Library or take any other action which
|
||||||
|
has the effect of enabling bypass of the Library's protection mechanisms
|
||||||
|
requiring the use of valid Developer Keys or Distribution Keys. (b) Licensee
|
||||||
|
explicitly acknowledges and agrees that Licensor's digital signature of the
|
||||||
|
Library is only applicable to the unmodified Library as made available by
|
||||||
|
Licensor, and that any modifications to the Library will result in Licensor's
|
||||||
|
digital signature no longer applying to the modified version.
|
||||||
|
|
||||||
|
1.2.8. Limitations on Distribution of the Library. Licensee's right to
|
||||||
|
distribute the Library (in modified or unmodified form) pursuant to this
|
||||||
|
Section 1.2 is subject to Licensee (a) including the applicable proprietary
|
||||||
|
notices set forth in Section 2.2; and (b) including the PySimpleGUI Flow-Down
|
||||||
|
License Terms set forth in Exhibit A in the license terms that Licensee uses to
|
||||||
|
distribute the Licensee Application.
|
||||||
|
|
||||||
|
1.2.9. Distribution Keys. Commercial Developers may obtain from Licensor a
|
||||||
|
PySimpleGUI distribution key ("Distribution Key") through the Authorized
|
||||||
|
Developer's Site account and utilizing the Distribution Key through the
|
||||||
|
protection mechanism made available in the Library to permit distribution to
|
||||||
|
End Users. The Commercial Developer may use its Distribution Key to enable End
|
||||||
|
Users to install and execute the Licensee Applications, including the Library
|
||||||
|
incorporated therein, without requiring each recipient to obtain a Developer
|
||||||
|
Key or be limited to a trial period as described in Section 1.2.5. Licensee
|
||||||
|
shall be responsible for all activities occurring under Distribution Keys
|
||||||
|
obtained by its Authorized Developers and for the compliance with this
|
||||||
|
Agreement of all Licensee Applications using such Distribution Keys.
|
||||||
|
|
||||||
|
1.3. Run-time End User License Grant. Subject to the terms and conditions of
|
||||||
|
this Agreement, Licensor grants Licensee a limited, personal, revocable,
|
||||||
|
non-exclusive, non-sublicensable, non-transferable license during the Term to
|
||||||
|
install and execute the Library solely for it and its employee End Users to
|
||||||
|
internally use the corresponding Licensee Applications with which the Library
|
||||||
|
is distributed. For the avoidance of doubt, the license set forth in this
|
||||||
|
Section 1.3 does not permit modification, external redistribution, integration
|
||||||
|
of the Library with other software, or any other use of the Library (for
|
||||||
|
development purposes or otherwise) except solely as distributed with the
|
||||||
|
unmodified Licensee Applications; any such activities are permitted only by
|
||||||
|
Authorized Developers and only to the extent permitted by Section 1.2. If the
|
||||||
|
Licensee Application does not include a valid Distribution Key from a
|
||||||
|
Commercial Developer, then the period of use of the Library within the Licensee
|
||||||
|
Application will be limited to a trial period for any End User who does not
|
||||||
|
register as an Authorized Developer hereunder.
|
||||||
|
|
||||||
|
1.4. License Restrictions. The licenses granted to Licensee hereunder are
|
||||||
|
expressly made subject to the following limitations: except as expressly
|
||||||
|
permitted herein, Licensee may not (and shall not permit any third party to):
|
||||||
|
(a) copy all or any portion of PySimpleGUI; (b) modify or translate
|
||||||
|
PySimpleGUI; (c) reverse engineer, decompile or disassemble the Software, in
|
||||||
|
whole or in part, except solely to the extent permitted under applicable law;
|
||||||
|
(d) create derivative works based on PySimpleGUI; (e) publicly display or
|
||||||
|
publish PySimpleGUI; (f) rent, lease, sublicense, sell, distribute, assign,
|
||||||
|
transfer, or otherwise permit access to PySimpleGUI to any third party; (g)
|
||||||
|
bypass or work around any requirements for license keys, limitations on access,
|
||||||
|
or obfuscation or security mechanisms incorporated into PySimpleGUI; (h) use
|
||||||
|
PySimpleGUI for illegal or otherwise harmful purposes, including without
|
||||||
|
limitation harassment, defamation, creation or delivery of unsolicited emails
|
||||||
|
or spam, infringement of third party intellectual property rights or other
|
||||||
|
third party rights, or distribution of viruses, worms, malware or other harmful
|
||||||
|
or destructive software; (i) incorporate PySimpleGUI or any portion thereof
|
||||||
|
into any software that purports to subject it to open source software or
|
||||||
|
similar license terms, including any prior version of PySimpleGUI (modified or
|
||||||
|
unmodified) which was previously distributed under such licenses; or (j)
|
||||||
|
exercise any other right to PySimpleGUI not expressly granted in this
|
||||||
|
Agreement.
|
||||||
|
|
||||||
|
1.5. Licensee Application Prohibitions. Notwithstanding anything else in
|
||||||
|
this Agreement, Licensee shall ensure that Licensee Applications (a) do not
|
||||||
|
have the purpose, intent or functionality of enabling End Users to make further
|
||||||
|
use of PySimpleGUI for their own development purposes or to carry out any
|
||||||
|
activities otherwise restricted or prohibited hereunder; (b) do not have a
|
||||||
|
substantially similar purpose to PySimpleGUI; (c) do not enable End Users to
|
||||||
|
interact, integrate or otherwise develop user interfaces via direct or indirect
|
||||||
|
access to PySimpleGUI's functionality; and (d) are not intended or designed for
|
||||||
|
use in high-risk use cases that could reasonably result in death, severe bodily
|
||||||
|
injury, or other physical property or environmental damage.
|
||||||
|
|
||||||
|
1.6. No Use with Earlier Versions of PySimpleGUI. For the avoidance of
|
||||||
|
doubt, no portions of PySimpleGUI distributed under this Agreement may be used
|
||||||
|
in connection with, or in any way incorporated with or into, any versions of
|
||||||
|
the PySimpleGUI library prior to version 5.0 that have been distributed under
|
||||||
|
the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
1.7. Additional Grant to Python Software Foundation. With regards to
|
||||||
|
portions of PySimpleGUI that Licensor uploads to PyPI, Python Software
|
||||||
|
Foundation ("PSF") may copy and redistribute such portions unmodified on PyPI
|
||||||
|
in the form provided by Licensor, with no further action required by PSF.
|
||||||
|
|
||||||
|
1.8. Prohibition on Training Artificial Intelligence. As used herein,
|
||||||
|
"Artificial Intelligence" means a system or model that is intended to generate
|
||||||
|
or identify patterns in code or data, produce insights or correlations, or make
|
||||||
|
predictions, recommendations, or decisions; in each case, where the system or
|
||||||
|
model operates using machine learning, neural networks, large language models,
|
||||||
|
or other approaches designed to approximate cognitive abilities. Licensee shall
|
||||||
|
not (and shall not directly or indirectly permit or assist anyone else to) use
|
||||||
|
PySimpleGUI, or any part thereof, to train an Artificial Intelligence that is
|
||||||
|
offered to third parties on a commercial basis or as part of a larger
|
||||||
|
commercial offering. The preceding sentence does not prohibit use of
|
||||||
|
PySimpleGUI in conjunction with an Artificial Intelligence in other ways, such
|
||||||
|
as developing a front-end user interface.
|
||||||
|
|
||||||
|
2. Intellectual Property Ownership; Notices.
|
||||||
|
|
||||||
|
2.1. Licensor Ownership. PySimpleGUI is not sold to Licensee, and all rights
|
||||||
|
not expressly granted herein are reserved to Licensor. As between the parties,
|
||||||
|
Licensor and its licensors own all right, title and interest in and to
|
||||||
|
PySimpleGUI and any part thereof, including, without limitation, all
|
||||||
|
copyrights, patents, trademarks, trade secrets or other intellectual property
|
||||||
|
or proprietary rights.
|
||||||
|
|
||||||
|
2.2. Proprietary Notices. Licensee shall not modify or remove any copyright
|
||||||
|
or patent notices or other proprietary notices or markings from any portion of
|
||||||
|
PySimpleGUI (whether modified or unmodified) without Licensor's explicit
|
||||||
|
written permission. Licensor shall ensure that any Licensee Applications that
|
||||||
|
use the Library include a notice in the following form within the Licensee
|
||||||
|
Application as well as any corresponding Licensee documentation or materials:
|
||||||
|
|
||||||
|
For unmodified versions of PySimpleGUI:
|
||||||
|
|
||||||
|
This product includes PySimpleGUI (https://PySimpleGUI.com). PySimpleGUI
|
||||||
|
is Copyright (c) PySimpleSoft, Inc. and/or its licensors. Use of
|
||||||
|
PySimpleGUI is subject to the license terms available at
|
||||||
|
https://PySimpleGUI.com/eula
|
||||||
|
|
||||||
|
PYSIMPLEGUI IS PROVIDED "AS IS," WITHOUT ANY WARRANTIES, WHETHER EXPRESS OR
|
||||||
|
IMPLIED. PYSIMPLESOFT DISCLAIMS ALL IMPLIED WARRANTIES, INCLUDING WITHOUT
|
||||||
|
LIMITATION THE IMPLIED WARRANTIES OF NONINFRINGEMENT, TITLE,
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
For modified versions of PySimpleGUI:
|
||||||
|
|
||||||
|
This product includes a modified version of PySimpleGUI
|
||||||
|
(https://PySimpleGUI.com). PySimpleGUI is Copyright (c) PySimpleSoft, Inc.
|
||||||
|
and/or its licensors. Use of PySimpleGUI is subject to the license terms
|
||||||
|
available at https://PySimpleGUI.com/eula
|
||||||
|
|
||||||
|
PYSIMPLEGUI IS PROVIDED "AS IS," WITHOUT ANY WARRANTIES, WHETHER EXPRESS OR
|
||||||
|
IMPLIED. PYSIMPLESOFT DISCLAIMS ALL IMPLIED WARRANTIES, INCLUDING WITHOUT
|
||||||
|
LIMITATION THE IMPLIED WARRANTIES OF NONINFRINGEMENT, TITLE,
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
If the Licensee Application or the corresponding Licensee documentation or
|
||||||
|
materials include Licensee's copyright notices or other third parties' notices,
|
||||||
|
then Licensee shall include the above notice together with such notices.
|
||||||
|
|
||||||
|
2.3. Licensor Marks. As between the parties hereto, all of Licensor's
|
||||||
|
trademarks and service marks applicable to Licensor or PySimpleGUI
|
||||||
|
(collectively, the "Licensor Marks") are the sole property of Licensor and/or
|
||||||
|
its licensors. Subject to the terms and conditions of this Agreement, Licensor
|
||||||
|
grants Licensee a limited, personal, revocable, non-exclusive,
|
||||||
|
non-sublicensable, non-transferable license to use the Licensor Mark
|
||||||
|
"PySimpleGUI" in connection with Licensee's permitted distribution of the
|
||||||
|
Library hereunder. The license set forth in this Section 2.3 is explicitly
|
||||||
|
conditioned on (a) Licensee's agreement not to challenge Licensor's ownership
|
||||||
|
of the Licensor Marks at any time during the Term or thereafter; (b) Licensee
|
||||||
|
ensuring that any modified version of the Library is clearly and prominently
|
||||||
|
noted as such; (c) Licensee complying with all trademark usage guidelines and
|
||||||
|
requirements that Licensor may publish from time to time; and (d) Licensee
|
||||||
|
immediately correcting incorrect usage of the Licensor Marks upon request from
|
||||||
|
Licensor. Licensee shall immediately cease usage of the Licensor Marks upon
|
||||||
|
written notice thereof from Licensor. All goodwill arising from use of the
|
||||||
|
Licensor Marks shall inure to the benefit of Licensor.
|
||||||
|
|
||||||
|
3. Developer Keys; Fees and Payments.
|
||||||
|
|
||||||
|
3.1. Developer Keys. In order to develop Licensee Applications pursuant to
|
||||||
|
Section 1.2 (and subject to any limited trial period usage as may be permitted
|
||||||
|
by Licensor from time to time), each Authorized Developer shall obtain a
|
||||||
|
PySimpleGUI developer license key ("Developer Key") by registering on the
|
||||||
|
Site as set forth therein. Each Developer Key is personal to the specific
|
||||||
|
Authorized Developer, and Licensee shall not permit Authorized Developers to
|
||||||
|
disclose, share or reuse Developer Keys. For the avoidance of doubt, any
|
||||||
|
disclosure, sharing or reuse of a Developer Key by Licensee's Authorized
|
||||||
|
Developers, whether or not authorized by Licensee, shall be a material breach
|
||||||
|
permitting termination of this Agreement pursuant to Section 8.3. Developer
|
||||||
|
Keys are Licensor's Confidential Information pursuant to Section 5. Developer
|
||||||
|
Keys are limited to a specified time period (which shall be annual from the
|
||||||
|
start date of the Developer Key, unless otherwise explicitly stated by
|
||||||
|
Licensor). Upon the expiration of a Developer Key for a Hobbyist Developer,
|
||||||
|
they may no longer use the Developer Key and must obtain a new Developer Key
|
||||||
|
from the Site in order to continue using PySimpleGUI for development purposes
|
||||||
|
pursuant to Section 1.2. Upon the expiration of a Developer Key for a
|
||||||
|
Commercial Developer, they may continue to use their Developer Key for versions
|
||||||
|
of PySimpleGUI released during that period, but may not obtain subsequent
|
||||||
|
updated versions under Section 4.2 unless they purchase a new Developer Key.
|
||||||
|
|
||||||
|
3.2. Fees for Commercial Developer Keys; Taxes. Before obtaining each
|
||||||
|
Developer Key for a Commercial Developer, Licensee shall pay to Licensor the
|
||||||
|
corresponding fees as stated on the Site and using the payment mechanism made
|
||||||
|
available on the Site. All payments shall be made in United States dollars. All
|
||||||
|
amounts payable by Licensee hereunder are exclusive of taxes and similar
|
||||||
|
assessments, and Licensee is responsible for all sales, use, and excise taxes,
|
||||||
|
and any other similar taxes of any kind imposed by any federal, state, or local
|
||||||
|
governmental or regulatory authority on any amounts payable by Licensee
|
||||||
|
hereunder, excluding any taxes imposed on Licensor's income.
|
||||||
|
|
||||||
|
3.3. Accuracy of Registration Details. Licensee represents and warrants that
|
||||||
|
(a) all information provided by it and its Authorized Developers when
|
||||||
|
registering for Developer Keys shall be truthful, accurate, complete and not
|
||||||
|
misleading, and (b) it and its Authorized Developers shall not misrepresent
|
||||||
|
their use of PySimpleGUI as qualifying for a Hobbyist Developer Key if their
|
||||||
|
use does not satisfy the Permitted No-cost Purposes.
|
||||||
|
|
||||||
|
4. Support and Updates.
|
||||||
|
|
||||||
|
4.1. Support. Licensor has no obligation hereunder to provide support to
|
||||||
|
Licensee or its Authorized Developers. Authorized Developers may submit
|
||||||
|
Feedback (as defined in Section 5.4) consisting of issues and bug reports to
|
||||||
|
the PySimpleGUI software repository as described on the Site or in the
|
||||||
|
Documentation. Licensor may in its sole discretion address such issues or bug
|
||||||
|
reports in current or future versions of PySimpleGUI, but has no obligation to
|
||||||
|
do so.
|
||||||
|
|
||||||
|
4.2. Updates. Licensor has no obligation hereunder to make available updated
|
||||||
|
versions of PySimpleGUI. In the event that Licensor elects to make available an
|
||||||
|
updated version of PySimpleGUI, then Authorized Developers with a then-active
|
||||||
|
Developer Key may download and use the updated version, and the updated version
|
||||||
|
shall be included in the definition of "PySimpleGUI" thereafter for purposes of
|
||||||
|
this Agreement.
|
||||||
|
|
||||||
|
5. Confidentiality; Feedback.
|
||||||
|
|
||||||
|
5.1. Confidential Information. Licensee acknowledges that portions of
|
||||||
|
PySimpleGUI and certain other materials are confidential as provided herein.
|
||||||
|
"Confidential Information" means any and all information, whether provided in
|
||||||
|
writing, orally, visually, electronically or by other means, related to
|
||||||
|
Licensor's or its licensors' services and/or business that, whether it
|
||||||
|
constitutes a Trade Secret or not, is treated as confidential or secret by
|
||||||
|
Licensor (that is, it is the subject of efforts by Licensor that are reasonable
|
||||||
|
under the circumstances to maintain its secrecy), including, but not limited
|
||||||
|
to, (i) Trade Secrets as defined below; (ii) any and all other information
|
||||||
|
which is disclosed by Licensor to Licensee orally, electronically, visually, or
|
||||||
|
in a document or other tangible form which is either identified as or should be
|
||||||
|
reasonably understood to be confidential and/or proprietary; and, (iii) any
|
||||||
|
notes, extracts, analysis, or materials prepared by Licensee which are copies
|
||||||
|
of or derivative works of Licensor's or its licensors' proprietary or
|
||||||
|
confidential information from which the substance of Confidential Information
|
||||||
|
can be inferred or otherwise understood. Confidential Information shall not
|
||||||
|
include information which Licensee can clearly establish by written evidence:
|
||||||
|
(a) already is lawfully known to or independently developed by Licensee without
|
||||||
|
access to the Confidential Information or Trade Secrets, (b) is disclosed by
|
||||||
|
Licensor in non-confidential published materials, (c) is generally known to the
|
||||||
|
public, or (d) is rightfully obtained from any third party without any
|
||||||
|
obligation of confidentiality.
|
||||||
|
|
||||||
|
5.2. Trade Secrets. As used herein, "Trade Secrets" means all non-public
|
||||||
|
information whether tangible or intangible related to Licensor's and its
|
||||||
|
licensors' services or business that (i) derives economic value, actual or
|
||||||
|
potential, from not being generally known to or readily ascertainable by other
|
||||||
|
persons who can obtain economic value from its disclosure or use; and (ii) is
|
||||||
|
the subject of efforts that are reasonable under the circumstances to maintain
|
||||||
|
its secrecy, which may include, without limitation, (a) marking any information
|
||||||
|
reduced to tangible form clearly and conspicuously with a legend identifying
|
||||||
|
its confidential or trade secret nature; (b) identifying any oral communication
|
||||||
|
as confidential or secret immediately before, during, or after such oral
|
||||||
|
communication; or (c) otherwise treating such information as confidential.
|
||||||
|
|
||||||
|
5.3. Licensee Obligations. Licensee agrees not to disclose Confidential
|
||||||
|
Information or Trade Secrets to any third party and will protect and treat all
|
||||||
|
Confidential Information and Trade Secrets with the highest degree of care.
|
||||||
|
Except as otherwise expressly provided in this Agreement, Licensee will not use
|
||||||
|
or make any copies of Confidential Information or Trade Secrets, in whole or in
|
||||||
|
part, without the prior written authorization of Licensor. Licensee may
|
||||||
|
disclose Confidential Information or Trade Secrets if required by statute,
|
||||||
|
regulation, or order of a court of competent jurisdiction, provided that
|
||||||
|
Licensee provides Licensor with prior notice, discloses only the minimum
|
||||||
|
Confidential Information or Trade Secrets required to be disclosed, and
|
||||||
|
cooperates with Licensor in taking appropriate protective measures. These
|
||||||
|
obligations shall continue for three (3) years following termination or
|
||||||
|
expiration of this Agreement with respect to Confidential Information that does
|
||||||
|
not rise to the level of a Trade Secret and shall continue for Trade Secrets so
|
||||||
|
long as they remain Trade Secrets.
|
||||||
|
|
||||||
|
5.4. Feedback. As used herein, "Feedback" means any comments, questions,
|
||||||
|
suggestions, issues, bug reports, or related feedback provided by Licensee to
|
||||||
|
Licensor relating to PySimpleGUI, including, without limitation, suggesting or
|
||||||
|
recommending changes to any part of PySimpleGUI, or new features or
|
||||||
|
functionality relating thereto. All Feedback is, and will be treated as,
|
||||||
|
non-confidential and non-proprietary, regardless of any markings Licensee may
|
||||||
|
apply to it. Licensee hereby assigns to Licensor all right, title, and interest
|
||||||
|
in, and Licensor is free to use without any attribution or compensation to
|
||||||
|
Licensee, any ideas, know-how, concepts, techniques, or other intellectual
|
||||||
|
property and proprietary rights contained in the Feedback, whether or not
|
||||||
|
patentable, for any purpose whatsoever, including but not limited to,
|
||||||
|
developing, manufacturing, having manufactured, licensing, marketing, and
|
||||||
|
selling, directly or indirectly, products and services using such Feedback. To
|
||||||
|
the extent the foregoing assignment of rights, title and interest in and to
|
||||||
|
Feedback is prohibited by applicable law, Licensee hereby grants Licensor a
|
||||||
|
non-exclusive, perpetual, irrevocable, royalty-free, fully paid-up, worldwide
|
||||||
|
license (including the right to sublicense through multiple tiers) to (a) fully
|
||||||
|
use, practice and exploit those non-assignable rights, title and interest,
|
||||||
|
including, but not limited to, the right to use, reproduce, adapt, publicly
|
||||||
|
perform, publicly display, modify, prepare derivative works, publish, transmit
|
||||||
|
and distribute Feedback, or any portion thereof, in any form, medium or
|
||||||
|
distribution method now known or hereafter existing, known or developed, for
|
||||||
|
any purpose, and to develop, manufacture, have manufactured, license, market,
|
||||||
|
and sell, directly or indirectly, products and services using Feedback; and (b)
|
||||||
|
authorize any such use by others of Feedback, or any portion thereof, in the
|
||||||
|
same manner.
|
||||||
|
|
||||||
|
6. NO LICENSOR WARRANTIES; LIABILITY.
|
||||||
|
|
||||||
|
6.1. DISCLAIMER OF WARRANTIES. PYSIMPLEGUI IS PROVIDED TO LICENSEE "AS IS".
|
||||||
|
LICENSOR DOES NOT MAKE ANY, AND HEREBY SPECIFICALLY DISCLAIMS ANY,
|
||||||
|
REPRESENTATIONS, ENDORSEMENTS, GUARANTEES, OR WARRANTIES, EXPRESS OR IMPLIED,
|
||||||
|
RELATED TO PYSIMPLEGUI INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTY OF
|
||||||
|
MERCHANTABILITY, TITLE, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT OF
|
||||||
|
INTELLECTUAL PROPERTY RIGHTS. Licensee acknowledges that Licensor does not
|
||||||
|
guarantee compatibility between PySimpleGUI and any future versions thereof,
|
||||||
|
and that Licensor makes no commitments as to future development, availability,
|
||||||
|
release or licensing of any current or future versions of PySimpleGUI. Licensee
|
||||||
|
will have sole responsibility for the adequate protection and backup of
|
||||||
|
Licensee's software, data and equipment used with PySimpleGUI. The entire risk
|
||||||
|
as to the quality and performance of PySimpleGUI and any obligation with
|
||||||
|
respect to service and support is borne by Licensee. Licensee understands that
|
||||||
|
Software hosted by Licensor for evaluation purposes may not be secure or
|
||||||
|
stable. Licensee waives any claim against Licensor which may arise as a result
|
||||||
|
of Licensee's breach of the foregoing. This Agreement does not grant Licensee
|
||||||
|
any right to any maintenance, services, including without limitation, any
|
||||||
|
support, enhancement, modification, bug fix or update to the Software, and
|
||||||
|
Licensor is under no obligation to provide or inform Licensee of any such
|
||||||
|
maintenance or services.
|
||||||
|
|
||||||
|
6.2. DISCLAIMER OF LIABILITY. LICENSEE EXPLICITLY AGREES THAT, TO THE
|
||||||
|
MAXIMUM EXTENT PERMITTED BY LAW, LICENSOR SHALL NOT BE LIABLE UNDER ANY LEGAL
|
||||||
|
THEORY FOR ANY DAMAGES SUFFERED IN CONNECTION WITH THE USE OF THE SOFTWARE,
|
||||||
|
INCLUDING BUT NOT LIMITED TO ANY LOST PROFITS, LOST SAVINGS OR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES,
|
||||||
|
WHETHER RESULTING FROM IMPAIRED OR LOST DATA, SOFTWARE OR COMPUTER FAILURE, THE
|
||||||
|
LICENSEE APPLICATIONS, OR ANY OTHER CAUSE, BY LICENSEE OR ANY OTHER THIRD
|
||||||
|
PARTY, EVEN IF IT HAS BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
LICENSEE HEREBY EXPRESSLY RELEASES LICENSOR FROM ANY AND ALL LIABILITY OR
|
||||||
|
RESPONSIBILITY TO ANY DAMAGE CAUSED, DIRECTLY OR INDIRECTLY, TO LICENSEE OR ANY
|
||||||
|
THIRD PARTY AS A RESULT OF THE USE OF THE SOFTWARE OR THE INSTALLATION THEREOF
|
||||||
|
INTO LICENSEE'S COMPUTER ENVIRONMENT. IN THE EVENT THAT THE DISCLAIMERS OF
|
||||||
|
LIABILITY SET FORTH HEREIN ARE HELD TO BE UNENFORCEABLE, THE PARTIES AGREE THAT
|
||||||
|
UNDER NO CIRCUMSTANCES SHALL LICENSOR'S AGGREGATE LIABILITY HEREUNDER OR IN
|
||||||
|
CONNECTION WITH THIS AGREEMENT EXCEED THE AMOUNTS PAID BY LICENSEE TO LICENSOR
|
||||||
|
IN THE 12 MONTHS PRECEDING THE DATE THAT A CLAIM FIRST ACCRUES. LICENSEE SHALL
|
||||||
|
BRING ANY CLAIM AGAINST LICENSOR WITHIN 12 MONTHS OF THE DATE THAT THE CLAIM
|
||||||
|
FIRST ACCRUES, AND HEREBY WAIVES ANY CLAIMS THAT IT DOES NOT BRING WITHIN SUCH
|
||||||
|
TIME PERIOD.
|
||||||
|
|
||||||
|
6.3. Essential Terms. THIS SECTION 6 IS AN ESSENTIAL BASIS OF LICENSOR'S
|
||||||
|
DECISION TO OFFER PYSIMPLEGUI, AND SHALL APPLY REGARDLESS OF THE LEGAL THEORY
|
||||||
|
UPON WHICH DAMAGES MAY BE CLAIMED; REGARDLESS OF WHETHER A PARTY KNEW OR SHOULD
|
||||||
|
HAVE KNOWN OF THE POSSIBILITY OF SUCH DAMAGES; AND REGARDLESS OF WHETHER THE
|
||||||
|
FOREGOING LIMITATIONS OF LIABILITY CAUSE ANY REMEDY TO FAIL IN ITS ESSENTIAL
|
||||||
|
PURPOSE.
|
||||||
|
|
||||||
|
7. Indemnification. Licensee agrees to defend, indemnify and hold Licensor
|
||||||
|
and its directors, officers, employees and representatives harmless for any
|
||||||
|
claims, expenses, losses, costs, fees (including attorneys' fees) or damages of
|
||||||
|
any sort resulting from (a) Licensee's breach of this Agreement; (b) Licensee's
|
||||||
|
use of PySimpleGUI or exercise of the license rights granted hereunder; or (c)
|
||||||
|
the Licensee Applications, or Licensee's or any third party's use thereof.
|
||||||
|
|
||||||
|
8. Term and Termination.
|
||||||
|
|
||||||
|
8.1. Term. This Agreement shall commence on the date on which Licensee
|
||||||
|
downloads PySimpleGUI or otherwise obtains a copy of PySimpleGUI, and shall
|
||||||
|
continue thereafter until terminated as set forth herein.
|
||||||
|
|
||||||
|
8.2. Termination by Licensee. Licensee may terminate this Agreement with
|
||||||
|
written notice to Licensor, effective upon Licensee destroying all copies of
|
||||||
|
PySimpleGUI in its possession and refraining from receiving or downloading
|
||||||
|
further copies.
|
||||||
|
|
||||||
|
8.3. Termination for Licensee's Breach. This limited License will
|
||||||
|
immediately terminate without notice if Licensee fails to comply with any
|
||||||
|
obligation of this Agreement. Additionally, if Licensor reasonably suspects
|
||||||
|
that Licensee has breached the Agreement, then Licensor may deliver written
|
||||||
|
notice of the suspected breach to Licensee, and the Agreement shall
|
||||||
|
automatically terminate 10 days following the date of such notice unless
|
||||||
|
Licensee cures the breach to Licensor's satisfaction within such period.
|
||||||
|
|
||||||
|
8.4. Effect of Termination; Survival. Upon termination of this Agreement for
|
||||||
|
any reason, the licenses granted to Licensee with respect to PySimpleGUI shall
|
||||||
|
immediately terminate and Licensee hereby undertakes to: (i) immediately cease
|
||||||
|
to use, distribute or otherwise exploit any part of PySimpleGUI or any modified
|
||||||
|
version thereof; and (ii) promptly destroy and delete any copy of PySimpleGUI
|
||||||
|
installed or copied by Licensee. Sections 2.1, 2.3, 3, 5-7, 8.4, 9 and 10 will
|
||||||
|
survive termination of this Agreement indefinitely in accordance with their
|
||||||
|
terms.
|
||||||
|
|
||||||
|
9. Assignment; Governing Law. The License is personal to Licensee and
|
||||||
|
Licensee agrees not to transfer, sublicense, lease, rent, or assign their
|
||||||
|
rights under this Agreement, and any such attempt shall be null and void.
|
||||||
|
Licensor may assign, transfer, or sublicense this Agreement or any rights or
|
||||||
|
obligations thereunder at any time in its sole discretion. This Agreement shall
|
||||||
|
be governed by and construed in accordance with the laws of the State of North
|
||||||
|
Carolina and the United States of America without regard to the conflicts of
|
||||||
|
laws provisions thereof. The parties expressly exclude the United Nations
|
||||||
|
Convention on Contracts for the International Sale of Goods from this
|
||||||
|
Agreement. All actions arising out of or in connection with this Agreement
|
||||||
|
shall be brought in the state or federal courts residing in Durham, North
|
||||||
|
Carolina, United States of America, and both parties hereby irrevocably consent
|
||||||
|
to the exclusive jurisdiction of such courts and waive any objections as to
|
||||||
|
venue or inconvenience of forum.
|
||||||
|
|
||||||
|
10. Miscellaneous. No changes or modifications to this Agreement by
|
||||||
|
Licensee or waivers of any provision of this Agreement by Licensor shall be
|
||||||
|
effective unless evidenced in a writing referencing this Agreement and signed
|
||||||
|
for and on behalf of Licensor. The failure of Licensor to enforce its rights
|
||||||
|
under this Agreement at any time for any period shall not be construed as a
|
||||||
|
waiver of such rights. There are no third party beneficiaries hereunder. This
|
||||||
|
Agreement constitutes the entire agreement between the parties regarding the
|
||||||
|
subject matter hereof and supersede all negotiations, conversations, or
|
||||||
|
discussions between or among the parties relating to the subject matter of this
|
||||||
|
Agreement. Neither Party relied on any promises or representations, written or
|
||||||
|
oral, of the other party in forming this Agreement, except for those expressly
|
||||||
|
contained herein. In the event that any provision of this Agreement shall be
|
||||||
|
determined to be unenforceable, that provision will be limited or eliminated to
|
||||||
|
the minimum extent necessary so that this Agreement shall otherwise remain in
|
||||||
|
full force and effect and enforceable. Licensee may not distribute, download or
|
||||||
|
otherwise export or re-export PySimpleGUI or any underlying technology except
|
||||||
|
in full compliance with this Agreement, United States laws and regulations and
|
||||||
|
any other applicable laws and regulations. Licensee represents and warrants
|
||||||
|
that it and its Authorized Developers are not located in, under control of, or
|
||||||
|
a national or resident of any country where exercise of the licenses granted
|
||||||
|
hereunder would not comply with all such laws or regulations. It is agreed that
|
||||||
|
because of the proprietary nature of PySimpleGUI, Licensor's remedies at law
|
||||||
|
for a breach by the Licensee of its obligations under this Agreement may be
|
||||||
|
inadequate and that Licensor will, in the event of such breach, be entitled to,
|
||||||
|
in addition to any other remedy available to it, equitable relief, including
|
||||||
|
injunctive relief, without the posting of any bond and in addition to all other
|
||||||
|
remedies provided under this Agreement or available at law.
|
||||||
|
|
||||||
|
Exhibit A
|
||||||
|
|
||||||
|
PySimpleGUI Flow-Down License Terms
|
||||||
|
|
||||||
|
This product (the "Product") includes PySimpleGUI (https://PySimpleGUI.com) or
|
||||||
|
a version of PySimpleGUI modified by the person or legal entity that provided
|
||||||
|
you with this product ("Provider").
|
||||||
|
|
||||||
|
PySimpleGUI is Copyright (c) PySimpleSoft, Inc. and/or its licensors.
|
||||||
|
|
||||||
|
Use of PySimpleGUI is subject to the license terms available at
|
||||||
|
https://PySimpleGUI.com/eula, including all limitations of liability and other
|
||||||
|
terms set forth therein. By using the Product, you acknowledge and agree that
|
||||||
|
PySimpleSoft has no obligation or liability to you regarding the operation,
|
||||||
|
support or maintenance of PySimpleGUI or of the Product. PYSIMPLEGUI IS
|
||||||
|
PROVIDED "AS IS," WITHOUT ANY WARRANTIES, WHETHER EXPRESS OR IMPLIED.
|
||||||
|
PYSIMPLESOFT DISCLAIMS ALL IMPLIED WARRANTIES, INCLUDING WITHOUT LIMITATION THE
|
||||||
|
IMPLIED WARRANTIES OF NONINFRINGEMENT, TITLE, MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE.
|
||||||
26484
PySimpleGUI/PySimpleGUI.py
Normal file
26484
PySimpleGUI/PySimpleGUI.py
Normal file
File diff suppressed because one or more lines are too long
102
PySimpleGUI/README.md
Normal file
102
PySimpleGUI/README.md
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img src="https://pysimplegui.net/images/big_news_emoji.png">
|
||||||
|
<br>
|
||||||
|
For more information visit <a href="https://home.PySimpleGUI.com">PySimpleGUI.com</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img height="250" src="https://pysimplegui.net/images/logos/Logo_Full_Transparent_Cropped.png">
|
||||||
|
<h2 align="center">User Interfaces for Humans<sup>TM</sup></h2>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
# Welcome to PySimpleGUI 5 !!
|
||||||
|
|
||||||
|
Do you use PySimpleGUI 4? [Here is what you need to know.](https://docs.pysimplegui.com/en/latest/readme/sunset/)
|
||||||
|
|
||||||
|
**PySimpleGUI creates desktop applications easily**, enhancing the tkinter, Qt, WxPython, and Remi frameworks with a much simpler programming interface:
|
||||||
|
|
||||||
|
1. PySimpleGUI user interfaces are defined using core Python data types (lists and dictionaries) that are easily understood by beginners.
|
||||||
|
2. PySimpleGUI event handling changes from a complex callback-based model to a simpple message passing one.
|
||||||
|
3. PySimpleGUI uses simple Python code and has no requirement for object oriented architecture.
|
||||||
|
|
||||||
|
PySimpleGUI is more than a GUI library: PySimpleGUI simplifies much of your Python development process. Sure, it makes developing user interfaces much easier, but PySimpleGUI also tames advanced Python functionality (such as threading) and makes it easy for all users to take their Python applications to the next level. PySimpleGUI is a robust toolkit.
|
||||||
|
|
||||||
|
## Introducing PySimpleGUI 5
|
||||||
|
|
||||||
|
For the last 5 years, PySimpleGUI offered free software with the hope of sustaining the
|
||||||
|
company by donations. We appreciate the support we received, but the amount has been too
|
||||||
|
small to support the PySimpleGUI project. For this reason, PySimpleGUI is switching to a
|
||||||
|
subscription model, where commercial users are expected to pay a nominal annual fee.
|
||||||
|
|
||||||
|
|
||||||
|
PySimpleGUI is now part of PySimpleSoft, Inc., whose mission is to make the best Python
|
||||||
|
application develement environment much, much better. Since launching in 2018, PySimpleGUI
|
||||||
|
has helped hobbyists and professionals alike create Python GUIs in a fraction of the time.
|
||||||
|
PySimpleGUI 5 takes PySimpleGUI to the next level, providing hundreds of improvements,
|
||||||
|
including new features, enhanced security, and priority support.
|
||||||
|
|
||||||
|
|
||||||
|
PySimpleGUI 5 is licensed software. As the [License Agreement](license.txt) explains, after a trial
|
||||||
|
period, all PySimpleGUI 5 users must register at PySimpleGUI.com to obtain a Developer Key.
|
||||||
|
For most users (Hobbyist Users), the license is at NO COST. If you are a Commercial User,
|
||||||
|
subscriptions cost a nominal $99/year.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img height="350" src="https://github.com/PySimpleGUI/PySimpleGUI_NEW_HOME/assets/65144/0b0dabcc-a538-482b-a226-c194ae30aa24">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
[Subscribe Now](https://pricing.PySimpleGUI.com) and help support the PySimpleGUI community.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
PySmipleGUI users have created thousands of amazing desktop applications. Here are a few screen shots. For more examples, see the [PySimpleGUI gallery](https://gallery.PySimpleGUI.com/).
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img height="150" src="https://github.com/PySimpleGUI/PSG5/assets/65144/c80eeaed-1029-4e22-83f9-c46fcc6916e6" />
|
||||||
|
|
||||||
|
<img height="150" src="https://github.com/PySimpleGUI/PSG5/assets/65144/dea22a36-b330-4160-96f7-3c7fcb968977" />
|
||||||
|
|
||||||
|
<img height="150" src="https://github.com/PySimpleGUI/PSG5/assets/65144/a9e30456-87aa-4174-90c2-c062f5cf84b9" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Get Started at No Cost
|
||||||
|
|
||||||
|
Whether you are a Hobbyist User or Commercial User, you can start using PySimpleGUI at no cost.
|
||||||
|
To get started with a 30-day trial period, first install Python and then
|
||||||
|
|
||||||
|
python -m pip install pysimplegui
|
||||||
|
|
||||||
|
and run some code, like
|
||||||
|
|
||||||
|
import PySimpleGUI as sg
|
||||||
|
layout = [ [sg.Text('Hello, world!')] ]
|
||||||
|
window = sg.Window('Hello Example', layout)
|
||||||
|
while True:
|
||||||
|
event, values = window.read()
|
||||||
|
if event == sg.WIN_CLOSED:
|
||||||
|
break
|
||||||
|
window.close()
|
||||||
|
|
||||||
|
(You might need to use `python3` instead of `python`.)
|
||||||
|
|
||||||
|
You can try PySimpleGUI for 30 days, after which you will need to Sign Up. Hobbyist users sign up at no cost, and Commercial Users subscribe at $99/year. For more details, see [PySimpleGUI.com/pricing](https://pricing.PySimpleGUI.com).
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
PySimpleGUI provides extensive documentation. Here are some starting points, depending on your needs and expertise:
|
||||||
|
|
||||||
|
* [Documentation](https://docs.pysimplegui.com/) - Extensive PySimpleGUI documenation
|
||||||
|
* [Cookbook](https://cookbook.pysimplegui.com/) - Step-by-step cookbook of PySimpleGUI basics. Find a recipe that is close to what you want to build and use it as a starting point.
|
||||||
|
* [Examples](https://examples.pysimplegui.com/) - Hundreds of sample PySimpeGUI applications.
|
||||||
|
* [SDK Reference](https://sdk.pysimplegui.com/) - details for each PySimpleGUI element
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3
PySimpleGUI/__init__.py
Normal file
3
PySimpleGUI/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from .PySimpleGUI import *
|
||||||
|
from .PySimpleGUI import __version__
|
||||||
|
|
||||||
4
PySimpleGUI/__main__.py
Normal file
4
PySimpleGUI/__main__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from .PySimpleGUI import *
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
BIN
PySimpleGUI/__pycache__/PySimpleGUI.cpython-310.pyc
Normal file
BIN
PySimpleGUI/__pycache__/PySimpleGUI.cpython-310.pyc
Normal file
Binary file not shown.
BIN
PySimpleGUI/__pycache__/PySimpleGUI.cpython-312.pyc
Normal file
BIN
PySimpleGUI/__pycache__/PySimpleGUI.cpython-312.pyc
Normal file
Binary file not shown.
BIN
PySimpleGUI/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
PySimpleGUI/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
PySimpleGUI/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
PySimpleGUI/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
PySimpleGUI/__pycache__/__main__.cpython-310.pyc
Normal file
BIN
PySimpleGUI/__pycache__/__main__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
__pycache__/device_conversion.cpython-310.pyc
Normal file
BIN
__pycache__/device_conversion.cpython-310.pyc
Normal file
Binary file not shown.
469
_device_main.py
Normal file
469
_device_main.py
Normal file
@ -0,0 +1,469 @@
|
|||||||
|
from PySimpleGUI import TIMEOUT_KEY, WIN_CLOSED
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import socket
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import device_interaction as dev
|
||||||
|
|
||||||
|
import gui
|
||||||
|
|
||||||
|
use_client = False
|
||||||
|
|
||||||
|
sending_param = {}
|
||||||
|
|
||||||
|
#### ---- Constants
|
||||||
|
|
||||||
|
GUI_TIMEOUT_INTERVAL = 5#505 - dev.WAIT_AFTER_SEND*1000 # GUI refresh time in milliseconds
|
||||||
|
|
||||||
|
SAVE_POINTS_NUMBER = 1000 # Number of most recent data points kept in memory
|
||||||
|
|
||||||
|
INITIAL_TEMPERATURE_1 = 22.40 # Set initial temperature for Laser 1 in Celsius: from -1 to 45 C ??
|
||||||
|
INITIAL_TEMPERATURE_2 = 16.70 # Set initial temperature for Laser 2 in Celsius: from -1 to 45 C ??
|
||||||
|
INITIAL_CURRENT_1 = 32.0 # 64.0879 max # Set initial current for Laser 1, in mA
|
||||||
|
INITIAL_CURRENT_2 = 32.0 # 64.0879 max # Set initial current for Laser 2, in mA
|
||||||
|
|
||||||
|
#### ---- Functions
|
||||||
|
|
||||||
|
def start_task(prt):
|
||||||
|
global sending_param
|
||||||
|
dev.send_task_command(prt, sending_param)
|
||||||
|
|
||||||
|
def stop_task(prt):
|
||||||
|
global sending_param
|
||||||
|
sending_param = {}
|
||||||
|
dev.reset_port_settings(prt)
|
||||||
|
dev.send_control_parameters(prt, params)
|
||||||
|
|
||||||
|
def get_float(values, strId):
|
||||||
|
value = 0.0
|
||||||
|
try:
|
||||||
|
value = float(values[strId])
|
||||||
|
except:
|
||||||
|
value = float("nan")
|
||||||
|
window['-StartCycle-'].update(disabled = True)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def shorten(i):
|
||||||
|
return "{:.2f}".format(round(i, 2))
|
||||||
|
|
||||||
|
|
||||||
|
def set_initial_params():
|
||||||
|
params = {}
|
||||||
|
params['Temp_1'] = INITIAL_TEMPERATURE_1 # Initial temperature for Laser 1
|
||||||
|
params['Temp_2'] = INITIAL_TEMPERATURE_2 # Initial temperature for Laser 2
|
||||||
|
params['ProportionalCoeff_1'] = int(10*256) # Proportional coefficient for temperature stabilizatoin for Laser 1 <-- ToDo (why int?)
|
||||||
|
params['ProportionalCoeff_2'] = int(10*256) # Proportional coefficient for temperature stabilizatoin for Laser 2 <-- ToDo (why int?)
|
||||||
|
params['IntegralCoeff_1'] = int(0.5*256) # Integral coefficient for temperature stabilizatoin for Laser 1 <-- ToDo (why int?)
|
||||||
|
params['IntegralCoeff_2'] = int(0.5*256) # Integral coefficient for temperature stabilizatoin for Laser 2 <-- ToDo (why int?)
|
||||||
|
params['Message_ID'] = "00FF" # Send Message ID (hex format)
|
||||||
|
params['Iset_1'] = INITIAL_CURRENT_1 # Currency value array for Laser 1, in mA
|
||||||
|
params['Iset_2'] = INITIAL_CURRENT_2 # Currency value array for Laser 2, in mA
|
||||||
|
params['Min_Temp_1'] = INITIAL_TEMPERATURE_1
|
||||||
|
params['Max_Temp_1'] = 28
|
||||||
|
params['Min_Current_1'] = INITIAL_CURRENT_1
|
||||||
|
params['Max_Current_1'] = 50.0
|
||||||
|
params['Delta_Temp_1'] = 0.05
|
||||||
|
params['Delta_Current_1'] = 0.05
|
||||||
|
params['Min_Temp_2'] = INITIAL_TEMPERATURE_2
|
||||||
|
params['Max_Temp_2'] = 28
|
||||||
|
params['Min_Current_2'] = INITIAL_CURRENT_2
|
||||||
|
params['Max_Current_2'] = 50.0
|
||||||
|
params['Delta_Temp_2'] = 0.05
|
||||||
|
params['Delta_Current_2'] = 0.05
|
||||||
|
params['Delta_Time'] = 50
|
||||||
|
params['Tau'] = 3
|
||||||
|
return params
|
||||||
|
|
||||||
|
def update_data_lists():
|
||||||
|
saved_data.append(data)
|
||||||
|
if len(saved_data)>SAVE_POINTS_NUMBER:
|
||||||
|
saved_data.pop(0)
|
||||||
|
|
||||||
|
draw_data.append(data)
|
||||||
|
if len(draw_data)>gui.GRAPH_POINTS_NUMBER:
|
||||||
|
draw_data.pop(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
######## ---- Main program
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
saved_data = []
|
||||||
|
draw_data = []
|
||||||
|
|
||||||
|
params = set_initial_params()
|
||||||
|
|
||||||
|
prt = dev.create_port_connection()
|
||||||
|
if prt is None:
|
||||||
|
print('Can\'t create connection. Closing program...')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# dev.request_state(prt)
|
||||||
|
dev.send_control_parameters(prt, params)
|
||||||
|
saved_data.append(dev.request_data(prt))
|
||||||
|
draw_data.append(saved_data[0])
|
||||||
|
|
||||||
|
window = gui.setup_gui(params)
|
||||||
|
axes_signs = gui.sign_axes(window)
|
||||||
|
|
||||||
|
current_and_temperature_settings_available = True
|
||||||
|
disableStartButton = False
|
||||||
|
|
||||||
|
if use_client:
|
||||||
|
p = subprocess.Popen("path/to/oscilloscope.exe")
|
||||||
|
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sck.bind(("127.0.0.1", 9090))
|
||||||
|
sck.listen()
|
||||||
|
conn, _ = sck.accept()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
event, values = window.read(timeout=GUI_TIMEOUT_INTERVAL)
|
||||||
|
|
||||||
|
enable_manual_settings = window['-EnableManualSettings-'].get()
|
||||||
|
if current_and_temperature_settings_available:
|
||||||
|
window['-EnableT1-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-EnableT2-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-EnableC1-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-EnableC2-'].update(disabled = enable_manual_settings)
|
||||||
|
|
||||||
|
window['-InputMinT1-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputMaxT1-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputDeltaT1-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputMinT2-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputMaxT2-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputDeltaT2-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputMinC1-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputMaxC1-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputDeltaC1-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputMinC2-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputMaxC2-'].update(disabled = enable_manual_settings)
|
||||||
|
window['-InputDeltaC2-'].update(disabled = enable_manual_settings)
|
||||||
|
|
||||||
|
window['-InputT1-'].update(disabled = not enable_manual_settings)
|
||||||
|
window['-InputT2-'].update(disabled = not enable_manual_settings)
|
||||||
|
window['-InputI1-'].update(disabled = not enable_manual_settings)
|
||||||
|
window['-InputI2-'].update(disabled = not enable_manual_settings)
|
||||||
|
|
||||||
|
window['-StartCycle-'].update(disabled = not enable_manual_settings)
|
||||||
|
|
||||||
|
if current_and_temperature_settings_available and not enable_manual_settings:
|
||||||
|
enable_t1 = window['-EnableT1-'].get()
|
||||||
|
enable_t2 = window['-EnableT2-'].get()
|
||||||
|
enable_c1 = window['-EnableC1-'].get()
|
||||||
|
enable_c2 = window['-EnableC2-'].get()
|
||||||
|
|
||||||
|
sending_param['ProportionalCoeff_1'] = params['ProportionalCoeff_1']
|
||||||
|
sending_param['IntegralCoeff_1'] = params['IntegralCoeff_1']
|
||||||
|
sending_param['ProportionalCoeff_2'] = params['ProportionalCoeff_2']
|
||||||
|
sending_param['IntegralCoeff_2'] = params['IntegralCoeff_2']
|
||||||
|
|
||||||
|
if enable_t1 and \
|
||||||
|
not enable_t2 and \
|
||||||
|
not enable_c1 and \
|
||||||
|
not enable_c2:
|
||||||
|
sending_param['TaskType'] = dev.cmd.TaskType.ChangeTemperatureLD1
|
||||||
|
sending_param['MinT1'] = get_float(values, '-InputMinT1-')
|
||||||
|
sending_param['MaxT1'] = get_float(values, '-InputMaxT1-')
|
||||||
|
sending_param['DeltaT1'] = get_float(values, '-InputDeltaT1-')
|
||||||
|
sending_param['I1'] = get_float(values, '-InputI1-')
|
||||||
|
sending_param['I2'] = get_float(values, '-InputI2-')
|
||||||
|
sending_param['T2'] = get_float(values, '-InputT2-')
|
||||||
|
sending_param['Dt'] = get_float(values ,'-InputDeltaTime-')
|
||||||
|
sending_param['Tau'] = get_float(values ,'-InputTau-')
|
||||||
|
|
||||||
|
disableStartButton = math.isnan(sending_param['MinT1']) or \
|
||||||
|
math.isnan(sending_param['MaxT1']) or \
|
||||||
|
math.isnan(sending_param['DeltaT1']) or \
|
||||||
|
math.isnan(sending_param['I1']) or \
|
||||||
|
math.isnan(sending_param['I2']) or \
|
||||||
|
math.isnan(sending_param['T2']) or \
|
||||||
|
math.isnan(sending_param['Dt']) or \
|
||||||
|
math.isnan(sending_param['Tau'])
|
||||||
|
|
||||||
|
window['-EnableT2-'].update(disabled = enable_t1)
|
||||||
|
window['-EnableC1-'].update(disabled = enable_t1)
|
||||||
|
window['-EnableC2-'].update(disabled = enable_t1)
|
||||||
|
enable_t2 = window['-EnableT2-'].get()
|
||||||
|
enable_c1 = window['-EnableC1-'].get()
|
||||||
|
enable_c2 = window['-EnableC2-'].get()
|
||||||
|
window['-InputMinT1-'].update(disabled = not enable_t1)
|
||||||
|
window['-InputMaxT1-'].update(disabled = not enable_t1)
|
||||||
|
window['-InputDeltaT1-'].update(disabled = not enable_t1)
|
||||||
|
window['-InputI1-'].update(disabled = not enable_t1)
|
||||||
|
window['-InputI2-'].update(disabled = not enable_t1)
|
||||||
|
window['-InputT2-'].update(disabled = not enable_t1)
|
||||||
|
window['-InputMinT2-'].update(disabled = enable_t1)
|
||||||
|
window['-InputMaxT2-'].update(disabled = enable_t1)
|
||||||
|
window['-InputDeltaT2-'].update(disabled = enable_t1)
|
||||||
|
window['-InputMinC1-'].update(disabled = enable_t1)
|
||||||
|
window['-InputMaxC1-'].update(disabled = enable_t1)
|
||||||
|
window['-InputDeltaC1-'].update(disabled = enable_t1)
|
||||||
|
window['-InputMinC2-'].update(disabled = enable_t1)
|
||||||
|
window['-InputMaxC2-'].update(disabled = enable_t1)
|
||||||
|
window['-InputDeltaC2-'].update(disabled = enable_t1)
|
||||||
|
window['-EnableManualSettings-'].update(disabled = True)
|
||||||
|
elif enable_t2 and \
|
||||||
|
not enable_t1 and \
|
||||||
|
not enable_c1 and \
|
||||||
|
not enable_c2:
|
||||||
|
sending_param['TaskType'] = dev.cmd.TaskType.ChangeTemperatureLD2
|
||||||
|
sending_param['MinT2'] = get_float(values, '-InputMinT2-')
|
||||||
|
sending_param['MaxT2'] = get_float(values, '-InputMaxT2-')
|
||||||
|
sending_param['DeltaT2'] = get_float(values, '-InputDeltaT2-')
|
||||||
|
sending_param['I1'] = get_float(values, '-InputI1-')
|
||||||
|
sending_param['I2'] = get_float(values, '-InputI2-')
|
||||||
|
sending_param['T1'] = get_float(values, '-InputT1-')
|
||||||
|
sending_param['Dt'] = get_float(values ,'-InputDeltaTime-')
|
||||||
|
sending_param['Tau'] = get_float(values ,'-InputTau-')
|
||||||
|
disableStartButton = math.isnan(sending_param['MinT2']) or \
|
||||||
|
math.isnan(sending_param['MaxT2']) or \
|
||||||
|
math.isnan(sending_param['DeltaT2']) or \
|
||||||
|
math.isnan(sending_param['I1']) or \
|
||||||
|
math.isnan(sending_param['I2']) or \
|
||||||
|
math.isnan(sending_param['T1']) or \
|
||||||
|
math.isnan(sending_param['Dt']) or \
|
||||||
|
math.isnan(sending_param['Tau'])
|
||||||
|
|
||||||
|
window['-EnableT1-'].update(disabled = enable_t2)
|
||||||
|
window['-EnableC1-'].update(disabled = enable_t2)
|
||||||
|
window['-EnableC2-'].update(disabled = enable_t2)
|
||||||
|
enable_t1 = window['-EnableT1-'].get()
|
||||||
|
enable_c1 = window['-EnableC1-'].get()
|
||||||
|
enable_c2 = window['-EnableC2-'].get()
|
||||||
|
window['-InputMinT1-'].update(disabled = enable_t2)
|
||||||
|
window['-InputMaxT1-'].update(disabled = enable_t2)
|
||||||
|
window['-InputDeltaT1-'].update(disabled = enable_t2)
|
||||||
|
window['-InputT1-'].update(disabled = not enable_t2)
|
||||||
|
window['-InputI1-'].update(disabled = not enable_t2)
|
||||||
|
window['-InputI2-'].update(disabled = not enable_t2)
|
||||||
|
window['-InputMinT2-'].update(disabled = not enable_t2)
|
||||||
|
window['-InputMaxT2-'].update(disabled = not enable_t2)
|
||||||
|
window['-InputDeltaT2-'].update(disabled = not enable_t2)
|
||||||
|
window['-InputMinC1-'].update(disabled = enable_t2)
|
||||||
|
window['-InputMaxC1-'].update(disabled = enable_t2)
|
||||||
|
window['-InputDeltaC1-'].update(disabled = enable_t2)
|
||||||
|
window['-InputMinC2-'].update(disabled = enable_t2)
|
||||||
|
window['-InputMaxC2-'].update(disabled = enable_t2)
|
||||||
|
window['-InputDeltaC2-'].update(disabled = enable_t2)
|
||||||
|
window['-EnableManualSettings-'].update(disabled = True)
|
||||||
|
elif enable_c1 and \
|
||||||
|
not enable_c2 and \
|
||||||
|
not enable_t1 and \
|
||||||
|
not enable_t2:
|
||||||
|
sending_param['TaskType'] = dev.cmd.TaskType.ChangeCurrentLD1
|
||||||
|
sending_param['MinC1'] = get_float(values, '-InputMinC1-')
|
||||||
|
sending_param['MaxC1'] = get_float(values, '-InputMaxC1-')
|
||||||
|
sending_param['DeltaC1'] = get_float(values, '-InputDeltaC1-')
|
||||||
|
sending_param['T1'] = get_float(values, '-InputT1-')
|
||||||
|
sending_param['T2'] = get_float(values, '-InputT2-')
|
||||||
|
sending_param['I2'] = get_float(values, '-InputI2-')
|
||||||
|
sending_param['Dt'] = get_float(values ,'-InputDeltaTime-')
|
||||||
|
sending_param['Tau'] = get_float(values ,'-InputTau-')
|
||||||
|
disableStartButton = math.isnan(sending_param['MinC1']) or \
|
||||||
|
math.isnan(sending_param['MaxC1']) or \
|
||||||
|
math.isnan(sending_param['DeltaC1']) or \
|
||||||
|
math.isnan(sending_param['T1']) or \
|
||||||
|
math.isnan(sending_param['T2']) or \
|
||||||
|
math.isnan(sending_param['I2']) or \
|
||||||
|
math.isnan(sending_param['Dt']) or \
|
||||||
|
math.isnan(sending_param['Tau'])
|
||||||
|
|
||||||
|
window['-EnableT1-'].update(disabled = enable_c1)
|
||||||
|
window['-EnableT2-'].update(disabled = enable_c1)
|
||||||
|
window['-EnableC2-'].update(disabled = enable_c1)
|
||||||
|
enable_t1 = window['-EnableT1-'].get()
|
||||||
|
enable_t2 = window['-EnableT2-'].get()
|
||||||
|
enable_c2 = window['-EnableC2-'].get()
|
||||||
|
window['-InputMinT1-'].update(disabled = enable_c1)
|
||||||
|
window['-InputMaxT1-'].update(disabled = enable_c1)
|
||||||
|
window['-InputDeltaT1-'].update(disabled = enable_c1)
|
||||||
|
window['-InputT1-'].update(disabled = not enable_c1)
|
||||||
|
window['-InputT2-'].update(disabled = not enable_c1)
|
||||||
|
window['-InputI2-'].update(disabled = not enable_c1)
|
||||||
|
window['-InputMinT2-'].update(disabled = enable_c1)
|
||||||
|
window['-InputMaxT2-'].update(disabled = enable_c1)
|
||||||
|
window['-InputDeltaT2-'].update(disabled = enable_c1)
|
||||||
|
window['-InputMinC1-'].update(disabled = not enable_c1)
|
||||||
|
window['-InputMaxC1-'].update(disabled = not enable_c1)
|
||||||
|
window['-InputDeltaC1-'].update(disabled = not enable_c1)
|
||||||
|
window['-InputMinC2-'].update(disabled = enable_c1)
|
||||||
|
window['-InputMaxC2-'].update(disabled = enable_c1)
|
||||||
|
window['-InputDeltaC2-'].update(disabled = enable_c1)
|
||||||
|
window['-EnableManualSettings-'].update(disabled = True)
|
||||||
|
elif enable_c2 and \
|
||||||
|
not enable_c1 and \
|
||||||
|
not enable_t1 and \
|
||||||
|
not enable_t2:
|
||||||
|
sending_param['TaskType'] = dev.cmd.TaskType.ChangeCurrentLD2
|
||||||
|
sending_param['MinC2'] = get_float(values, '-InputMinC2-')
|
||||||
|
sending_param['MaxC2'] = get_float(values, '-InputMaxC2-')
|
||||||
|
sending_param['DeltaC2'] = get_float(values, '-InputDeltaC2-')
|
||||||
|
sending_param['T1'] = get_float(values, '-InputT1-')
|
||||||
|
sending_param['T2'] = get_float(values, '-InputT2-')
|
||||||
|
sending_param['I1'] = get_float(values, '-InputI1-')
|
||||||
|
sending_param['Dt'] = get_float(values ,'-InputDeltaTime-')
|
||||||
|
sending_param['Tau'] = get_float(values ,'-InputTau-')
|
||||||
|
disableStartButton = math.isnan(sending_param['MinC2']) or \
|
||||||
|
math.isnan(sending_param['MaxC2']) or \
|
||||||
|
math.isnan(sending_param['DeltaC2']) or \
|
||||||
|
math.isnan(sending_param['T1']) or \
|
||||||
|
math.isnan(sending_param['T2']) or \
|
||||||
|
math.isnan(sending_param['I1']) or \
|
||||||
|
math.isnan(sending_param['Dt']) or \
|
||||||
|
math.isnan(sending_param['Tau'])
|
||||||
|
|
||||||
|
window['-EnableT1-'].update(disabled = enable_c2)
|
||||||
|
window['-EnableT2-'].update(disabled = enable_c2)
|
||||||
|
window['-EnableC1-'].update(disabled = enable_c2)
|
||||||
|
enable_t1 = window['-EnableT1-'].get()
|
||||||
|
enable_t2 = window['-EnableT2-'].get()
|
||||||
|
enable_c1 = window['-EnableC1-'].get()
|
||||||
|
window['-InputMinT1-'].update(disabled = enable_c2)
|
||||||
|
window['-InputMaxT1-'].update(disabled = enable_c2)
|
||||||
|
window['-InputDeltaT1-'].update(disabled = enable_c2)
|
||||||
|
window['-InputI1-'].update(disabled = not enable_c2)
|
||||||
|
window['-InputT1-'].update(disabled = not enable_c2)
|
||||||
|
window['-InputT2-'].update(disabled = not enable_c2)
|
||||||
|
window['-InputMinT2-'].update(disabled = enable_c2)
|
||||||
|
window['-InputMaxT2-'].update(disabled = enable_c2)
|
||||||
|
window['-InputDeltaT2-'].update(disabled = enable_c2)
|
||||||
|
window['-InputMinC1-'].update(disabled = enable_c2)
|
||||||
|
window['-InputMaxC1-'].update(disabled = enable_c2)
|
||||||
|
window['-InputDeltaC1-'].update(disabled = enable_c2)
|
||||||
|
window['-InputMinC2-'].update(disabled = not enable_c2)
|
||||||
|
window['-InputMaxC2-'].update(disabled = not enable_c2)
|
||||||
|
window['-InputDeltaC2-'].update(disabled = not enable_c2)
|
||||||
|
window['-EnableManualSettings-'].update(disabled = True)
|
||||||
|
elif not enable_t1 and \
|
||||||
|
not enable_t2 and \
|
||||||
|
not enable_c1 and \
|
||||||
|
not enable_c2:
|
||||||
|
sending_param = {}
|
||||||
|
|
||||||
|
window['-EnableT1-'].update(disabled = False)
|
||||||
|
window['-EnableT2-'].update(disabled = False)
|
||||||
|
window['-EnableC1-'].update(disabled = False)
|
||||||
|
window['-EnableC2-'].update(disabled = False)
|
||||||
|
window['-InputMinT1-'].update(disabled = True)
|
||||||
|
window['-InputMaxT1-'].update(disabled = True)
|
||||||
|
window['-InputDeltaT1-'].update(disabled = True)
|
||||||
|
window['-InputMinT2-'].update(disabled = True)
|
||||||
|
window['-InputMaxT2-'].update(disabled = True)
|
||||||
|
window['-InputDeltaT2-'].update(disabled = True)
|
||||||
|
window['-InputMinC1-'].update(disabled = True)
|
||||||
|
window['-InputMaxC1-'].update(disabled = True)
|
||||||
|
window['-InputDeltaC1-'].update(disabled = True)
|
||||||
|
window['-InputMinC2-'].update(disabled = True)
|
||||||
|
window['-InputMaxC2-'].update(disabled = True)
|
||||||
|
window['-InputDeltaC2-'].update(disabled = True)
|
||||||
|
window['-InputT1-'].update(disabled = True)
|
||||||
|
window['-InputT2-'].update(disabled = True)
|
||||||
|
window['-InputI1-'].update(disabled = True)
|
||||||
|
window['-InputI2-'].update(disabled = True)
|
||||||
|
window['-EnableManualSettings-'].update(disabled = False)
|
||||||
|
|
||||||
|
window['-InputDeltaTime-'].update(disabled = not enable_c1 and not enable_t1 and not enable_c2 and not enable_t2)
|
||||||
|
window['-InputTau-'].update(disabled = not enable_c1 and not enable_t1 and not enable_c2 and not enable_t2)
|
||||||
|
|
||||||
|
window['-StartCycle-'].update(disabled = not enable_c1 and not enable_t1 and not enable_c2 and not enable_t2 or disableStartButton)
|
||||||
|
|
||||||
|
if event == WIN_CLOSED or event == '-EXIT-':
|
||||||
|
if use_client:
|
||||||
|
p.terminate()
|
||||||
|
conn.close()
|
||||||
|
sck.close()
|
||||||
|
dev.reset_port_settings(prt)
|
||||||
|
break
|
||||||
|
|
||||||
|
elif event == '-StartCycle-':
|
||||||
|
if not enable_manual_settings:
|
||||||
|
window['-StopCycle-'].update(disabled = False)
|
||||||
|
window['-StartCycle-'].update(disabled = True)
|
||||||
|
window['-EnableT1-'].update(disabled = True)
|
||||||
|
window['-EnableC1-'].update(disabled = True)
|
||||||
|
window['-EnableT1-'].update(False)
|
||||||
|
window['-EnableC1-'].update(False)
|
||||||
|
window['-EnableT2-'].update(disabled = True)
|
||||||
|
window['-EnableC2-'].update(disabled = True)
|
||||||
|
window['-EnableT2-'].update(False)
|
||||||
|
window['-EnableC2-'].update(False)
|
||||||
|
window['-InputMinT1-'].update(disabled = True)
|
||||||
|
window['-InputMaxT1-'].update(disabled = True)
|
||||||
|
window['-InputDeltaT1-'].update(disabled = True)
|
||||||
|
window['-InputMinT2-'].update(disabled = True)
|
||||||
|
window['-InputMaxT2-'].update(disabled = True)
|
||||||
|
window['-InputDeltaT2-'].update(disabled = True)
|
||||||
|
window['-InputMinC1-'].update(disabled = True)
|
||||||
|
window['-InputMaxC1-'].update(disabled = True)
|
||||||
|
window['-InputDeltaC1-'].update(disabled = True)
|
||||||
|
window['-InputMinC2-'].update(disabled = True)
|
||||||
|
window['-InputMaxC2-'].update(disabled = True)
|
||||||
|
window['-InputDeltaC2-'].update(disabled = True)
|
||||||
|
window['-InputDeltaTime-'].update(disabled = True)
|
||||||
|
window['-InputTau-'].update(disabled = True)
|
||||||
|
window['-InputT1-'].update(disabled = True)
|
||||||
|
window['-InputT2-'].update(disabled = True)
|
||||||
|
window['-InputI1-'].update(disabled = True)
|
||||||
|
window['-InputI2-'].update(disabled = True)
|
||||||
|
current_and_temperature_settings_available = False
|
||||||
|
# TODO get task parameters from gui and put its to params
|
||||||
|
|
||||||
|
if use_client:
|
||||||
|
jsondoc_str = json.dumps(sending_param)
|
||||||
|
jsondoc = bytearray()
|
||||||
|
jsondoc.extend(jsondoc_str.encode())
|
||||||
|
conn.sendall(jsondoc)
|
||||||
|
|
||||||
|
start_task(prt)
|
||||||
|
else:
|
||||||
|
params['Temp_1'] = float(values['-InputT1-'])
|
||||||
|
params['Temp_2'] = float(values['-InputT2-'])
|
||||||
|
params['Iset_1'] = float(values['-InputI1-'])
|
||||||
|
params['Iset_2'] = float(values['-InputI2-'])
|
||||||
|
dev.send_control_parameters(prt, params)
|
||||||
|
#print(sending_param)
|
||||||
|
elif event == '-StopCycle-':
|
||||||
|
window['-StopCycle-'].update(disabled = True)
|
||||||
|
current_and_temperature_settings_available = True
|
||||||
|
stop_task(prt)
|
||||||
|
elif event == TIMEOUT_KEY:
|
||||||
|
data = dev.request_data(prt)
|
||||||
|
|
||||||
|
update_data_lists()
|
||||||
|
|
||||||
|
window['-TOUT_1-'].update(gui.READ_TEMPERATURE_TEXT+' 1: '+shorten(data['Temp_1'])+' C')
|
||||||
|
window['-TOUT_2-'].update(gui.READ_TEMPERATURE_TEXT+' 2: '+shorten(data['Temp_2'])+' C')
|
||||||
|
window['-IOUT_1-'].update(gui.READ_CURRENT_TEXT+' 1: '+shorten(data['I1'])+' мА')
|
||||||
|
window['-IOUT_2-'].update(gui.READ_CURRENT_TEXT+' 2: '+shorten(data['I2'])+' мА')
|
||||||
|
window['-DateTime-'].update(data['datetime'].strftime('%d-%m-%Y %H:%M:%S:%f')[:-3])
|
||||||
|
window['-TTerm1-'].update('T терм 1: '+shorten(data['Temp_Ext_1'])+' C')
|
||||||
|
window['-TTerm2-'].update('T терм 2: '+shorten(data['Temp_Ext_2'])+' C')
|
||||||
|
window['-3V3-'].update('3V3: '+shorten(data['MON_3V3'])+' В')
|
||||||
|
window['-5V1-'].update('5V1: '+shorten(data['MON_5V1'])+' В')
|
||||||
|
window['-5V2-'].update('5V2: '+shorten(data['MON_5V2'])+' В')
|
||||||
|
window['-7V0-'].update('7V0: '+shorten(data['MON_7V0'])+' В')
|
||||||
|
|
||||||
|
window['-GraphT1-'].draw_line((len(draw_data)-1, draw_data[-2]['Temp_1']), (len(draw_data), draw_data[-1]['Temp_1']), color='yellow')
|
||||||
|
window['-GraphT2-'].draw_line((len(draw_data)-1, draw_data[-2]['Temp_2']), (len(draw_data), draw_data[-1]['Temp_2']), color='yellow')
|
||||||
|
window['-GraphI1-'].draw_line((len(draw_data)-1, draw_data[-2]['I1']), (len(draw_data), draw_data[-1]['I1']), color='yellow')
|
||||||
|
window['-GraphI2-'].draw_line((len(draw_data)-1, draw_data[-2]['I2']), (len(draw_data), draw_data[-1]['I2']), color='yellow')
|
||||||
|
|
||||||
|
# When graphs reach end of X scale, start scrolling
|
||||||
|
if len(draw_data)>=gui.GRAPH_POINTS_NUMBER:
|
||||||
|
# Scroll graphs
|
||||||
|
window['-GraphT1-'].move(-1, 0)
|
||||||
|
window['-GraphT2-'].move(-1, 0)
|
||||||
|
window['-GraphI1-'].move(-1, 0)
|
||||||
|
window['-GraphI2-'].move(-1, 0)
|
||||||
|
|
||||||
|
# Scroll back graphs' labels
|
||||||
|
for key, sgn in axes_signs.items():
|
||||||
|
window[key].MoveFigure(sgn[0], 1, 0)
|
||||||
|
window[key].MoveFigure(sgn[1], 1, 0)
|
||||||
|
|
||||||
|
window.close()
|
||||||
|
|
||||||
|
dev.close_connection(prt)
|
||||||
|
|
||||||
|
|
||||||
346
device_commands.py
Normal file
346
device_commands.py
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
from enum import IntEnum
|
||||||
|
from serial import Serial
|
||||||
|
from serial.tools import list_ports
|
||||||
|
import device_conversion as cnv
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
#### ---- Constants
|
||||||
|
|
||||||
|
GET_DATA_TOTAL_LENGTH = 30 # Total number of bytes when getting DATA
|
||||||
|
SEND_PARAMS_TOTAL_LENGTH = 30 # Total number of bytes when sending parameters
|
||||||
|
TASK_ENABLE_COMMAND_LENGTH = 32 # Total number of bytes when sending TASK_ENABLE command
|
||||||
|
|
||||||
|
class TaskType(IntEnum):
|
||||||
|
Manual = 0x00
|
||||||
|
ChangeCurrentLD1 = 0x01
|
||||||
|
ChangeCurrentLD2 = 0x02
|
||||||
|
ChangeTemperatureLD1 = 0x03
|
||||||
|
ChangeTemperatureLD2 = 0x04
|
||||||
|
#### ---- Auxiliary functions
|
||||||
|
|
||||||
|
def int_to_hex(inp):
|
||||||
|
if inp<0 or inp>65535:
|
||||||
|
print("Error. Input should be within [0, 65535]. Returning N=0.")
|
||||||
|
return "0000"
|
||||||
|
return f"{inp:#0{6}x}"[2:]
|
||||||
|
|
||||||
|
def crc(lst):
|
||||||
|
crc=int("0x"+lst[0],16)
|
||||||
|
for i in range(1,len(lst)):
|
||||||
|
crc=crc^int("0x"+lst[i],16)
|
||||||
|
return int_to_hex(crc)
|
||||||
|
|
||||||
|
def show_hex_string(string):
|
||||||
|
return "".join("\\x{}".format(char.encode()) for char in (string[i:i+2] for i in range(0, len(string), 2)))
|
||||||
|
|
||||||
|
|
||||||
|
def flipfour(s):
|
||||||
|
''' Changes "abcd" to "cdba"
|
||||||
|
'''
|
||||||
|
if len(s) != 4:
|
||||||
|
print("Error. Trying to flip string with length not equal to 4.")
|
||||||
|
return None
|
||||||
|
return s[2:4]+s[0:2]
|
||||||
|
|
||||||
|
|
||||||
|
#### ---- Port Operations
|
||||||
|
|
||||||
|
|
||||||
|
def setup_port_connection(baudrate: int, port: str, timeout_sec: float):
|
||||||
|
prt = Serial()
|
||||||
|
prt.baudrate = baudrate
|
||||||
|
prt.port = port
|
||||||
|
prt.timeout = timeout_sec
|
||||||
|
return prt
|
||||||
|
|
||||||
|
|
||||||
|
def open_port(prt):
|
||||||
|
prt.open()
|
||||||
|
|
||||||
|
if prt.is_open:
|
||||||
|
print("Connection succesful. Port is opened.")
|
||||||
|
print("Port parameters:", prt)
|
||||||
|
print("")
|
||||||
|
else:
|
||||||
|
print("Can't open port. Exiting program.")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
def close_port(prt):
|
||||||
|
prt.close()
|
||||||
|
print("")
|
||||||
|
if prt.is_open:
|
||||||
|
print("Can't close port. Exiting program.")
|
||||||
|
exit()
|
||||||
|
else:
|
||||||
|
print("Port is closed. Exiting program.")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
#### ---- Interacting with device: low-level
|
||||||
|
|
||||||
|
# ---- Sending commands
|
||||||
|
|
||||||
|
def send_TASK_ENABLE(prt, bytestring):
|
||||||
|
''' Set task parameters (x7777 + ...).
|
||||||
|
Expected device answer: STATE.
|
||||||
|
'''
|
||||||
|
if len(bytestring) != TASK_ENABLE_COMMAND_LENGTH:
|
||||||
|
print("Error. Wrong parameter string for TASK_ENABLE.")
|
||||||
|
return None
|
||||||
|
prt.write(bytestring)
|
||||||
|
print("Sent: Set control parameters (TASK_ENABLE).")
|
||||||
|
|
||||||
|
def send_DECODE_ENABLE(prt, bytestring):
|
||||||
|
''' Set control parameters (x1111 + ...).
|
||||||
|
Expected device answer: STATE.
|
||||||
|
'''
|
||||||
|
if len(bytestring) != SEND_PARAMS_TOTAL_LENGTH:
|
||||||
|
print("Error. Wrong parameter string for DECODE_ENABLE.")
|
||||||
|
return None
|
||||||
|
prt.write(bytestring)
|
||||||
|
print("Sent: Set control parameters (DECODE_ENABLE).")
|
||||||
|
|
||||||
|
|
||||||
|
def send_DEFAULT_ENABLE(prt):
|
||||||
|
''' Reset the device (x2222).
|
||||||
|
Expected device answer: STATE.
|
||||||
|
'''
|
||||||
|
input = bytearray.fromhex(flipfour("2222"))
|
||||||
|
prt.write(input)
|
||||||
|
print("Sent: Reset device (DEFAULT_ENABLE).")
|
||||||
|
|
||||||
|
|
||||||
|
def send_TRANSS_ENABLE(prt):
|
||||||
|
''' Request all saved data (x3333).
|
||||||
|
Expected device answer: SAVED_DATA.
|
||||||
|
'''
|
||||||
|
# TODO later.
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def send_TRANS_ENABLE(prt):
|
||||||
|
''' Request last piece of data (x4444).
|
||||||
|
Expected device answer: DATA.
|
||||||
|
'''
|
||||||
|
input = bytearray.fromhex(flipfour("4444"))
|
||||||
|
prt.write(input)
|
||||||
|
print("Sent: Request last data (TRANS_ENABLE).")
|
||||||
|
|
||||||
|
|
||||||
|
def send_REMOVE_FILE(prt):
|
||||||
|
''' Delete saved data (x5555).
|
||||||
|
Expected device answer: STATE.
|
||||||
|
'''
|
||||||
|
input = bytearray.fromhex(flipfour("5555"))
|
||||||
|
prt.write(input)
|
||||||
|
print("Sent: Delete saved data (REMOVE_FILE).")
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def send_STATE(prt):
|
||||||
|
''' Request state (x6666).
|
||||||
|
Expected device answer: STATE.
|
||||||
|
'''
|
||||||
|
input = bytearray.fromhex(flipfour("6666"))
|
||||||
|
prt.write(input)
|
||||||
|
print("Sent: Request state (STATE).")
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# ---- Getting data
|
||||||
|
|
||||||
|
|
||||||
|
def get_STATE(prt):
|
||||||
|
''' Get decoded state of the device in byte format (2 bytes).
|
||||||
|
'''
|
||||||
|
|
||||||
|
print("Received "+str(prt.inWaiting())+" bytes.")
|
||||||
|
if prt.inWaiting()!=2:
|
||||||
|
print("Error. Couldn't get STATE data. prt.inWaiting():", prt.inWaiting())
|
||||||
|
print("Flushing input data:", prt.read(prt.inWaiting()))
|
||||||
|
# print("Flushing input data:", prt.read(2), prt.read(2))
|
||||||
|
return None
|
||||||
|
|
||||||
|
out_bytes = prt.read(2)
|
||||||
|
return out_bytes
|
||||||
|
|
||||||
|
|
||||||
|
def get_DATA(prt):
|
||||||
|
''' Get decoded state of the device in byte format (426 bytes).
|
||||||
|
'''
|
||||||
|
|
||||||
|
print("Received "+str(prt.inWaiting())+" bytes.\n")
|
||||||
|
if prt.inWaiting()!=GET_DATA_TOTAL_LENGTH:
|
||||||
|
print("Error. Couldn't get DATA data.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
out_bytes = prt.read(GET_DATA_TOTAL_LENGTH)
|
||||||
|
return out_bytes
|
||||||
|
|
||||||
|
|
||||||
|
#### ---- Interacting with device: decode/encode messages
|
||||||
|
|
||||||
|
# ---- Encoding functions
|
||||||
|
def CalculateCRC(data):
|
||||||
|
CRC_input = []
|
||||||
|
for i in range(1,int(len(data)/4)):
|
||||||
|
CRC_input.append(data[4*i:4*i+4])
|
||||||
|
return crc(CRC_input)
|
||||||
|
|
||||||
|
def encode_Setup():
|
||||||
|
bits=['0']*16
|
||||||
|
|
||||||
|
bits[15] = "1" # enable work
|
||||||
|
bits[14] = "1" # enable 5v1
|
||||||
|
bits[13] = "1" # enable 5v2
|
||||||
|
bits[12] = "1" # enable LD1
|
||||||
|
bits[11] = "1" # enable LD2
|
||||||
|
bits[10] = "1" # enable REF1
|
||||||
|
bits[9] = "1" # enable REF2
|
||||||
|
bits[8] = "1" # enable TEC1
|
||||||
|
bits[7] = "1" # enable TEC2
|
||||||
|
bits[6] = "1" # enable temp stab 1
|
||||||
|
bits[5] = "1" # enable temp stab 2
|
||||||
|
bits[4] = "0" # enable sd save
|
||||||
|
bits[3] = "1" # enable PI1 coef read
|
||||||
|
bits[2] = "1" # enable PI2 coef read
|
||||||
|
bits[1] = "0" # reserved
|
||||||
|
bits[0] = "0" # reserved
|
||||||
|
|
||||||
|
s="".join([str(i) for i in bits])
|
||||||
|
return hex(int(s,2))[2:]
|
||||||
|
|
||||||
|
def create_TaskEnableCommand(sending_param):
|
||||||
|
data = flipfour("7777") # Word 0
|
||||||
|
data += flipfour(encode_Setup()) # Word 1
|
||||||
|
data += flipfour(int_to_hex(sending_param['TaskType'])) # Word 2
|
||||||
|
match sending_param['TaskType']:
|
||||||
|
case TaskType.ChangeCurrentLD1.value:
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['MinC1']))) # Word 3
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['MaxC1']))) # Word 4
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['DeltaC1']))) # Word 5
|
||||||
|
data += flipfour(int_to_hex(int(sending_param['Dt']*100))) # Word 6
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_T_C_to_N(sending_param['T1']))) # Word 7
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['I2']))) # Word 8
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_T_C_to_N(sending_param['T2']))) # Word 9
|
||||||
|
case TaskType.ChangeCurrentLD2.value:
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['MinC2']))) # Word 3
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['MaxC2']))) # Word 4
|
||||||
|
data += flipfour(int_to_hex(int(sending_param['DeltaC2']*100))) # Word 5
|
||||||
|
data += flipfour(int_to_hex(int(sending_param['Dt']*100))) # Word 6
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_T_C_to_N(sending_param['T2']))) # Word 7
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['I1']))) # Word 8
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_T_C_to_N(sending_param['T1']))) # Word 9
|
||||||
|
case TaskType.ChangeTemperatureLD1:
|
||||||
|
raise Exception("Temperature changing is not implemented yet")
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['MinT1']))) # Word 3
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['MaxT1']))) # Word 4
|
||||||
|
data += flipfour(int_to_hex(sending_param['DeltaT1']*100)) # Word 5
|
||||||
|
data += flipfour(int_to_hex(sending_param['Dt']*100)) # Word 6
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_T_C_to_N(sending_param['I1']))) # Word 7
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['I2']))) # Word 8
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_T_C_to_N(sending_param['T2']))) # Word 9
|
||||||
|
case TaskType.ChangeTemperatureLD2:
|
||||||
|
raise Exception("Temperature changing is not implemented yet")
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['MinT2']))) # Word 3
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['MaxT2']))) # Word 4
|
||||||
|
data += flipfour(int_to_hex(sending_param['DeltaT2']*100)) # Word 5
|
||||||
|
data += flipfour(int_to_hex(sending_param['Dt']*100)) # Word 6
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_T_C_to_N(sending_param['I2']))) # Word 7
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(sending_param['I1']))) # Word 8
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_T_C_to_N(sending_param['T1']))) # Word 9
|
||||||
|
case _:
|
||||||
|
raise Exception(f"Undefined TaskType:{sending_param['TaskType']}")
|
||||||
|
data += flipfour(int_to_hex(int(sending_param['Tau']))) # Word 10
|
||||||
|
data += flipfour(int_to_hex(sending_param['ProportionalCoeff_1'])) # Word 11
|
||||||
|
data += flipfour(int_to_hex(sending_param['IntegralCoeff_1'])) # Word 12
|
||||||
|
data += flipfour(int_to_hex(sending_param['ProportionalCoeff_2'])) # Word 13
|
||||||
|
data += flipfour(int_to_hex(sending_param['IntegralCoeff_2'])) # Word 14
|
||||||
|
data += CalculateCRC(data) # Word 15
|
||||||
|
|
||||||
|
return bytearray.fromhex(data)
|
||||||
|
|
||||||
|
def encode_Input(params):
|
||||||
|
|
||||||
|
if params is None:
|
||||||
|
return bytearray.fromhex("1111"+"00"*14)
|
||||||
|
|
||||||
|
data = flipfour("1111") # Word 0
|
||||||
|
data += flipfour(encode_Setup()) # Word 1
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_T_C_to_N(params['Temp_1']))) # Word 2
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_T_C_to_N(params['Temp_2']))) # Word 3
|
||||||
|
data += flipfour("0000")*3 # Words 4-6
|
||||||
|
data += flipfour(int_to_hex(params['ProportionalCoeff_1'])) # Word 7
|
||||||
|
data += flipfour(int_to_hex(params['IntegralCoeff_1'])) # Word 8
|
||||||
|
data += flipfour(int_to_hex(params['ProportionalCoeff_2'])) # Word 9
|
||||||
|
data += flipfour(int_to_hex(params['IntegralCoeff_2'])) # Word 10
|
||||||
|
data += flipfour(params['Message_ID']) # Word 11
|
||||||
|
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(params['Iset_1']))) # Word 12
|
||||||
|
data += flipfour(int_to_hex(cnv.conv_I_mA_to_N(params['Iset_2']))) # Word 13
|
||||||
|
|
||||||
|
CRC_input = []
|
||||||
|
for i in range(1,int(len(data)/4)):
|
||||||
|
CRC_input.append(data[4*i:4*i+4])
|
||||||
|
|
||||||
|
CRC = crc(CRC_input)
|
||||||
|
data += CRC # Word 14
|
||||||
|
|
||||||
|
return bytearray.fromhex(data)
|
||||||
|
|
||||||
|
|
||||||
|
# ---- Decoding functions
|
||||||
|
|
||||||
|
def decode_STATE(state):
|
||||||
|
st = flipfour(state)
|
||||||
|
if st == '0000':
|
||||||
|
status = "All ok."
|
||||||
|
elif st == '0001':
|
||||||
|
status = "SD Card reading/writing error (SD_ERR)."
|
||||||
|
elif st == '0002':
|
||||||
|
status = "Command error (UART_ERR)."
|
||||||
|
elif st == '0004':
|
||||||
|
status = "Wrong parameter value error (UART_DECODE_ERR)."
|
||||||
|
elif st == '0008':
|
||||||
|
status = "Laser 1: TEC driver overheat (TEC1_ERR)."
|
||||||
|
elif st == '0010':
|
||||||
|
status = "Laser 2: TEC driver overheat (TEC2_ERR)."
|
||||||
|
elif st == '0020':
|
||||||
|
status = "Resetting system error (DEFAULT_ERR)."
|
||||||
|
elif st == '0040':
|
||||||
|
status = "File deletion error (REMOVE_ERR)."
|
||||||
|
else:
|
||||||
|
status = "Unknown or reserved error."
|
||||||
|
return status
|
||||||
|
|
||||||
|
|
||||||
|
def decode_DATA(dh):
|
||||||
|
def get_word(s,num):
|
||||||
|
return flipfour(s[num*2*2:num*2*2+4])
|
||||||
|
def get_int_word(s,num):
|
||||||
|
return int(get_word(s,num),16)
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
data['datetime'] = datetime.now()
|
||||||
|
data['Header'] = get_word(dh, 0)
|
||||||
|
data['I1'] = cnv.conv_I_N_to_mA(get_int_word(dh, 1))
|
||||||
|
data['I2'] = cnv.conv_I_N_to_mA(get_int_word(dh, 2))
|
||||||
|
data['TO_LSB'] = get_int_word(dh, 3)
|
||||||
|
data['TO_MSB'] = get_int_word(dh, 4)
|
||||||
|
data['Temp_1'] = cnv.conv_T_N_to_C(get_int_word(dh, 5))
|
||||||
|
data['Temp_2'] = cnv.conv_T_N_to_C(get_int_word(dh, 6))
|
||||||
|
data['Temp_Ext_1'] = cnv.conv_TExt_N_to_C(get_int_word(dh, 7))
|
||||||
|
data['Temp_Ext_2'] = cnv.conv_TExt_N_to_C(get_int_word(dh, 8))
|
||||||
|
data['MON_3V3'] = cnv.conv_U3V3_N_to_V(get_int_word(dh, 9))
|
||||||
|
data['MON_5V1'] = cnv.conv_U5V_N_to_V(get_int_word(dh, 10))
|
||||||
|
data['MON_5V2'] = cnv.conv_U5V_N_to_V(get_int_word(dh, 11))
|
||||||
|
data['MON_7V0'] = cnv.conv_U7V_N_to_V(get_int_word(dh, 12))
|
||||||
|
data['Message_ID'] = get_word(dh, 13) # Last received command
|
||||||
|
data['CRC'] = get_word(dh, 14)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
68
device_conversion.py
Normal file
68
device_conversion.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
|
# ---- Conversion functions
|
||||||
|
|
||||||
|
VREF = 2.5 # Volts
|
||||||
|
|
||||||
|
R1 = 10000 # Ohm
|
||||||
|
R2 = 2200 # Ohm
|
||||||
|
R3 = 27000 # Ohm
|
||||||
|
R4 = 30000 # Ohm
|
||||||
|
R5 = 27000 # Ohm
|
||||||
|
R6 = 56000 # Ohm
|
||||||
|
|
||||||
|
RREF = 28.7 # Ohm (current-setting resistor) @1550 nm - 28.7 Ohm; @840 nm - 10 Ohm
|
||||||
|
|
||||||
|
R7 = 22000 # Ohm
|
||||||
|
R8 = 22000 # Ohm
|
||||||
|
R9 = 5100 # Ohm
|
||||||
|
R10 = 180000 # Ohm
|
||||||
|
|
||||||
|
class Task:
|
||||||
|
def __init__(self):
|
||||||
|
self.task_type = 0
|
||||||
|
# Here should be fields, contained task parameters
|
||||||
|
|
||||||
|
def conv_T_C_to_N(T):
|
||||||
|
Rt = 10000 * math.exp( 3900/(T+273) - 3900/298 )
|
||||||
|
U = VREF/(R5*(R3+R4)) * ( R1*R4*(R5+R6) - Rt*(R3*R6-R4*R5) ) / (Rt+R1)
|
||||||
|
N = int(U * 65535 / VREF)
|
||||||
|
if N<0 or N>65535:
|
||||||
|
print("Error converting T=" + str(T) + " to N=" + str(N) + ". N should be within [0, 65535]. Returning N=0.")
|
||||||
|
return N
|
||||||
|
|
||||||
|
def conv_T_N_to_C(N):
|
||||||
|
U = N*VREF/65535 # Volts
|
||||||
|
Rt = R1 * (VREF*R4*(R5+R6) - U*R5*(R3+R4)) / (U*R5*(R3+R4) + VREF*R3*R6 - VREF*R4*R5) # Ohm
|
||||||
|
T = 1 / (1/298 + 1/3900 * math.log(Rt/10000)) - 273 # In Celsius
|
||||||
|
return T
|
||||||
|
|
||||||
|
def conv_TExt_N_to_C(N):
|
||||||
|
U = N*VREF/4095*1/(1+100000/R10) + VREF*R9/(R8+R9) # Volts
|
||||||
|
Rt = R7*U/(VREF-U) # Ohm
|
||||||
|
T = 1 / (1/298 + 1/3455 * math.log(Rt/10000)) - 273 # In Celsius
|
||||||
|
return T
|
||||||
|
|
||||||
|
def conv_I_mA_to_N(I):
|
||||||
|
N = int(65535/2000 * RREF * I) # I in mA
|
||||||
|
if N<0 or N>65535:
|
||||||
|
print("Error converting I=" + str(I) + " to N=" + str(N) + ". N should be within [0, 65535]. Returning N=0.")
|
||||||
|
N=0
|
||||||
|
return N
|
||||||
|
|
||||||
|
def conv_I_N_to_mA(N):
|
||||||
|
return N*2.5/(65535*4.4) - 1/20.4 # I in mA
|
||||||
|
|
||||||
|
|
||||||
|
def conv_U3V3_N_to_V(u_int):
|
||||||
|
return u_int * 1.221 * 0.001 # Volts
|
||||||
|
|
||||||
|
def conv_U5V_N_to_V(u_int):
|
||||||
|
return u_int * 1.8315 * 0.001 # Volts
|
||||||
|
|
||||||
|
def conv_U7V_N_to_V(u_int):
|
||||||
|
return u_int * 6.72 * 0.001 # Volts
|
||||||
|
|
||||||
|
|
||||||
110
device_interaction.py
Normal file
110
device_interaction.py
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
import device_commands as cmd
|
||||||
|
|
||||||
|
|
||||||
|
#### ---- Constants
|
||||||
|
|
||||||
|
WAIT_AFTER_SEND = 0.15 # Wait after sending command, before requesting input (in seconds).
|
||||||
|
|
||||||
|
|
||||||
|
#### ---- High-level port commands
|
||||||
|
|
||||||
|
def create_port_connection():
|
||||||
|
prt = None
|
||||||
|
for port, _, _ in sorted(cmd.list_ports.comports()):
|
||||||
|
try:
|
||||||
|
prt = cmd.setup_port_connection(port=port, baudrate=115200, timeout_sec=1)
|
||||||
|
cmd.open_port(prt)
|
||||||
|
reset_port_settings(prt)
|
||||||
|
except:
|
||||||
|
prt.close()
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
return prt
|
||||||
|
|
||||||
|
# def setup_connection():
|
||||||
|
# prt = cmd.setup_port_connection()
|
||||||
|
# cmd.open_port(prt)
|
||||||
|
# return prt
|
||||||
|
|
||||||
|
|
||||||
|
def reset_port_settings(prt):
|
||||||
|
# Reset port settings and check status
|
||||||
|
cmd.send_DEFAULT_ENABLE(prt)
|
||||||
|
time.sleep(WAIT_AFTER_SEND)
|
||||||
|
status = cmd.get_STATE(prt).hex()
|
||||||
|
if status is not None:
|
||||||
|
print("Received: STATE. State status:", cmd.decode_STATE(status), "("+cmd.flipfour(status)+")")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
|
||||||
|
def request_state(prt):
|
||||||
|
# Request data
|
||||||
|
cmd.send_STATE(prt)
|
||||||
|
time.sleep(WAIT_AFTER_SEND)
|
||||||
|
status = cmd.get_STATE(prt).hex()
|
||||||
|
if status is not None:
|
||||||
|
print("Received: STATE. State status:", cmd.decode_STATE(status), "("+cmd.flipfour(status)+")")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
|
||||||
|
def send_control_parameters(prt, params):
|
||||||
|
# Send control parameters
|
||||||
|
hexstring = cmd.encode_Input(params)
|
||||||
|
cmd.send_DECODE_ENABLE(prt,hexstring)
|
||||||
|
time.sleep(WAIT_AFTER_SEND)
|
||||||
|
status = cmd.get_STATE(prt).hex()
|
||||||
|
if status is not None:
|
||||||
|
print("Received: STATE. State status:", cmd.decode_STATE(status), "("+cmd.flipfour(status)+")")
|
||||||
|
print("")
|
||||||
|
else:
|
||||||
|
print("")
|
||||||
|
|
||||||
|
def send_task_command(prt, sending_param):
|
||||||
|
# Send task command (TASK_ENABLE state in firmware)
|
||||||
|
hexstring = cmd.create_TaskEnableCommand(sending_param)
|
||||||
|
cmd.send_TASK_ENABLE(prt,hexstring)
|
||||||
|
time.sleep(WAIT_AFTER_SEND)
|
||||||
|
status = cmd.get_STATE(prt).hex()
|
||||||
|
if status is not None:
|
||||||
|
print("Received: STATE. State status:", cmd.decode_STATE(status), "("+cmd.flipfour(status)+")")
|
||||||
|
print("")
|
||||||
|
else:
|
||||||
|
print("")
|
||||||
|
|
||||||
|
def request_data(prt):
|
||||||
|
# Request data
|
||||||
|
cmd.send_TRANS_ENABLE(prt)
|
||||||
|
time.sleep(WAIT_AFTER_SEND)
|
||||||
|
data = cmd.get_DATA(prt).hex()
|
||||||
|
data_dict = []
|
||||||
|
if data is not None:
|
||||||
|
data_dict = cmd.decode_DATA(data)
|
||||||
|
return data_dict
|
||||||
|
|
||||||
|
|
||||||
|
def print_data(data):
|
||||||
|
def shorten(i):
|
||||||
|
return str(round(i, 2))
|
||||||
|
|
||||||
|
print("Data from device (time: "+datetime.now().strftime("%H:%M:%S:%f")+"):")
|
||||||
|
print("Message Header:", data['Header'], " Message ID:", data['Message_ID'])
|
||||||
|
print("Photodiode Current 1 ("+str(len(data['I1']))+" values):", \
|
||||||
|
shorten(data['I1']), shorten(data['I1'][1]), "...", \
|
||||||
|
shorten(data['I1']), shorten(data['I1'][-1]), "mA")
|
||||||
|
print("Photodiode Current 2 ("+str(len(data['I2']))+" values):", \
|
||||||
|
shorten(data['I2']), shorten(data['I2'][1]), "...", \
|
||||||
|
shorten(data['I2']), shorten(data['I2'][-1]), "mA")
|
||||||
|
print("Laser Temperature 1:", shorten(data['Temp_1']), "C")
|
||||||
|
print("Laser Temperature 2:", shorten(data['Temp_2']), "C")
|
||||||
|
print("Temperature of external thermistor 1:", shorten(data['Temp_Ext_1']), "C")
|
||||||
|
print("Temperature of external thermistor 2:", shorten(data['Temp_Ext_2']), "C")
|
||||||
|
print("Voltages 3V3: "+shorten(data['MON_3V3'])+"V 5V1: "+shorten(data['MON_5V1'])+ \
|
||||||
|
"V 5V2: "+shorten(data['MON_5V2'])+"V 7V0: "+shorten(data['MON_7V0'])+"V.")
|
||||||
|
|
||||||
|
def close_connection(prt):
|
||||||
|
cmd.close_port(prt)
|
||||||
201
gui.py
Normal file
201
gui.py
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
|
||||||
|
import PySimpleGUI as sg
|
||||||
|
|
||||||
|
#### ---- GUI Constants
|
||||||
|
|
||||||
|
WINDOW_TITLE = 'Модуль управления лазерной схемой оптического смесителя (Отдел радиофотоники МФТИ)'
|
||||||
|
WINDOW_SIZE = [0, 0]
|
||||||
|
|
||||||
|
SET_BUTTON_TEXT = 'Задать'
|
||||||
|
|
||||||
|
SET_TEMPERATURE_TEXT_1 = 'Установка температуры лазера 1 (C):'
|
||||||
|
SET_TEMPERATURE_TEXT_2 = 'Установка температуры лазера 2 (C):'
|
||||||
|
SET_CURRENT_TEXT_1 = 'Управляющий ток лазера 1 (15-60 мА):'
|
||||||
|
SET_CURRENT_TEXT_2 = 'Управляющий ток лазера 2 (15-60 мА):'
|
||||||
|
SET_MANUAL_MODE_TEXT = 'Ручной режим ввода'
|
||||||
|
SET_TEXT_WIDTH = 34
|
||||||
|
SET_INPUT_WIDTH = 5
|
||||||
|
|
||||||
|
SET_MIN_TEMPERATURE_TEXT_1 = 'Минимальная температура лазера 1 (C):'
|
||||||
|
SET_MAX_TEMPERATURE_TEXT_1 = 'Максимальная температура лазера 1 (C):'
|
||||||
|
SET_DELTA_TEMPERATURE_TEXT_1 = 'Шаг дискретизации температуры лазера 1 (0.05-1 С):'
|
||||||
|
SET_MIN_CURRENT_TEXT_1 = 'Мнимальный ток лазера 1 (мА):'
|
||||||
|
SET_MAX_CURRENT_TEXT_1 = 'Максимальный ток лазера 1 (мА):'
|
||||||
|
SET_DELTA_CURRENT_TEXT_1 = 'Шаг дискретизации тока лазера 1 (0.002-0.5 мА):'
|
||||||
|
SET_MIN_TEMPERATURE_TEXT_2 = 'Минимальная температура лазера 2 (C):'
|
||||||
|
SET_MAX_TEMPERATURE_TEXT_2 = 'Максимальная температура лазера 2 (C):'
|
||||||
|
SET_DELTA_TEMPERATURE_TEXT_2 = 'Шаг дискретизации температуры лазера 2 (0.05-1 С):'
|
||||||
|
SET_MIN_CURRENT_TEXT_2 = 'Мнимальный ток лазера 2 (мА):'
|
||||||
|
SET_MAX_CURRENT_TEXT_2 = 'Максимальный ток лазера 2 (мА):'
|
||||||
|
SET_DELTA_CURRENT_TEXT_2 = 'Шаг дискретизации тока лазера 2 (0.002-0.5 мА):'
|
||||||
|
SET_DELTA_T_TEXT = 'Шаг дискретизации времени (1-100 мкс):'
|
||||||
|
SET_TAU_T_TEXT = 'Время задержки (3-10мс):'
|
||||||
|
SET_TEXT_WIDTH_NEW = 40
|
||||||
|
|
||||||
|
SET_START_BUTTON_TEXT = 'Пуск'
|
||||||
|
SET_STOP_BUTTON_TEXT = 'Стоп'
|
||||||
|
|
||||||
|
|
||||||
|
GRAPH_POINTS_NUMBER = 100 # Number of most recent data points shown on charts
|
||||||
|
GRAPH_CANVAS_SIZE = (0, 0)
|
||||||
|
GRAPH_BG_COLOR = '#303030'
|
||||||
|
GRAPH_SIGN_AXES_COLOR = 'orange'
|
||||||
|
|
||||||
|
GRAPH_T_MIN = 0 # Celsius
|
||||||
|
GRAPH_T_MAX = 50 # Celsius
|
||||||
|
GRAPH_I_MIN = 0.0 # mA
|
||||||
|
GRAPH_I_MAX = 1.0 # mA
|
||||||
|
|
||||||
|
|
||||||
|
READ_TEMPERATURE_TEXT = 'Температура лазера'
|
||||||
|
READ_CURRENT_TEXT = 'Ток фотодиода'
|
||||||
|
|
||||||
|
VOLTAGE_TEXT_WIDTH = 15
|
||||||
|
|
||||||
|
|
||||||
|
#### ---- Setting GUI
|
||||||
|
|
||||||
|
def get_screen_size():
|
||||||
|
window = sg.Window('Test')
|
||||||
|
global WINDOW_SIZE
|
||||||
|
WINDOW_SIZE = window.get_screen_size()
|
||||||
|
window.close()
|
||||||
|
global GRAPH_CANVAS_SIZE
|
||||||
|
GRAPH_CANVAS_SIZE = (int(WINDOW_SIZE[0]/3.5), int(WINDOW_SIZE[0]/(3*2.75)))
|
||||||
|
return WINDOW_SIZE
|
||||||
|
|
||||||
|
def setup_gui(params):
|
||||||
|
|
||||||
|
sg.theme("DarkBlue12")
|
||||||
|
|
||||||
|
screen_size = get_screen_size()
|
||||||
|
|
||||||
|
layout_input_col1 = [[sg.Text(SET_TEMPERATURE_TEXT_1), sg.Push(),
|
||||||
|
sg.Input(params['Temp_1'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputT1-', disabled = True)],
|
||||||
|
|
||||||
|
[sg.Text(SET_CURRENT_TEXT_1), sg.Push(),
|
||||||
|
sg.Input(params['Iset_1'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputI1-', disabled = True)],
|
||||||
|
|
||||||
|
[sg.HSeparator(pad=(1,20))],
|
||||||
|
|
||||||
|
[sg.Push(), sg.Text(READ_TEMPERATURE_TEXT+' 1: ', key='-TOUT_1-')],
|
||||||
|
|
||||||
|
[sg.Graph(canvas_size=GRAPH_CANVAS_SIZE, graph_bottom_left=(0, GRAPH_T_MIN), graph_top_right=(GRAPH_POINTS_NUMBER, GRAPH_T_MAX),
|
||||||
|
background_color=GRAPH_BG_COLOR, enable_events=False, drag_submits=False, key='-GraphT1-')],
|
||||||
|
|
||||||
|
# [sg.HSeparator(pad=(10,15), color=sg.theme_background_color())],
|
||||||
|
|
||||||
|
[sg.Push(), sg.Text(READ_CURRENT_TEXT+' 1: ', pad=(5, (20,5)), key='-IOUT_1-')],
|
||||||
|
|
||||||
|
[sg.Graph(canvas_size=GRAPH_CANVAS_SIZE, graph_bottom_left=(0, GRAPH_I_MIN), graph_top_right=(GRAPH_POINTS_NUMBER, GRAPH_I_MAX),
|
||||||
|
background_color=GRAPH_BG_COLOR, enable_events=False, drag_submits=False, key='-GraphI1-')]]
|
||||||
|
|
||||||
|
|
||||||
|
layout_input_col2 = [[sg.Text(SET_TEMPERATURE_TEXT_2), sg.Push(),
|
||||||
|
sg.Input(params['Temp_2'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputT2-', disabled = True)],
|
||||||
|
|
||||||
|
[sg.Text(SET_CURRENT_TEXT_2), sg.Push(),
|
||||||
|
sg.Input(params['Iset_2'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputI2-', disabled = True)],
|
||||||
|
|
||||||
|
[sg.HSeparator(pad=(1,20))],
|
||||||
|
|
||||||
|
[sg.Push(), sg.Text(READ_TEMPERATURE_TEXT+' 2: ', key='-TOUT_2-')],
|
||||||
|
|
||||||
|
[sg.Graph(canvas_size=GRAPH_CANVAS_SIZE, graph_bottom_left=(0, GRAPH_T_MIN), graph_top_right=(GRAPH_POINTS_NUMBER, GRAPH_T_MAX),
|
||||||
|
background_color=GRAPH_BG_COLOR, enable_events=False, drag_submits=False, key='-GraphT2-')],
|
||||||
|
|
||||||
|
# [sg.HSeparator(pad=(10,15), color=sg.theme_background_color())],
|
||||||
|
|
||||||
|
[sg.Push(), sg.Text(READ_CURRENT_TEXT+' 2: ', pad=(5, (20,5)), key='-IOUT_2-')],
|
||||||
|
|
||||||
|
[sg.Graph(canvas_size=GRAPH_CANVAS_SIZE, graph_bottom_left=(0, GRAPH_I_MIN), graph_top_right=(GRAPH_POINTS_NUMBER, GRAPH_I_MAX),
|
||||||
|
background_color=GRAPH_BG_COLOR, enable_events=False, drag_submits=False, key='-GraphI2-')]]
|
||||||
|
|
||||||
|
layout_input_col3 = [
|
||||||
|
[sg.Text(SET_MANUAL_MODE_TEXT), sg.Checkbox('', default=False, key='-EnableManualSettings-')],
|
||||||
|
|
||||||
|
[sg.Text(SET_MIN_TEMPERATURE_TEXT_1, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Min_Temp_1'], size=(SET_INPUT_WIDTH,1), key='-InputMinT1-', disabled=True, disabled_readonly_background_color="Gray"), sg.Checkbox('', default=False, key='-EnableT1-')],
|
||||||
|
|
||||||
|
[sg.Text(SET_MAX_TEMPERATURE_TEXT_1, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Max_Temp_1'], size=(SET_INPUT_WIDTH,1), key='-InputMaxT1-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||||
|
|
||||||
|
[sg.Text(SET_MIN_CURRENT_TEXT_1, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Min_Current_1'], size=(SET_INPUT_WIDTH,1), key='-InputMinC1-', disabled=True, disabled_readonly_background_color="Gray"), sg.Checkbox('', default=False, key='-EnableC1-')],
|
||||||
|
|
||||||
|
[sg.Text(SET_MAX_CURRENT_TEXT_1, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Max_Current_1'], size=(SET_INPUT_WIDTH,1), key='-InputMaxC1-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||||
|
|
||||||
|
[sg.Text(SET_DELTA_TEMPERATURE_TEXT_1, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Delta_Temp_1'], size=(SET_INPUT_WIDTH,1), key='-InputDeltaT1-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||||
|
|
||||||
|
[sg.Text(SET_DELTA_CURRENT_TEXT_1, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Delta_Current_1'], size=(SET_INPUT_WIDTH,1), key='-InputDeltaC1-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||||
|
|
||||||
|
[sg.HSeparator(pad=(1,20))],
|
||||||
|
|
||||||
|
[sg.Text(SET_MIN_TEMPERATURE_TEXT_2, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Min_Temp_2'], size=(SET_INPUT_WIDTH,1), key='-InputMinT2-', disabled=True, disabled_readonly_background_color="Gray"), sg.Checkbox('', default=False, key='-EnableT2-')],
|
||||||
|
|
||||||
|
[sg.Text(SET_MAX_TEMPERATURE_TEXT_2, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Max_Temp_2'], size=(SET_INPUT_WIDTH,1), key='-InputMaxT2-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||||
|
|
||||||
|
[sg.Text(SET_MIN_CURRENT_TEXT_2, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Min_Current_2'], size=(SET_INPUT_WIDTH,1), key='-InputMinC2-', disabled=True, disabled_readonly_background_color="Gray"), sg.Checkbox('', default=False, key='-EnableC2-')],
|
||||||
|
|
||||||
|
[sg.Text(SET_MAX_CURRENT_TEXT_2, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Max_Current_2'], size=(SET_INPUT_WIDTH,1), key='-InputMaxC2-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||||
|
|
||||||
|
[sg.Text(SET_DELTA_TEMPERATURE_TEXT_2, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Delta_Temp_2'], size=(SET_INPUT_WIDTH,1), key='-InputDeltaT2-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||||
|
|
||||||
|
[sg.Text(SET_DELTA_CURRENT_TEXT_2, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Delta_Current_2'], size=(SET_INPUT_WIDTH,1), key='-InputDeltaC2-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||||
|
|
||||||
|
[sg.HSeparator(pad=(1,20))],
|
||||||
|
|
||||||
|
[sg.Text(SET_DELTA_T_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Delta_Time'], size=(SET_INPUT_WIDTH,1), key='-InputDeltaTime-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||||
|
|
||||||
|
[sg.Text(SET_TAU_T_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||||
|
sg.Input(params['Tau'], size=(SET_INPUT_WIDTH,1), key='-InputTau-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||||
|
|
||||||
|
[sg.HSeparator(pad=(1,20))],
|
||||||
|
|
||||||
|
[sg.Button(SET_START_BUTTON_TEXT, key='-StartCycle-', disabled_button_color=("Gray22", "Blue"), disabled=True), sg.Button(SET_STOP_BUTTON_TEXT, disabled_button_color=("Gray22", "Blue"), key='-StopCycle-', disabled=True)]]
|
||||||
|
|
||||||
|
|
||||||
|
layout = [[sg.Column(layout_input_col1), sg.VSeparator(), sg.Column(layout_input_col2), sg.VSeparator(), sg.Column(layout_input_col3)],
|
||||||
|
|
||||||
|
[sg.HSeparator(pad=(25,10))],
|
||||||
|
|
||||||
|
[sg.Text('', size=(7,1)),
|
||||||
|
sg.Text('T терм 1:', size=(VOLTAGE_TEXT_WIDTH,1), key='-TTerm1-'), sg.Text('T терм 2:', size=(VOLTAGE_TEXT_WIDTH,1), key='-TTerm2-'),
|
||||||
|
sg.Text('3V3:', size=(VOLTAGE_TEXT_WIDTH,1), key='-3V3-'), sg.Text('5V1:', size=(VOLTAGE_TEXT_WIDTH,1), key='-5V1-'),
|
||||||
|
sg.Text('5V2:', size=(VOLTAGE_TEXT_WIDTH,1), key='-5V2-'), sg.Text('7V0:', size=(VOLTAGE_TEXT_WIDTH,1), key='-7V0-'),
|
||||||
|
sg.Push(), sg.Text('', key='-DateTime-', pad=(1,10)),
|
||||||
|
sg.Text('', size=(10,1))],
|
||||||
|
|
||||||
|
[sg.Exit('Выход', pad=(1,5), size=(10,1), key='-EXIT-')]]
|
||||||
|
|
||||||
|
window = sg.Window(WINDOW_TITLE, layout, finalize=True, element_justification='c', size=screen_size)
|
||||||
|
window.bind('<Escape>', '-EXIT-')
|
||||||
|
return window
|
||||||
|
|
||||||
|
|
||||||
|
def sign_axes(window):
|
||||||
|
signs_dict = {}
|
||||||
|
signs_dict['-GraphT1-'] = \
|
||||||
|
(window['-GraphT1-'].draw_text(text=str(GRAPH_T_MIN)+' C', location=(3, GRAPH_T_MIN+(GRAPH_T_MAX-GRAPH_T_MIN)*0.05), color=GRAPH_SIGN_AXES_COLOR),
|
||||||
|
window['-GraphT1-'].draw_text(text=str(GRAPH_T_MAX)+' C', location=(3, GRAPH_T_MAX-(GRAPH_T_MAX-GRAPH_T_MIN)*0.05), color=GRAPH_SIGN_AXES_COLOR))
|
||||||
|
signs_dict['-GraphI1-'] = \
|
||||||
|
(window['-GraphI1-'].draw_text(text=str(GRAPH_I_MIN)+' мА', location=(4, GRAPH_I_MIN+(GRAPH_I_MAX-GRAPH_I_MIN)*0.05), color=GRAPH_SIGN_AXES_COLOR),
|
||||||
|
window['-GraphI1-'].draw_text(text=str(GRAPH_I_MAX)+' мА', location=(4, GRAPH_I_MAX-(GRAPH_I_MAX-GRAPH_I_MIN)*0.05), color=GRAPH_SIGN_AXES_COLOR))
|
||||||
|
signs_dict['-GraphT2-'] = \
|
||||||
|
(window['-GraphT2-'].draw_text(text=str(GRAPH_T_MIN)+' C', location=(3, GRAPH_T_MIN+(GRAPH_T_MAX-GRAPH_T_MIN)*0.05), color=GRAPH_SIGN_AXES_COLOR),
|
||||||
|
window['-GraphT2-'].draw_text(text=str(GRAPH_T_MAX)+' C', location=(3, GRAPH_T_MAX-(GRAPH_T_MAX-GRAPH_T_MIN)*0.05), color=GRAPH_SIGN_AXES_COLOR))
|
||||||
|
signs_dict['-GraphI2-'] = \
|
||||||
|
(window['-GraphI2-'].draw_text(text=str(GRAPH_I_MIN)+' мА', location=(4, GRAPH_I_MIN+(GRAPH_I_MAX-GRAPH_I_MIN)*0.05), color=GRAPH_SIGN_AXES_COLOR),
|
||||||
|
window['-GraphI2-'].draw_text(text=str(GRAPH_I_MAX)+' мА', location=(4, GRAPH_I_MAX-(GRAPH_I_MAX-GRAPH_I_MIN)*0.05), color=GRAPH_SIGN_AXES_COLOR))
|
||||||
|
return signs_dict
|
||||||
|
|
||||||
Reference in New Issue
Block a user