diff --git a/luci-app-gpoint-main/Images/logo.png b/luci-app-gpoint-main/Images/logo.png deleted file mode 100644 index cd81bc607..000000000 Binary files a/luci-app-gpoint-main/Images/logo.png and /dev/null differ diff --git a/luci-app-gpoint-main/Images/overview.png b/luci-app-gpoint-main/Images/overview.png deleted file mode 100644 index 4942bf81d..000000000 Binary files a/luci-app-gpoint-main/Images/overview.png and /dev/null differ diff --git a/luci-app-gpoint-main/Images/overview_wait.png b/luci-app-gpoint-main/Images/overview_wait.png deleted file mode 100644 index ebe30a42d..000000000 Binary files a/luci-app-gpoint-main/Images/overview_wait.png and /dev/null differ diff --git a/luci-app-gpoint-main/Images/settings.png b/luci-app-gpoint-main/Images/settings.png deleted file mode 100644 index 320183474..000000000 Binary files a/luci-app-gpoint-main/Images/settings.png and /dev/null differ diff --git a/luci-app-gpoint-main/LICENSE b/luci-app-gpoint-main/LICENSE deleted file mode 100644 index f288702d2..000000000 --- a/luci-app-gpoint-main/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/luci-app-gpoint-main/Makefile b/luci-app-gpoint-main/Makefile deleted file mode 100644 index 6accd6e1e..000000000 --- a/luci-app-gpoint-main/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=GNSS Information dashboard for 3G/LTE dongle -LUCI_DEPENDS:=+lua +curl +lua-rs232 +luasocket +iwinfo +libiwinfo-lua +lua-bit32 -PKG_LICENSE:=GPLv3 -PKG_VERSION:=1.6.0 - -define Package/luci-app-gpoint/conffiles - /etc/config/gpoint -endef - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-gpoint-main/README.md b/luci-app-gpoint-main/README.md deleted file mode 100644 index 2c2fc338f..000000000 --- a/luci-app-gpoint-main/README.md +++ /dev/null @@ -1,45 +0,0 @@ -

- Gpoint -
Global Navigation Satellite System for OpenWrt LuCi
-

-

Gpoint was created in order to use full set of functions of mobile modules installed in OpenWRT router. -Manufacturers of GSM/3G/LTE modems often lay down GNSS function, so why not use it? -It doesn't matter if you use a router in transport or it is installed in your terminal, you can always find out its location!

-
- Screenshots - overview_wait - overview - overview -
- -## Features -- Support: GPS, GLONASS (works with "NMEA 0183" standard protocol) -- GeoHash (reduces drift of GPS\GLONASS coordinate readings in parking) -- [Kalman filter](https://github.com/lacker/ikalman) (Implementation of Kalman filter for geo (gps) tracks. This is a Lua port of original C code) -- Yandex Locator [API](https://yandex.ru/dev/locator/) (Determines location by nearest Wi-Fi access points) -- Server side (sends GNSS data to a remote server) -- Support [OpenLayers](https://openlayers.org/) maps in UI, and much more! - -## Supported devices -- Dell DW5821e/DW5829e -- Quectel EC25/EP06/EM12/RM500Q -- Sierra EM7455/EM7565 -- Simcom SIM7600E-H -- U-Blox VK-172 GPS/GLONASS module (u-blox 7 GNSS modules) - - -## Supported GNSS protocols -- [OsmAnd](https://www.traccar.org/osmand/) -- [Wialon IPS](https://gurtam.com/ru/gps-hardware/soft/wialon-ips) - -## Install -- Upload ipk file to tmp folder -- cd /tmp -- opkg update -- opkg install luci-app-gpoint_1.7.0_all.ipk - -## Uninstall -- opkg remove luci-app-gpoint - -## License -Gpoint like OpenWRT is released under the GPL v3.0 License - see detailed [LICENSE](https://github.com/Kodo-kakaku/luci-app-gpoint/blob/main/LICENSE). diff --git a/luci-app-gpoint-main/htdocs/luci-static/resources/icons/gpoint_icons/marker.png b/luci-app-gpoint-main/htdocs/luci-static/resources/icons/gpoint_icons/marker.png deleted file mode 100644 index 950edf246..000000000 Binary files a/luci-app-gpoint-main/htdocs/luci-static/resources/icons/gpoint_icons/marker.png and /dev/null differ diff --git a/luci-app-gpoint-main/htdocs/luci-static/resources/icons/gpoint_icons/spiner.gif b/luci-app-gpoint-main/htdocs/luci-static/resources/icons/gpoint_icons/spiner.gif deleted file mode 100644 index c78a08281..000000000 Binary files a/luci-app-gpoint-main/htdocs/luci-static/resources/icons/gpoint_icons/spiner.gif and /dev/null differ diff --git a/luci-app-gpoint-main/luasrc/controller/gpoint/gpoint.lua b/luci-app-gpoint-main/luasrc/controller/gpoint/gpoint.lua deleted file mode 100644 index a16f77adf..000000000 --- a/luci-app-gpoint-main/luasrc/controller/gpoint/gpoint.lua +++ /dev/null @@ -1,86 +0,0 @@ -------------------------------------------------------------- --- luci-app-gpoint. Gnss information dashboard for 3G/LTE dongle. -------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -local ubus = require("ubus") -local uci = require("luci.model.uci") -local json = require("luci.jsonc") - -module("luci.controller.gpoint.gpoint", package.seeall) - -function index() - entry({"admin", "services", "gpoint"}, alias ("admin","services", "gpoint", "map"), translate("GPoint"), 10).acl_depends={"unauthenticated"} - entry({"admin", "services", "gpoint", "map"}, template("gpoint/overview"), translate("Overview"), 51).acl_depends={"unauthenticated"} - entry({"admin", "services", "gpoint", "settings"}, cbi("gpoint/gpoint"), translate("Settings"), 52).acl_depends={"unauthenticated"} - entry({"admin", "services", "gpoint", "action"}, call("gpoint_action"), nil).leaf = true - entry({"admin", "services", "gpoint", "geopoint"}, call("get_geopoint"), nil).leaf = true - entry({"admin", "services", "gpoint", "blackbox"}, call("get_blackbox"), nil).leaf = true -end - -local serviceIsStop = { - warning={ - app={true,"Service stop"}, - server={true,"Service stop"}, - filter={true,"Service stop"}, - locator={true,"Service stop"}, - kalman={true,"Service stop"} - } -} - -local serviceUbusFailed = { - warning={ - app={true,"Ubus Failed"}, - server={true,"Loading..."}, - filter={true,"Loading..."}, - locator={true,"Loading..."}, - kalman ={true, "Loading..."} - } -} - --- Overview JSON request -function get_geopoint() - local sessionId = uci:get("gpoint", "service_settings", "sessionid") - luci.http.prepare_content("application/json") - local data - if sessionId == "stop" then - data = json.stringify(serviceIsStop) - else - local conn = ubus.connect() - if conn then - local resp = conn:call("session", "list", {ubus_rpc_session = sessionId}) - data = json.stringify(resp.data) - conn:close() - else - data = json.stringify(serviceUbusFailed) - end - - end - luci.http.write(data) -end - --- BlackBox JSON request -function get_blackbox() - local data = luci.sys.exec("cat /usr/share/gpoint/tmp/blackbox.json") - luci.http.prepare_content("application/json") - luci.http.write(data) -end - --- Settings init.d service -function gpoint_action(name) - local packageName = "gpoint" - if name == "start" then - luci.sys.init.start(packageName) - elseif name == "action" then - luci.util.exec("/etc/init.d/" .. packageName .. " reload") - elseif name == "stop" then - luci.sys.init.stop(packageName) - elseif name == "enable" then - luci.sys.init.enable(packageName) - elseif name == "disable" then - luci.sys.init.disable(packageName) - end - luci.http.prepare_content("text/plain") - luci.http.write("0") -end diff --git a/luci-app-gpoint-main/luasrc/model/cbi/gpoint/gpoint.lua b/luci-app-gpoint-main/luasrc/model/cbi/gpoint/gpoint.lua deleted file mode 100644 index c262b8958..000000000 --- a/luci-app-gpoint-main/luasrc/model/cbi/gpoint/gpoint.lua +++ /dev/null @@ -1,252 +0,0 @@ -------------------------------------------------------------- --- luci-app-gpoint. Gnss information dashboard for 3G/LTE dongle. -------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -local fs = require("nixio.fs") -local sys = require("luci.sys") -local util = require("luci.util") -local json = require("luci.jsonc") - - -local packageName = "gpoint" -local helperText = "" -local tmpfsStatus, tmpfsStatusCode -local ubusStatus = util.ubus("service", "list", { name = packageName }) -local lsusb = sys.exec("lsusb") -local device_port = fs.glob("/dev/tty[A-Z][A-Z]*") - -local timezone = { - {'Autodetect (experimental)','auto'},{'Etc/GMT', '0' },{ 'Etc/GMT+1', '1' },{ 'Etc/GMT+10', '10'}, - { 'Etc/GMT+11', '11'},{ 'Etc/GMT+12', '12'},{ 'Etc/GMT+2', '2' },{ 'Etc/GMT+3', '3' }, - { 'Etc/GMT+4', '4' },{ 'Etc/GMT+5', '5' },{ 'Etc/GMT+6', '6' },{ 'Etc/GMT+7', '7' }, - { 'Etc/GMT+8', '8' },{ 'Etc/GMT+9', '9' },{ 'Etc/GMT-1', '-1' },{ 'Etc/GMT-10', '-10'}, - { 'Etc/GMT-11', '-11'},{ 'Etc/GMT-12', '-12'},{ 'Etc/GMT-13', '-13'},{ 'Etc/GMT-14', '-14'}, - { 'Etc/GMT-2', '-2' },{ 'Etc/GMT-3', '-3' },{ 'Etc/GMT-4', '-4' },{ 'Etc/GMT-5', '-5' }, - { 'Etc/GMT-6', '-6' },{ 'Etc/GMT-7', '-7' },{ 'Etc/GMT-8', '-8' },{ 'Etc/GMT-9', '-9' } -} - -local modems = { - ["Quectel"] = { - ["2c7c:0306"] = "EP06", - ["2c7c:0512"] = "EM12", - ["2c7c:0125"] = "EC25", - ["2c7c:0800"] = "RM500Q" - }, - ["Sierra"] = { - ["1199:9071"] = "EM7455", - ["1199:9091"] = "EM7565" - }, - ["U-Blox"] = { - ["1546:01a7"] = "VK-172" - }, - ["Simcom"] = { - ["1e0e:9001"] = "SIM7600E-H" - }, - ["Dell"] = { - ["413c:81d7"] = "DW5821e", - ["413c:81e6"] = "DW5829e" - } - -} - -local m = Map("gpoint", translate("")) - --- Service -local s = m:section(TypedSection, "modem_settings", translate("Service")) -s.anonymous = true -s.addremove = false - -local o = s:option(DummyValue, "_dummy") -o.template = packageName .. "/buttons" - -o = s:option(DummyValue, "_dummy", translate("Service Status:")) -o.template = packageName .. "/service_status" - - --- Modem -s = m:section(TypedSection, "modem_settings", translate("Modem"), translate("Select the modem(s) to find the location")) -s.anonymous = true -s.addremove = false - -local no_device = true -o = s:option(ListValue, "modem", translate("Modem(s):")) -if lsusb then - for modem_name, modem_data in pairs(modems) do - for id, modem in pairs(modem_data) do - if string.find(lsusb, id) then - no_device = false - o:value(modem_name .. '_' .. modem, modem_name .. ' ' .. modem) - end - end - end -end - -if no_device then - o:value('mnf', translate("-- Modems not found --")) -end - -o = s:option(ListValue, "port", translate("Modem port:"), translate("Select the NMEA port of the device.")) -if no_device then - o:value('pnf', translate("-- disable --")) - o = s:option( DummyValue, "nfound") - function o.cfgvalue(self, section) - local nfound = "
No modem(s) found! Check the modem connections.
\ -
Supported modems: " - for modem_name, modem_data in pairs(modems) do - nfound = nfound .. "
" .. modem_name .. ' ' - for _, modem in pairs(modem_data) do - nfound = nfound .. modem .. ", " - end - nfound = nfound:sub(1, -3) - end - nfound = nfound .. "
" - return translate(nfound) - end - o.rawhtml = true -else - if device_port then - for node in device_port do - o:value(node, node) - end - end -end - --- Add TimeZone -o = s:option(ListValue, "timezone", translate("Timezone:")) -for _, zone in pairs(timezone) do - o:value(zone[2], zone[1]) -end - - --- Remote Server -s = m:section(TypedSection, "server_settings", translate("Remote Server"), translate("Configuration of the remote navigation server")) -s.addremove = false -s.anonymous = true - -o = s:option(Flag, "server_enable", translate("Enable server:"), translate("Enabling Remote Server service")) - -o = s:option(ListValue, "proto", translate(" "), translate("Navigation data transmission protocol")) -o.widget = "radio" -o:value("traccar", " Traccar Client") -- Key and value pairs -o:value("wialon", " Wialon IPS") -o.default = "trackcar" - -o = s:option(Value, "server_frequency", translate("Frequency:"), translate("Frequency of sending data to the Remote Server")) -o.placeholder = "In seconds" -o.datatype = "range(5, 600)" - -o = s:option(Value, "server_ip", translate("Address:")) -o.datatype = "host" -o.placeholder = '172.0.0.1' - -o = s:option(Value, "server_port", translate("Port:")) -o.datatype = "port" -o.placeholder = '80' - -o = s:option(Value, "server_login", translate("Login:")) -o.placeholder = "Device login (ID)" - -o = s:option(Value, "server_password", translate("Password:"), translate("If you don't use Password, leave the field empty")) -o.password = true -o.placeholder = "Device password" - -o = s:option(Flag, "blackbox_enable", translate("BlackBox enable:"), - translate("Blackbox makes it possible to record and store data even in the absence of a cellular signal")) -o:depends("proto","wialon") - -o = s:option(Flag, "blackbox_cycle", translate("BlackBox cycle:"), translate("Cyclic overwriting of data stored in the BlackBox")) -o:depends("proto", "wialon") - -o = s:option(Value, "blackbox_max_size", translate("BlackBox size:"), translate("Number of sentences in the BlackBox")) -o.placeholder = "default: 1000 sentence" -o.datatype = "range(1000, 5000)" -o:depends("proto","wialon") - -o = s:option(DummyValue, "_dummy", translate(" ")) -o.template = packageName .. "/blackbox" -o:depends("proto","wialon") - -o = s:option(Button, "clear", translate("Clear BlackBox"), translate("Warning! After clearing the BlackBox, GNSS data will be destroyed!")) -o.inputstyle = "remove" -o:depends("proto", "wialon") -function o.write(self, section) - local file = io.open("/usr/share/gpoint/tmp/blackbox.json", 'w') - file:write(json.stringify({["size"]=0,["max"]=1000,["data"]={}})) - file:close() -end - - --- Tab menu settings -s = m:section(TypedSection, "service_settings") -s.addremove = false -s.anonymous = true - - ----------------------------------------------------------------------------------------------------------------- -s:tab("ya", translate("Yandex Locator"), translate("Determines the location of the mobile \ - device by the nearest Wi-Fi access points and \ - cellular base stations — without using satellite navigation systems.")) -s:tab("gpoint_filter", translate("GeoHash Filter"), translate("Filters \"DRIFT\" and \"JUMPS\" of navigation 3G/LTE dongles")) -s:tab("kalman", translate("Kalman Filter"), translate("Designed to make the route smoother. Removes \"jumps\" of navigation 3G/LTE dongles")) - ----------------------------------------------------------------------------------------------------------------- - --- API Yandex locator -o = s:taboption("ya", Flag, "ya_enable", translate("Enable:"), translate("Enabling the Yandex locator")) -o.optional = true - -o = s:taboption("ya", ListValue, "ya_wifi", translate("Interface:"), translate("Select the Wi-Fi interface for Yandex locator")) -local iwinfo = sys.exec("iwinfo") -no_device = true -for device in string.gmatch(iwinfo, "(%S+)(%s%s%s%s%s)(%S+)") do - o:value(device, device) - no_device = false -end - -if no_device then - o:value('wnf', translate("-- Wifi not found --")) -end - -o = s:taboption("ya", Value, "ya_key", translate("API Key:"), translate("To work with the Yandex locator must use an API key")) -o.password = true -o.placeholder = "Yandex API key" - -o = s:taboption("ya", DummyValue, "ya_href") - function o.cfgvalue(self, section) - local h = "Get Yandex API key" - return translate(h) - end -o.rawhtml = true - --- GeoHash -o = s:taboption("gpoint_filter", Flag, "filter_enable", translate("Enable:"), translate("Enabling GpointFilter")) -o.optional = true - -o = s:taboption("gpoint_filter", Value, "filter_changes", translate("Jump:"), translate("Registration of the \"jump\" coordinates. \ - The coordinate is recognized as valid after the modem has received it more than the specified number of times.")) -o.placeholder = "" -o.datatype = "range(2, 6)" - -o = s:taboption("gpoint_filter", ListValue, "filter_hash", translate("Area:"), translate("The longer the hash length,\ - the smaller the area and the greater the accuracy of the coordinates in one area.")) -o.optional = true -o.default = 7 -for i = 1, 12 do - o:value(i, i) -end -o = s:taboption("gpoint_filter", Value, "filter_speed", translate("Speed:"), translate("Above the specified speed, the filter will be disabled")) -o.placeholder = "default 2 km/h" -o.datatype = "range(0, 150)" - --- Kalman -o = s:taboption("kalman", Flag, "kalman_enable", translate("Enable:"), translate("Enabling KalmanFilter")) -o.optional = true -o = s:taboption("kalman", Value, "kalman_noise", translate("Noise:"), translate("Noise is a parameter you can use to alter the expected noise.\ - 1.0 is the original, and the higher it is, the more a path will be \"smoothed\"")) -o.placeholder = "" -o.datatype = "range(1.0, 30.0)" - - -return m diff --git a/luci-app-gpoint-main/luasrc/view/gpoint/blackbox.htm b/luci-app-gpoint-main/luasrc/view/gpoint/blackbox.htm deleted file mode 100644 index 6723fb936..000000000 --- a/luci-app-gpoint-main/luasrc/view/gpoint/blackbox.htm +++ /dev/null @@ -1,33 +0,0 @@ -<%# - Module for providing data from a mobile satellite navigation system ( mobile modems, etc.) - -= Design and Development 2021-2022 =- - Licensed to the public under the Apache License 2.0. --%> - -<%+cbi/valueheader%> - -
- - - -<%+cbi/valuefooter%> diff --git a/luci-app-gpoint-main/luasrc/view/gpoint/buttons.htm b/luci-app-gpoint-main/luasrc/view/gpoint/buttons.htm deleted file mode 100644 index 62c2e8e61..000000000 --- a/luci-app-gpoint-main/luasrc/view/gpoint/buttons.htm +++ /dev/null @@ -1,81 +0,0 @@ -<%# - Module for providing data from a mobile satellite navigation system ( mobile modems, etc.) - -= Design and Development 2021-2022 =- - Licensed to the public under the Apache License 2.0. --%> - -<%+gpoint/css/style%> -<%+gpoint/service%> - -<%- - local packageName = "gpoint" - local serviceRunning, serviceEnabled = false, false; - - serviceEnabled = luci.sys.init.enabled(packageName) - local ubusStatus = luci.util.ubus("service", "list", { name = packageName }) - if ubusStatus and ubusStatus[packageName] then - serviceRunning = true - end - - if serviceEnabled then - btn_start_status = true - btn_action_status = true - btn_stop_status = true - btn_enable_status = false - btn_disable_status = true - else - btn_start_status = false - btn_action_status = false - btn_stop_status = false - btn_enable_status = true - btn_disable_status = false - end - if serviceRunning then - btn_start_status = false - btn_action_status = true - btn_stop_status = true - else - btn_action_status = false - btn_stop_status = false - end --%> - -
-
- - - - - - -   -   -   -   - - - - -
-
- -<%-if not btn_start_status then%> - -<%-end%> -<%-if not btn_action_status then%> - -<%-end%> -<%-if not btn_stop_status then%> - -<%-end%> -<%-if not btn_enable_status then%> - -<%-end%> -<%-if not btn_disable_status then%> - -<%-end%> diff --git a/luci-app-gpoint-main/luasrc/view/gpoint/css/style.htm b/luci-app-gpoint-main/luasrc/view/gpoint/css/style.htm deleted file mode 100644 index c6b8ea961..000000000 --- a/luci-app-gpoint-main/luasrc/view/gpoint/css/style.htm +++ /dev/null @@ -1,26 +0,0 @@ - diff --git a/luci-app-gpoint-main/luasrc/view/gpoint/js/js.htm b/luci-app-gpoint-main/luasrc/view/gpoint/js/js.htm deleted file mode 100644 index 4f917e63d..000000000 --- a/luci-app-gpoint-main/luasrc/view/gpoint/js/js.htm +++ /dev/null @@ -1,183 +0,0 @@ -<%# - Module for providing data from a mobile satellite navigation system ( mobile modems, etc.) - -= Design and Development 2021-2022 =- - Licensed to the public under the Apache License 2.0. --%> - - diff --git a/luci-app-gpoint-main/luasrc/view/gpoint/overview.htm b/luci-app-gpoint-main/luasrc/view/gpoint/overview.htm deleted file mode 100644 index 4b0e49f84..000000000 --- a/luci-app-gpoint-main/luasrc/view/gpoint/overview.htm +++ /dev/null @@ -1,140 +0,0 @@ -<%# - Module for providing data from a mobile satellite navigation system ( mobile modems, etc.) - -= Design and Development 2021-2022 =- - Licensed to the public under the Apache License 2.0. --%> - -<%+gpoint/css/style%> - -<%+header%> - - - -

-
GPoint: Router Location - -
-

- -
-
-
-
-
- -
-

<%:Details:%>

-
- - - - - - - - - - - - - - - - - - - - - - - - - -
<%:Longitude:%>-<%:Latitude:%>-<%:Altitude:%>-
<%:Time (UTC):%>-<%:Date:%>-<%:Satellites:%>-
<%:Hdop:%>-<%:Course:%>-<%:Speed:%>-
-
-
- - -<%+gpoint/js/js%> - -<%+footer%> diff --git a/luci-app-gpoint-main/luasrc/view/gpoint/service.htm b/luci-app-gpoint-main/luasrc/view/gpoint/service.htm deleted file mode 100644 index d1a9f606d..000000000 --- a/luci-app-gpoint-main/luasrc/view/gpoint/service.htm +++ /dev/null @@ -1,65 +0,0 @@ -<%# - Module for providing data from a mobile satellite navigation system ( mobile modems, etc.) - -= Design and Development 2021-2022 =- - Licensed to the public under the Apache License 2.0. --%> - - diff --git a/luci-app-gpoint-main/luasrc/view/gpoint/service_status.htm b/luci-app-gpoint-main/luasrc/view/gpoint/service_status.htm deleted file mode 100644 index f985697c9..000000000 --- a/luci-app-gpoint-main/luasrc/view/gpoint/service_status.htm +++ /dev/null @@ -1,83 +0,0 @@ -<%# - Module for providing data from a mobile satellite navigation system ( mobile modems, etc.) - -= Design and Development 2021-2022 =- - Licensed to the public under the Apache License 2.0. --%> - -<%+cbi/valueheader%> - - - - - - - - - - - - - - - - - - - - - - - - -
-
Application: -
Remote Server: -
Yandex Locator: -
GpointFilter: -
KalmanFilter: -
- - - -<%+cbi/valuefooter%> diff --git a/luci-app-gpoint-main/root/etc/config/gpoint b/luci-app-gpoint-main/root/etc/config/gpoint deleted file mode 100644 index 07f712714..000000000 --- a/luci-app-gpoint-main/root/etc/config/gpoint +++ /dev/null @@ -1,5 +0,0 @@ -config modem_settings 'modem_settings' - -config server_settings 'server_settings' - -config service_settings 'service_settings' diff --git a/luci-app-gpoint-main/root/etc/init.d/gpoint b/luci-app-gpoint-main/root/etc/init.d/gpoint deleted file mode 100644 index 15322ff85..000000000 --- a/luci-app-gpoint-main/root/etc/init.d/gpoint +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright 2021-2022 Vladislav Kadulin {spanky@yandex.ru} - -USE_PROCD=1 -START=95 -STOP=01 - -CONFIGURATION=gpoint - -start_service() { - config_load "${CONFIGURATION}" - procd_open_instance - procd_append_param command /usr/share/gpoint/gpoint - procd_set_param respawn - procd_set_param stdout 1 - procd_set_param stderr 1 - procd_set_param pidfile /var/run/gpoint.pid - procd_close_instance - echo "gpoint service start" -} - -stop_service() { - if [ -f /var/run/gpoint.pid ]; then - sessionId=$(uci get gpoint.service_settings.sessionid) - uci set gpoint.service_settings.sessionid=stop - uci commit gpoint - ubus call session destroy "{\"ubus_rpc_session\":\"${sessionId}\"}" - echo "gpoint service stop" - else - echo "gpoint not running" - fi -} diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/gpoint b/luci-app-gpoint-main/root/usr/share/gpoint/gpoint deleted file mode 100644 index 9961fd7f5..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/gpoint +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env lua -------------------------------------------------------------- --- luci-app-gpoint. Gnss information dashboard for 3G/LTE dongle. -------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -common_path = "/usr/share/gpoint/modems/?.lua;/usr/share/gpoint/lib/?.lua;/usr/share/gpoint/proto/?.lua;/usr/share/gpoint/lib/kalman_filter/?.lua;" -package.path = common_path .. package.path - -local config = require("config") -local socket = require("socket") -local nixio = require("nixio.fs") -local ubus = require("ubus") - - -function portActive(port) - local fport = nixio.glob("/dev/tty[A-Z][A-Z]*") - for p in fport do - if string.find(p, port) then - return true, {warning = {app = {false, "OK"}}} - end - end - return false, {warning = { - app = {true, "Port is unavailable. Check the modem connections!"}, - locator = {}, - server = {} - } - } -end - --------------------------------------------------------------------------------- --- all warnings: [1]-true/false, [2]-what err --- initializing modem --------------------------------------------------------------------------------- -local modemVendor = "" -local modemStatus, modemConfig = config.getModemData() -if not modemStatus[1] then - if string.find(modemConfig.name, "Quectel") then - modemVendor = require("que") - elseif string.find(modemConfig.name, "Sierra") then - modemVendor = require("sierra") - elseif string.find(modemConfig.name, "U-Blox") then - modemVendor = require("ublox") - elseif string.find(modemConfig.name, "Simcom") then - modemVendor = require("simcom") - elseif string.find(modemConfig.name, "Dell") then - modemVendor = require("dell") - end -end --------------------------------------------------------------------------------- --- initializing Remote Server, Remote Server frequency update time --------------------------------------------------------------------------------- -local gnssProtocol, frequencyDataSend = "", nil -local serverStatus, serverConfig = config.getServerData() -if not serverStatus[1] then - if serverConfig.protocol == "wialon" then - gnssProtocol = require("wialon_ips") - elseif serverConfig.protocol == "traccar" then - gnssProtocol = require("traccar") - end - frequencyDataSend = os.time() + serverConfig.frequency -end --------------------------------------------------------------------------------- --- initializing Yandex Locator --------------------------------------------------------------------------------- -local locator = "" -local locatorGPSmiss = 0 -local locatorStatus, locatorConfig = config.getLoctorData() -if not locatorStatus[1] then - locator = require("locator") -end --------------------------------------------------------------------------------- --- Filter coorinate GeoHash Filter --------------------------------------------------------------------------------- -local FilterGNSS = "" -local FilterGNSSdata = { - gp = { longitude = "", latitude = "" }, - gga = { longitude = "", latitude = "" }, - gns = { longitude = "", latitude = "" }, - coordHash = 0, - changesSize = 0, - empty = true -} - -local filterStatus, filterConfig = config.getFilterData() -if not filterStatus[1] then - FilterGNSS = require("geohash") -else - FilterGNSS, FilterGNSSdata = nil, nil -end --------------------------------------------------------------------------------- --- Filter coorinate KalmanFilter --------------------------------------------------------------------------------- -local kalman = {} -local kalmanFilter = "" -local kalmanIsStop = true; -local secondsSinceLastUpdate = os.time() - -local kalmanStatus, kalmanConfig = config.getKalmanData() -if not kalmanStatus[1] then - kalmanFilter = require("gps_lib") -else - kalman,kalmanFilter,kalmanIsStop,secondsSinceLastUpdate = nil, nil, nil, nil -end --------------------------------------------------------------------------------- --- Config Ubus --------------------------------------------------------------------------------- -local serviceIsStart = {warning={app={true,"Service start"},locator={true,"Loading..."},server={true,"Loading..."}}} -local conn = ubus.connect() -if not conn then - error("Failed to connect to ubus") -end - -local createUbusSession = conn:call("session", "create", {timeout = 0}) -local ubusSessionId = createUbusSession.ubus_rpc_session -config.setUbusSessionId(ubusSessionId) -conn:call("session", "set", {ubus_rpc_session = ubusSessionId, values = serviceIsStart}) -serviceIsStart = nil -conn:close() --------------------------------------------------------------------------------- - -local timeToUpdateGNSSdata = 3 - -while true do - -- modem GNSS data - local portStatus, GnssData = portActive(modemConfig.port) - if portStatus then - GnssData = modemVendor.getGNSSdata(modemConfig.port) - if GnssData.warning.app[1] then - modemVendor.start(modemConfig.port) - end - end - - -- yandex locator - GnssData.warning.locator = locatorStatus - if portStatus and not locatorStatus[1] then - if GnssData.gp.longitude == "-" and GnssData.gp.latitude == "-" then - if locatorGPSmiss >= 3 then - local err, latitude, longitude = locator.getLocation(locatorConfig.iface, locatorConfig.key) - GnssData.warning.locator = err[1] and err or {false, "Data received from locator..."} - if not GnssData.warning.locator[1] then - GnssData.gp.latitude = latitude - GnssData.gp.longitude = longitude - GnssData.gp.date = os.date("%d.%m.%Y") - GnssData.gp.utc = os.date("%H:%M", os.time(os.date("!*t"))) -- TODO time + UTF(+3) - GnssData.gga.latitude = locator.degreesToNmea(latitude) - GnssData.gga.longitude = locator.degreesToNmea(longitude) - end - else - GnssData.warning.locator = {true, "getting navigation data..."} - locatorGPSmiss = 1 + locatorGPSmiss - end - else - locatorGPSmiss = 0 - end - end - - -- drift GpointFilter - GnssData.warning.filter = filterStatus - if portStatus and not GnssData.warning.filter[1] then - if not GnssData.warning.gga[1] or not GnssData.warning.gns[1] and GnssData.warning.locator[2] == "OK" then - if GnssData.gp.spkm ~= '-' and tonumber(GnssData.gp.spkm) < filterConfig.speed then - - local tmpHash = FilterGNSS.encode(GnssData.gp.latitude, GnssData.gp.longitude, filterConfig.hash) - - if not FilterGNSSdata.empty and tmpHash == FilterGNSSdata.coordHash and FilterGNSSdata.changesSize < filterConfig.changes then - FilterGNSSdata.changesSize = 0 - GnssData.gp.latitude, GnssData.gp.longitude = FilterGNSSdata.gp.latitude, FilterGNSSdata.gp.longitude - GnssData.gga.latitude, GnssData.gga.longitude = FilterGNSSdata.gga.latitude, FilterGNSSdata.gga.longitude - GnssData.gns.latitude, GnssData.gns.longitude = FilterGNSSdata.gns.latitude, FilterGNSSdata.gns.longitude - - elseif FilterGNSSdata.changesSize >= filterConfig.changes or FilterGNSSdata.empty then - FilterGNSSdata.gp.latitude, FilterGNSSdata.gp.longitude = GnssData.gp.latitude, GnssData.gp.longitude - if not GnssData.warning.gga[1] then - FilterGNSSdata.gga.latitude, FilterGNSSdata.gga.longitude = GnssData.gga.latitude, GnssData.gga.longitude - end - if not GnssData.warning.gns[1] then - FilterGNSSdata.gns.latitude, FilterGNSSdata.gns.longitude = GnssData.gns.latitude, GnssData.gns.longitude - end - FilterGNSSdata.changesSize, FilterGNSSdata.empty, FilterGNSSdata.coordHash = 0, false, tmpHash - else - FilterGNSSdata.changesSize = FilterGNSSdata.changesSize + 1 - end - else - FilterGNSSdata.changesSize, FilterGNSSdata.empty = 0, true - end - end - end - - - -- KalmanFilter - -- TODO enabling and disabling in parking lot - GnssData.warning.kalman = kalmanStatus - if portStatus and not GnssData.warning.kalman[1] then - if not GnssData.warning.gga[1] or not GnssData.warning.gns[1] and GnssData.warning.locator[2] == "OK" then - if kalmanIsStop then - kalman = kalmanFilter.create_velocity2d(kalmanConfig.noise) - kalmanIsStop = false - end - kalman = kalmanFilter.update_velocity2d(kalman, GnssData.gp.latitude, GnssData.gp.longitude, os.time() - secondsSinceLastUpdate) - GnssData.gp.latitude, GnssData.gp.longitude = kalmanFilter.get_lat_lon(kalman) - GnssData.gga.latitude, GnssData.gga.longitude = locator.degreesToNmea(GnssData.gp.latitude), ('0' .. locator.degreesToNmea(GnssData.gp.longitude)) - GnssData.gns.latitude, GnssData.gns.longitude = GnssData.gga.latitude, GnssData.gga.longitude - else - kalmanIsStop = true - end - end - - -- remote server - -- Filter locator to access send data to server - GnssData.warning.server = serverStatus - if locatorGPSmiss == 0 or locatorGPSmiss >= 3 then - if portStatus and not serverStatus[1] and os.time() >= frequencyDataSend then - frequencyDataSend = os.time() + (serverConfig.frequency - timeToUpdateGNSSdata) - GnssData.warning.server = gnssProtocol.sendData(GnssData, serverConfig) - end - end - - -- ubus send json data in session - conn = ubus.connect() - if conn then - conn:call("session", "set", {ubus_rpc_session = ubusSessionId, values = GnssData}) - conn:close() - end - - -- update NMEA coordinate time - socket.sleep((locatorGPSmiss == 0 or locatorGPSmiss >= 3) and timeToUpdateGNSSdata or 1) -end diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/lib/checksum.lua b/luci-app-gpoint-main/root/usr/share/gpoint/lib/checksum.lua deleted file mode 100644 index 6efb81744..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/lib/checksum.lua +++ /dev/null @@ -1,95 +0,0 @@ -------------------------------------------------------------------- --- This module is designed to receive a checksum of GNSS messages, --- Such as crc8 and crc16 checksum. -------------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -checksum = {} - -local function decimalToHex(num) - if num == 0 then - return '0' - end - local neg = false - if num < 0 then - neg = true - num = num * -1 - end - local hexstr = "0123456789ABCDEF" - local result = "" - while num > 0 do - local n = math.mod(num, 16) - result = string.sub(hexstr, n + 1, n + 1) .. result - num = math.floor(num / 16) - end - if neg then - result = '-' .. result - end - return result -end - -local function BitXOR(a, b) - local p, c = 1, 0 - while a > 0 and b > 0 do - local ra, rb = a % 2, b % 2 - if ra ~= rb then c = c + p end - a, b, p = (a - ra) / 2, (b - rb) / 2, p * 2 - end - - if a < b then a = b end - while a > 0 do - local ra = a % 2 - if ra > 0 then c = c + p end - a, p = (a - ra) / 2, p * 2 - end - return c -end - -local function BitAND(a, b) - local p, c = 1,0 - while a > 0 and b > 0 do - local ra, rb = a%2, b%2 - if ra + rb > 1 then c = c + p end - a, b, p = (a - ra) / 2, (b - rb) / 2, p*2 - end - return c -end - -local function rshift(x, by) - return math.floor(x / 2 ^ by) -end - - --- Checksum for NMEA data (CRC8) -function checksum.crc8(data) - local crc8 = string.sub(data, #data - 1) - data = string.sub(data, 2, #data - 3) - - local b_sum = string.byte(data, 1) - for i = 2, #data do - b_sum = BitXOR(b_sum, string.byte(data, i)) - end - - return decimalToHex(b_sum) == crc8 and true or false -end - --- Checksum for Wialone IPS (CRC16) -function checksum.crc16(s) - assert(type(s) == 'string') - local crc16 = 0x0000 - for i = 1, #s do - local c = s:byte(i) - crc16 = BitXOR(crc16, c) - for j = 1, 8 do - local k = BitAND(crc16, 1) - crc16 = rshift(crc16, 1) - if k ~= 0 then - crc16 = BitXOR(crc16, 0xA001) - end - end - end - return decimalToHex(crc16) -end - -return checksum diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/lib/config.lua b/luci-app-gpoint-main/root/usr/share/gpoint/lib/config.lua deleted file mode 100644 index 86c1fcc8e..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/lib/config.lua +++ /dev/null @@ -1,225 +0,0 @@ -------------------------------------------------------------------- --- Module is used for point configuration and interaction with the UI -------------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -local uci = require("luci.model.uci") -local sys = require("luci.sys") - -config = {} - -local CFG = uci:get_all("gpoint") - --- Status table -local STATUS = { - APP = { - MODEM_OK = {false, "OK"}, - MODEM_ERROR = {true, "Modem error. Select modem in the settings!"}, - PORT_ERROR = {true, "Modem Port error. Select port in the settings!"} - }, - SERVER = { - SERVICE_ON = {false, "OK"}, - SERVICE_OFF = {true, "OFF"}, - IP_ERROR = {true, "Server address error. Enter the server address!"}, - PORT_ERROR = {true, "Server port error. Set the server port!"}, - LOGIN_ERROR = {true, "Login (ID) error. Specify the device login!"} - }, - LOCATOR = { - SERVICE_ON = {false, "OK"}, - SERVICE_OFF = {true, "OFF"}, - API_KEY_ERROR = {true, "Yandex Locator: API key not found!"}, - WIFI_IFACE_ERROR = {true, "Yandex Locator: Wi-Fi interface not found!"} - }, - FILTER = { - SERVICE_ON = {false, "OK"}, - SERVICE_OFF = {true, "OFF"} - } -} - ------------------------------------------------------------------------------------ --- APP (Modem Settings) - -- 1.Checking the configuration for the presence of the modem name - -- 2.Checking the presence of the port in the configuration and whether - -- it is in the list of devices, if the device is unavailable, we return a warning - -- 3. return err + modem data (name modem and NMEA port modem) ------------------------------------------------------------------------------------ -function config.getModemData() - - local err = {} - local modem = { - name = "-", - port = "-" - } - - if not CFG.modem_settings.modem and CFG.modem_settings.modem == "mnf" then - err = STATUS.APP.MODEM_ERROR - elseif CFG.modem_settings.port and CFG.modem_settings.port == "pnf" then - err = STATUS.APP.PORT_ERROR - else - err = STATUS.APP.MODEM_OK - end - - if not err[1] then - modem.name = CFG.modem_settings.modem - modem.port = CFG.modem_settings.port - end - return err, modem -end - ------------------------------------------------------------------------------------ --- Remote Server - -- 1.We check whether the server service is enabled or not. - -- 2.The correctness of the completed forms is checked such as address, login, port, etc ... - -- 3.We return the absence of an error and the server configuration data otherwise an error, nil ... ------------------------------------------------------------------------------------ -function config.getServerData() - - local err = {} - local server = { - address = "", - port = "", - protocol = "", - login = "", - password = "", - frequency = "", - blackbox = { - enable = "", - cycle = "", - size = 0 - } - } - - if not CFG.server_settings.server_enable then - err = STATUS.SERVER.SERVICE_OFF - elseif not CFG.server_settings.server_ip then - err = STATUS.SERVER.IP_ERROR - elseif not CFG.server_settings.server_port then - err = STATUS.SERVER.PORT_ERROR - elseif not CFG.server_settings.server_login then - err = STATUS.SERVER.LOGIN_ERROR - else - err = STATUS.SERVER.SERVICE_ON - end - - if not err[1] then - server.address = CFG.server_settings.server_ip - server.port = CFG.server_settings.server_port - server.protocol = CFG.server_settings.proto - server.login = CFG.server_settings.server_login - - if server.protocol == "wialon" then - server.password = CFG.server_settings.server_password or "NA" - server.frequency = CFG.server_settings.server_frequency or 5 - server.blackbox.enable = CFG.server_settings.blackbox_enable and true or false - server.blackbox.cycle = CFG.server_settings.blackbox_cycle and true or false - server.blackbox.size = CFG.server_settings.blackbox_max_size or 1000 - elseif server.protocol == "traccar" then - server.frequency = CFG.server_settings.server_frequency or 5 - end - - return err, server - else - return err, nil - end -end - ------------------------------------------------------------------------------------ --- Yandex Locator - -- 1.Check Yandex Locator service enable/disable - -- 2.Check Yandex API key status enable/disable - -- 3.Check Yandex Locator interface status enable/disable ------------------------------------------------------------------------------------ -function config.getLoctorData() - - local err = {} - local locator = { - enable = false, - iface = "", - key = "" - } - - if not CFG.service_settings.ya_enable then - err = STATUS.LOCATOR.SERVICE_OFF - elseif not CFG.service_settings.ya_key then - err = STATUS.LOCATOR.API_KEY_ERROR - elseif not CFG.service_settings.ya_wifi and CFG.service_settings.ya_wifi == "wnf" then - err = STATUS.LOCATOR.WIFI_IFACE_ERROR - else - err = STATUS.LOCATOR.SERVICE_ON - end - - if not err[1] then - locator.iface = CFG.service_settings.ya_wifi - locator.key = CFG.service_settings.ya_key - return err, locator - else - return err, nil - end -end - ------------------------------------------------------------------------------------ --- GpointFilter - -- 1. Checking for the filter library - -- 2. Check GpointFilter service enable/disable - -- 3. Make the settings, if there are none, then we apply the default settings ------------------------------------------------------------------------------------ -function config.getFilterData() - - local err = {} - local filter = { - enable = false, - changes = 0, - hash ='0', - speed = 0 - } - - if not CFG.service_settings.filter_enable then - err = STATUS.FILTER.SERVICE_OFF - else - err = STATUS.FILTER.SERVICE_ON - filter.enable = true - filter.changes = tonumber(CFG.service_settings.filter_changes or 3) - filter.hash = tostring(CFG.service_settings.filter_hash or'7') - filter.speed = tonumber(CFG.service_settings.filter_speed or 2) - end - - return err, filter -end - ------------------------------------------------------------------------------------ --- KalmanFilter - -- 1. Checking for the kalman filter library - -- 2. Check KalmanFilter service enable/disable - -- 3. Make the settings, if there are none, then we apply the default settings ------------------------------------------------------------------------------------ -function config.getKalmanData() - - local err = {} - local filter = { - enable = false, - noise = 0 - } - - if not CFG.service_settings.kalman_enable then - err = STATUS.FILTER.SERVICE_OFF - else - err = STATUS.FILTER.SERVICE_ON - filter.enable = true - filter.noise = tonumber(CFG.service_settings.kalman_noise or 1.0) - end - - return err, filter -end - ------------------------------------------------------------------------------------ --- Session ID - -- 1.When initializing the ubus, we write the session id to the uci to work with the UI ------------------------------------------------------------------------------------ -function config.setUbusSessionId(id) - uci:set("gpoint", "service_settings", "sessionid", id) - uci:save("gpoint") - uci:commit("gpoint") -end - -return config diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/lib/geohash.lua b/luci-app-gpoint-main/root/usr/share/gpoint/lib/geohash.lua deleted file mode 100644 index de0d09c2f..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/lib/geohash.lua +++ /dev/null @@ -1,147 +0,0 @@ --- Geohash --- (c) 2015 Ivan Ribeiro Rocha (ivan.ribeiro@gmail.com) --- (c) 2022 modified by Vladislav Kadulin (spanky@yandex.ru) - -local bit = require("bit32") - -geohash = {} - -local BITS = { 16, 8, 4, 2, 1 } -local BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz" - -local NEIGHBORS = { right = { even = "bc01fg45238967deuvhjyznpkmstqrwx" }, - left = { even = "238967debc01fg45kmstqrwxuvhjyznp" }, - top = { even = "p0r21436x8zb9dcf5h7kjnmqesgutwvy" }, - bottom = { even = "14365h7k9dcfesgujnmqp0r2twvyx8zb" } } - -local BORDERS = { right = { even = "bcfguvyz" }, - left = { even = "0145hjnp" }, - top = { even = "prxz" }, - bottom = { even = "028b" } } - -NEIGHBORS.bottom.odd = NEIGHBORS.left.even -NEIGHBORS.top.odd = NEIGHBORS.right.even -NEIGHBORS.left.odd = NEIGHBORS.bottom.even -NEIGHBORS.right.odd = NEIGHBORS.top.even - -BORDERS.bottom.odd = BORDERS.left.even -BORDERS.top.odd = BORDERS.right.even -BORDERS.left.odd = BORDERS.bottom.even -BORDERS.right.odd = BORDERS.top.even - -function geohash.decode(hash) - local flip = true; - local coords = { latitude = { -90.0, 90.0 }, - longitude = { -180.0, 180.0 } } - - for i = 1, #hash do - local c = hash:sub(i, i) - local cd = BASE32:find(c) - 1 - for j = 1, 5 do - mask = BITS[j] - local tab = (flip and coords.longitude) or coords.latitude - local idx = (bit.band(cd, mask) > 0) and 1 or 2 - tab[idx] = (tab[1] + tab[2]) / 2 - flip = not flip - end - end - - for k, _ in pairs(coords) do - coords[k][3] = (coords[k][1] + coords[k][2]) / 2 - end - - return { lat = coords.latitude, lon = coords.longitude } - -end - -function geohash.encode(latitude, longitude, precision) - local lat = { -90.0, 90.0 } - local lon = { -180.0, 180.0 } - local b, ch, flip = 0, 0, true - local res = ""; - - latitude = tonumber(latitude) - longitude = tonumber(longitude) - precision = tonumber(precision) - local precision = precision or 12 - - while #res < precision do - local tab = flip and lon or lat - local grd = flip and longitude or latitude - - mid = (tab[1] + tab[2]) / 2 - - if grd > mid then - ch = bit.bor(ch, BITS[b + 1]) - tab[1] = mid - else - tab[2] = mid - end - - flip = not flip; - - if b < 4 then - b = b + 1 - else - res = res..BASE32:sub(ch + 1, ch + 1); - b, ch = 0, 0 - end - end - return res -end - -function geohash.calculate_distance(lat1, lon1, lat2, lon2) - local R = 6371000 - local r1, r2 = math.rad(lat1), math.rad(lat2) - local dlat, dlon = math.rad((lat2-lat1)), math.rad((lon2-lon1)) - local a = math.sin(dlat/2) * math.sin(dlat/2) + - math.cos(r1) * math.cos(r2) * - math.sin(dlon/2) * math.sin(dlon/2) - local c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) - return R * c -end - -function geohash.distance(hash1, hash2) - local t1, t2 = decode(hash1), decode(hash2) - return calculate_distance(coord(t1).lat, coord(t1).lon, - coord(t2).lat, coord(t2).lon) -end - -function geohash.neighbor(hash, dir) - hash = hash:lower() - local len = #hash - local last = hash:sub(len, len); - local flip = ((math.mod(len,2) == 0) and 'even') or 'odd' - local base = hash:sub(1, len - 1) - if BORDERS[dir][flip]:find(last) then - base = neighbor(base, dir) - end - local n = NEIGHBORS[dir][flip]:find(last) - return base..BASE32:sub(n, n) -end - -function geohash.neighbors(hash) - local neighbors = { top = neighbor(hash, 'top'), - bottom = neighbor(hash, 'bottom'), - right = neighbor(hash, 'right'), - left = neighbor(hash, 'left') } - neighbors.topleft = neighbor(neighbors.left, 'top'); - neighbors.topright = neighbor(neighbors.right, 'top'); - neighbors.bottomleft = neighbor(neighbors.left, 'bottom'); - neighbors.bottomright = neighbor(neighbors.right, 'bottom'); - return neighbors -end - -function geohash.coord(t) - if type(t) == 'table' then - return { lat = t.lat[3], lon = t.lon[3] } - end - return coord(decode(t)) -end - -function geohash.coord_str(t) - local t = coord(t) - return string.format("lat: %s and lon: %s", tostring(t.lat), tostring(t.lon)) -end - -return geohash \ No newline at end of file diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/lib/kalman_filter/gps_lib.lua b/luci-app-gpoint-main/root/usr/share/gpoint/lib/kalman_filter/gps_lib.lua deleted file mode 100644 index 3e81f5acd..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/lib/kalman_filter/gps_lib.lua +++ /dev/null @@ -1,111 +0,0 @@ -local kalman = require("kalman_lib") -local matrix = require("matrix_lib") - -gps_lib = {} - -local PI = 3.14159265 -local EARTH_RADIUS_IN_MILES = 3963.1676 - -function gps_lib.set_seconds_per_timestep(kalman_filter, seconds_per_timestep) - local unit_scaler = 0.001 - kalman_filter.state_transition[1][3] = unit_scaler * seconds_per_timestep - kalman_filter.state_transition[2][4] = unit_scaler * seconds_per_timestep - return kalman_filter -end - -function gps_lib.create_velocity2d(noise) - local kalman_filter = kalman.create(4, 2) - local v2p = 0.001 - - kalman_filter.state_transition = matrix.set_identity(kalman_filter.state_transition) - kalman_filter = gps_lib.set_seconds_per_timestep(kalman_filter, 1.0) - kalman_filter.observation_model = matrix.set(kalman_filter.observation_model, - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0) - - local pos = 0.000001 - kalman_filter.process_noise_covariance = matrix.set(kalman_filter.process_noise_covariance, - pos, 0.0, 0.0, 0.0, - 0.0, pos, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0) - - kalman_filter.observation_noise_covariance = matrix.set(kalman_filter.observation_noise_covariance, - pos * noise, 0.0, - 0.0, pos * noise) - - kalman_filter.state_estimate = matrix.set(kalman_filter.state_estimate, 0.0, 0.0, 0.0, 0.0) - kalman_filter.estimate_covariance = matrix.set_identity(kalman_filter.estimate_covariance) - local trillion = 1000.0 * 1000.0 * 1000.0 * 1000.0 - kalman_filter.estimate_covariance = matrix.scale(kalman_filter.estimate_covariance, trillion) - return kalman_filter -end - -function gps_lib.update_velocity2d(kalman_filter, lat, lon, seconds_since_last_timestep) - kalman_filter = gps_lib.set_seconds_per_timestep(kalman_filter, seconds_since_last_timestep) - kalman_filter.observation = matrix.set(kalman_filter.observation, lat * 1000.0, lon * 1000.0) - kalman_filter = kalman.update(kalman_filter) - return kalman_filter -end - -function gps_lib.get_lat_lon(kalman_filter) - return string.format("%0.6f", kalman_filter.state_estimate[1][1] / 1000.0), - string.format("%0.6f", kalman_filter.state_estimate[2][1] / 1000.0) -end - -function gps_lib.get_velocity(kalman_filter) - return kalman_filter.state_estimate[3][1] / (1000.0 * 1000.0), - kalman_filter.state_estimate[4][1] / (1000.0 * 1000.0) -end - -function gps_lib.get_bearing(kalman_filter) - local lat, lon = gps_lib.get_lat_lon(kalman_filter) - local delta_lat, delta_lon = gps_lib.get_velocity(kalman_filter) - - local to_radians = PI / 180.0 - lat = lat * to_radians - lon = lon * to_radians - delta_lat = delta_lat * to_radians - delta_lon = delta_lon * to_radians - - local lat1 = lat - delta_lat - local y = math.sin(delta_lon) * math.cos(lat) - local x = math.cos(lat1) * math.sin(lat) - math.sin(lat1) * math.cos(lat) * math.cos(delta_lon) - local bearing = math.atan2(y, x) - - bearing = bearing / to_radians - while bearing >= 360 do - bearing = bearing - 360 - end - while bearing < 0 do - bearing = bearing + 360 - end - return bearing -end - -function gps_lib.calculate_mph(lat, lon, delta_lat, delta_lon) - local to_radians = PI / 180 - lat = lat * to_radians - lon = lon * to_radians - delta_lat = delta_lat * to_radians - delta_lon = delta_lon * to_radians - - local lat1 = lat - delta_lat - local sin_half_dlat = math.sin(delta_lat / 2) - local sin_half_dlon = math.sin(delta_lon / 2) - - local a = sin_half_dlat * sin_half_dlat + math.cos(lat1) * math.cos(lat) * sin_half_dlon * sin_half_dlon - local radians_per_second = 2 * math.atan2(1000 * math.sqrt(a), 1000 * math.sqrt(1.0 - a)) - - local miles_per_second = radians_per_second * EARTH_RADIUS_IN_MILES - local miles_per_hour = miles_per_second * 60 * 60 - return miles_per_hour -end - -function gps_lib.get_mph(kalman_filter) - local lat, lon = gps_lib.get_lat_lon(kalman_filter) - local delta_lat, delta_lon = gps_lib.get_velocity(kalman_filter) - return gps_lib.calculate_mph(lat, lon, delta_lat, delta_lon) -end - -return gps_lib \ No newline at end of file diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/lib/kalman_filter/kalman_lib.lua b/luci-app-gpoint-main/root/usr/share/gpoint/lib/kalman_filter/kalman_lib.lua deleted file mode 100644 index 207b43007..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/lib/kalman_filter/kalman_lib.lua +++ /dev/null @@ -1,82 +0,0 @@ - local matrix = require("matrix_lib") - -kalman_lib = {} - -function kalman_lib.create(state, observation) - local kalman = { - timestep = 0, -- K - -- These parameters define the size of the matrices. - state_dimension = state, - observation_dimension = observation, - - -- This group of matrices must be specified by the user. - state_transition = matrix.create(state, state), -- F_k - observation_model = matrix.create(observation, state), -- H_k - process_noise_covariance = matrix.create(state, state), -- Q_k - observation_noise_covariance = matrix.create(observation, observation), -- R_k - - -- The observation is modified by the user before every time step. - observation = matrix.create(observation, 1), -- z_k - - -- This group of matrices are updated every time step by the filter. - predicted_state = matrix.create(state, 1), -- x-hat_k|k-1 - predicted_estimate_covariance = matrix.create(state, state), -- P_k|k-1 - innovation = matrix.create(observation, 1), -- y-tilde_k - innovation_covariance = matrix.create(observation, observation), -- S_k - inverse_innovation_covariance = matrix.create(observation, observation), -- S_k^-1 - optimal_gain = matrix.create(state, observation), -- K_k - state_estimate = matrix.create(state, 1), -- x-hat_k|k - estimate_covariance = matrix.create(state, state), -- P_k|k - - -- This group is used for meaningless intermediate calculations. - vertical_scratch = matrix.create(state, observation), - mall_square_scratch = matrix.create(observation, observation), - big_square_scratch = matrix.create(state, state) - } - return kalman -end - -function kalman_lib.predict(kalman) - kalman.timestep = kalman.timestep + 1 - -- Predict the state - kalman.predicted_state = matrix.multiply(kalman.state_transition, kalman.state_estimate, kalman.predicted_state) - -- Predict the state estimate covariance - kalman.big_square_scratch = matrix.multiply(kalman.state_transition, kalman.estimate_covariance, kalman.big_square_scratch) - kalman.predicted_estimate_covariance = matrix.multiply_by_transpose(kalman.big_square_scratch, kalman.state_transition, kalman.predicted_estimate_covariance) - kalman.predicted_estimate_covariance = matrix.add(kalman.predicted_estimate_covariance, kalman.process_noise_covariance, kalman.predicted_estimate_covariance) - return kalman -end - -function kalman_lib.estimate(kalman) - -- Calculate innovation - kalman.innovation = matrix.multiply(kalman.observation_model, kalman.predicted_state, kalman.innovation) - kalman.innovation = matrix.subtract(kalman.observation, kalman.innovation, kalman.innovation) - -- Calculate innovation covariance - kalman.vertical_scratch = matrix.multiply_by_transpose(kalman.predicted_estimate_covariance, kalman.observation_model, kalman.vertical_scratch) - kalman.innovation_covariance = matrix.multiply(kalman.observation_model, kalman.vertical_scratch, kalman.innovation_covariance) - kalman.innovation_covariance = matrix.add(kalman.innovation_covariance, kalman.observation_noise_covariance, kalman.innovation_covariance) - -- Invert the innovation covariance. - -- Note: this destroys the innovation covariance. - -- TODO: handle inversion failure intelligently. - matrix.destructive_invert(kalman.innovation_covariance, kalman.inverse_innovation_covariance) - -- Calculate the optimal Kalman gain. - -- Note we still have a useful partial product in vertical scratch - -- from the innovation covariance. - kalman.optimal_gain = matrix.multiply(kalman.vertical_scratch, kalman.inverse_innovation_covariance, kalman.optimal_gain) - -- Estimate the state - kalman.state_estimate = matrix.multiply(kalman.optimal_gain, kalman.innovation, kalman.state_estimate) - kalman.state_estimate = matrix.add(kalman.state_estimate, kalman.predicted_state, kalman.state_estimate) - -- Estimate the state covariance - kalman.big_square_scratch = matrix.multiply(kalman.optimal_gain, kalman.observation_model, kalman.big_square_scratch) - kalman.big_square_scratch = matrix.subtract_from_identity(kalman.big_square_scratch) - kalman.estimate_covariance = matrix.multiply(kalman.big_square_scratch, kalman.predicted_estimate_covariance, kalman.estimate_covariance) - return kalman -end - -function kalman_lib.update(kalman) - kalman = kalman_lib.predict(kalman) - kalman = kalman_lib.estimate(kalman) - return kalman -end - -return kalman_lib diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/lib/kalman_filter/matrix_lib.lua b/luci-app-gpoint-main/root/usr/share/gpoint/lib/kalman_filter/matrix_lib.lua deleted file mode 100644 index 23c3dbfc4..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/lib/kalman_filter/matrix_lib.lua +++ /dev/null @@ -1,191 +0,0 @@ -matrix_lib = {} - -function matrix_lib.create(rows, cols) - local matrix = {} - for i = 1,rows do - matrix[i] = {} - for j = 1,cols do - matrix[i][j] = 0.0 - end - end - return matrix -end - -function matrix_lib.print(matrix) - for i = 1, #matrix do - for j = 1, #matrix[i] do - io.write(matrix[i][j] .. " ") - end - io.write('\n') - end -end - -function matrix_lib.set(matrix, ...) - local k = 1 - for i = 1, #matrix do - for j = 1, #matrix[i] do - if arg[k] ~= nil then - matrix[i][j] = arg[k] - end - k = k + 1 - end - end - return matrix -end - -function matrix_lib.set_identity(matrix) - for i = 1, #matrix do - for j = 1, #matrix[i] do - matrix[i][j] = i == j and 1.0 or 0.0 - end - end - return matrix -end - -function matrix_lib.copy(matrix) - local copy = {} - for i = 1, #matrix do - copy[i] = {} - for j = 1, #matrix[i] do - copy[i][j] = matrix[i][j] - end - end - return copy -end - -function matrix_lib.add(matrix_a, matrix_b, matrix_c) - for i = 1, #matrix_a do - for j = 1, #matrix_a[i] do - matrix_c[i][j] = matrix_a[i][j] + matrix_b[i][j] - end - end - return matrix_c -end - -function matrix_lib.subtract(matrix_a, matrix_b, matrix_c) - for i = 1, #matrix_a do - for j = 1, #matrix_a[i] do - matrix_c[i][j] = matrix_a[i][j] - matrix_b[i][j] - end - end - return matrix_c -end - -function matrix_lib.subtract_from_identity(matrix) - for i = 1, #matrix do - for j = 1, #matrix[i] do - matrix[i][j] = i == j and (1.0 - matrix[i][j]) or (0.0 - matrix[i][j]) - end - end - return matrix -end - -function matrix_lib.multiply(matrix_a, matrix_b, matrix_c) - for i = 1, #matrix_c do - for j = 1, #matrix_c[i] do - matrix_c[i][j] = 0.0 - for k = 1, #matrix_a[i] do - matrix_c[i][j] = matrix_c[i][j] + (matrix_a[i][k] * matrix_b[k][j]) - end - end - end - return matrix_c -end - -function matrix_lib.multiply_by_transpose(matrix_a, matrix_b, matrix_c) - for i = 1, #matrix_c do - for j = 1, #matrix_c[i] do - matrix_c[i][j] = 0.0 - for k = 1, #matrix_a[1] do - matrix_c[i][j] = matrix_c[i][j] + (matrix_a[i][k] * matrix_b[j][k]) - end - end - end - return matrix_c -end - -function matrix_lib.transpose(matrix_input, matrix_output) - for i = 1, #matrix_input do - for j = 1, #matrix_input[i] do - matrix_output[j][i] = matrix_input[i][j] - end - end - return matrix_output -end - -function matrix_lib.equal(matrix_a, matrix_b, tolerance) - for i = 1, #matrix_a do - for j = 1, #matrix_a[i] do - if math.abs(matrix_a[i][j] - matrix_b[i][j]) > tolerance then - return false - end - end - end - return true -end - -function matrix_lib.scale(matrix, scalar) - for i = 1, #matrix do - for j = 1, #matrix[i] do - matrix[i][j] = matrix[i][j] * scalar - end - end - return matrix -end - -function matrix_lib.swap_rows(matrix, r1, r2) - local tmp = matrix[r1] - matrix[r1] = matrix[r2] - matrix[r2] = tmp - return matrix -end - -function matrix_lib.scale_row(matrix, r, scalar) - for i = 1, #matrix do - matrix[r][i] = matrix[r][i] * scalar - end - return matrix -end - -function matrix_lib.shear_row(matrix, r1, r2, scalar) - for i = 1, #matrix do - matrix[r1][i] = matrix[r1][i] + (scalar * matrix[r2][i]) - end - return matrix -end - -function matrix_lib.destructive_invert(matrix_input, matrix_output) - matrix_output = matrix_lib.set_identity(matrix_output) - for i = 1, #matrix_input do - if matrix_input[i][i] == 0.0 then - local j - for j = i + 1, #matrix_input do - if matrix_input[r][i] ~= 0.0 then - return - end - end - - if j == #matrix_input then - return - end - - matrix_input = matrix_lib.swap_rows(matrix_input, i, j) - matrix_output = matrix_lib.swap_rows(matrix_output, i, j) - end - - local scalar = 1.0 / matrix_input[i][i] - matrix_input = matrix_lib.scale_row(matrix_input, i, scalar) - matrix_output = matrix_lib.scale_row(matrix_output, i, scalar) - - for r = 1, #matrix_input do - if i ~= r then - local shear_needed = -matrix_input[r][i] - matrix_input = matrix_lib.shear_row(matrix_input, r, i, shear_needed) - matrix_output = matrix_lib.shear_row(matrix_output, r, i, shear_needed) - end - end - end - return matrix_input, matrix_output -end - -return matrix_lib \ No newline at end of file diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/lib/locator.lua b/luci-app-gpoint-main/root/usr/share/gpoint/lib/locator.lua deleted file mode 100644 index cea13b093..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/lib/locator.lua +++ /dev/null @@ -1,78 +0,0 @@ -------------------------------------------------------------------- --- Module is designed to work with the Yandex Locator API --- (WiFi is required!) -------------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -local json = require("luci.jsonc") -local sys = require("luci.sys") -local iwinfo = require("iwinfo") - -locator = {} - -local function configJSON(jsonData, iface, key) - jsonData.common.api_key = key - local inter = iwinfo.type(iface) - local scanlist = iwinfo[inter].scanlist(iface) - for _, v in pairs(scanlist) do - v.bssid = string.gsub(v.bssid, ':', '') - table.insert(jsonData.wifi_networks, {["mac"] = v.bssid, ["signal_strength"] = v.signal}) - end -end - -local function request(curl, jsonData) - curl = curl .. json.stringify(jsonData) .. '\'' - local res = sys.exec(curl) - if res == "" then - res = "{\"error\": {\"message\":\"No internet connection\"}}" - end - return json.parse(res) -end - --- Converter from degrees to NMEA data. -function locator.degreesToNmea(coord) - local degrees = math.floor(coord) - coord = math.abs(coord) - degrees - local sign = coord < 0 and "-" or "" - return sign .. string.format("%02i%02.5f", degrees, coord * 60.00) -end - --- Getting data coordinates via Yandex API -function locator.getLocation(iface_name, api_key) - local curl = "curl -X POST 'http://api.lbs.yandex.net/geolocation' -d 'json=" - local jsonData = { - wifi_networks = {}, - common = { - version = "1.0", - api_key = "" - } - } - - configJSON(jsonData, iface_name, api_key) - local location = request(curl, jsonData) - local err = {false, "OK"} - local latitude = "" - local longitude = "" - local altitude = "" - - if location.error then - err = {true, location.error.message} - end - - if location.position then - if tonumber(location.position.precision) >= 100000 then - err = {true, "Bad precision"} - else - latitude = string.format("%0.8f", location.position.latitude) - longitude = string.format("%0.8f", location.position.longitude) - if latitude == "" or longitude == "" then - err = {true, "Bad data..."} - end - end - end - - return err, latitude, longitude -end - -return locator diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/lib/nmea.lua b/luci-app-gpoint-main/root/usr/share/gpoint/lib/nmea.lua deleted file mode 100644 index 698ab8000..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/lib/nmea.lua +++ /dev/null @@ -1,385 +0,0 @@ -------------------------------------------------------------- --- This module is designed to extract data from NMEA messages. --- All data is combined into a table "GnssData". -------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -local uci = require("luci.model.uci") -local serial = require("serial") -local checksum = require("checksum") - - -local nmea = {} - --- Table for navigation data -local function createGnssForm() - local GnssForm = { - warning = { - app = {true, ""}, - gga = {true, ""}, - rmc = {true, ""}, - vtg = {true, ""}, - gsa = {true, ""}, - gp = {true, ""}, - gns = {true, ""}, - server = {true, ""}, - locator = {true, ""} - }, - gp = { longitude = "-", latitude = "-"}, - gga = { longitude = "-", latitude = "-"} - } - return GnssForm -end - ---Converting coordinates from the NMEA protocol to degrees -local function nmeaCoordinatesToDouble(coord) - local deg = math.floor(coord / 100) - return deg + (coord - 100 * deg) / 60 -end - ---We are looking for the desired data line in the line received from the device -local function findInResp(data, begin) - local err = true - local b = string.find(data, begin) - local e = string.find(data, "\r\n", b) - - if b and e then - err = false - else - b, e = nil, nil - end - return err, b, e -end - --- message parsing, checksum checking -local function getCropData(data, msg) - local err, b, e = findInResp(data, msg) - if not err then - data = string.gsub(string.sub(data, b, e), '%c', "") - if checksum.crc8(data) then - data = string.gsub(data, msg, '', 1) - data = string.gsub(data, "*%d+%w+", '', 1) - err = {false, "OK"} - else - err = {true, "Checksum error"} - data = nil - end - else - err = {true, "No data found"} - data = nil - end - return err, data -end - --- Creating a table with data before adding data to a single space -function doTable(data, keys) - local parseData = {} - - while string.find(data, ',,') do - data = string.gsub(data, ',,', ",-,") - end - - if string.sub(data, 1, 1) == ',' then - data = '-' .. data - end - - local i = 1 - for val in string.gmatch(data, "[^,]+") do - parseData[keys[i]] = val - i = i + 1 - end - return parseData -end - --- The function of searching the time zone by the received coordinates -local function findTimeZone(time, date, lon) - local datetime = { year,month,day,hour,min,sec } - local timeZone = uci:get("gpoint", "modem_settings", "timezone") - - -- calculate the time zone by coordinates - if timeZone == nil or timeZone == "auto" then - timeZone = math.floor((tonumber(lon) + (7.5 * (tonumber(lon) > 0 and 1.0 or -1.0))) / 15.0) - end - - datetime.hour, datetime.min, datetime.sec = string.match(time, "(%d%d)(%d%d)(%d%d)") - datetime.day, datetime.month, datetime.year = string.match(date,"(%d%d)(%d%d)(%d%d)") - datetime.year = "20" .. datetime.year -- Someone change this to 21 in the 2100 year - - --we request the unix time and then add the time zone - local unix = os.time(datetime) - unix = unix + ((math.floor(tonumber(timeZone) * 100)) % 100) * 36 - return unix + math.floor(tonumber(timeZone)) * 3600 -end - --- Add 0 for the time and date values if < 10 -local function addZero(val) - return tonumber(val) > 9 and tostring(val) or '0' .. tostring(val) -end - --- If there is no data, the default values of the table are dashed -local function addDash(data) - local dashData = {} - for i=1, #data do - dashData[data[i]] = '-' - end - return dashData -end - ---------------------------------------------------------------------------------------------------------------- --- GGA - Global Positioning System Fix Data -local function getGGA(GnssData, resp) - GnssData.gga = { - "utc", -- UTC of this position report, hh is hours, mm is minutes, ss.ss is seconds. - "latitude", -- Latitude, dd is degrees, mm.mm is minutes - "ne", -- N or S (North or South) - "longitude", -- Longitude, dd is degrees, mm.mm is minutes - "ew", -- E or W (East or West) - "qual", -- GPS Quality Indicator (non null) - "sat", -- Number of satellites in use, 00 - 12 - "hdp", -- Horizontal Dilution of precision (meters) - "alt", -- Antenna Altitude above/below mean-sea-level (geoid) (in meters) - "ualt", -- Units of antenna altitude, meters - "gsep", -- Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level - "ugsep", -- Units of geoidal separation, meters - "age", -- Age of differential GPS data, time in seconds since last SC104 type 1 or 9 update, null field when DGPS is not used - "drs" -- Differential reference station ID, 0000-1023 - } - - local err, gga = getCropData(resp, "$GPGGA,") - if not err[1] and string.gsub(gga, ',', '') ~= '0' - and string.sub(gga, string.find(gga, ',') + 1, string.find(gga, ',') + 1) ~= ',' then - GnssData.gga = doTable(gga, GnssData.gga) - GnssData.warning.gga = {false, "OK"} - else - GnssData.gga = addDash(GnssData.gga) - GnssData.warning.gga = err[1] and err or {true, "Bad GGA data"} - end -end - --- RMC - Recommended Minimum Navigation Information -local function getRMC(GnssData, resp) - GnssData.rmc = { - "utc", -- UTC of position fix, hh is hours, mm is minutes, ss.ss is seconds. - "valid", -- Status, A = Valid, V = Warning - "latitude", -- Latitude, dd is degrees. mm.mm is minutes. - "ns", -- N or S - "longitude", -- Longitude, ddd is degrees. mm.mm is minutes. - "ew", -- E or W - "knots", -- Speed over ground, knots - "tmgdt", -- Track made good, degrees true - "date", -- Date, ddmmyy - "mv", -- Magnetic Variation, degrees - "ewm", -- E or W - "nstat", -- Nav Status (NMEA 4.1 and later) A=autonomous, D=differential, E=Estimated, -> - -- M=Manual input mode N=not valid, S=Simulator, V = Valid - "sc" --checksum - } - - local err, rmc = getCropData(resp, "$GPRMC,") - if not err[1] and string.find(rmc, ",A,") then - GnssData.rmc = doTable(rmc, GnssData.rmc) - GnssData.warning.rmc = {false, "OK"} - else - GnssData.rmc = addDash(GnssData.rmc) - GnssData.warning.rmc = err[1] and err or {true, "Bad RMC data"} - end -end - --- VTG - Track made good and Ground speed -local function getVTG(GnssData, resp) - GnssData.vtg = { - "course_t", -- Course over ground, degrees True - 't', -- T = True - "course_m", -- Course over ground, degrees Magnetic - 'm', -- M = Magnetic - "knots", -- Speed over ground, knots - 'n', -- N = Knots - "speed", -- Speed over ground, km/hr - 'k', -- K = Kilometers Per Hour - "faa" -- FAA mode indicator (NMEA 2.3 and later) - } - - local err, vtg = getCropData(resp, "$GPVTG,") - if not err[1] and (string.find(vtg, 'A') or string.find(vtg, 'D')) then - GnssData.vtg = doTable(vtg, GnssData.vtg) - GnssData.warning.vtg = {false, "OK"} - else - GnssData.vtg = addDash(GnssData.vtg) - GnssData.warning.vtg = err[1] and err or {true, "Bad VTG data"} - end -end - ---GSA - GPS DOP and active satellites -local function getGSA(GnssData, resp) - GnssData.gsa = { - "smode", -- Selection mode: M=Manual, forced to operate in 2D or 3D, A=Automatic, 2D/3D - "mode", -- Mode (1 = no fix, 2 = 2D fix, 3 = 3D fix) - "id1", -- ID of 1st satellite used for fix - "id2", -- ID of 2nd satellite used for fix - "id3", -- ID of 3rd satellite used for fix - "id4", -- ID of 4th satellite used for fix - "id5", -- ID of 5th satellite used for fix - "id6", -- ID of 6th satellite used for fix - "id7", -- ID of 7th satellite used for fix - "id8", -- ID of 8th satellite used for fix - "id9", -- ID of 9th satellite used for fix - "id10", -- ID of 10th satellite used for fix - "id11", -- ID of 11th satellite used for fix - "id12", -- ID of 12th satellite used for fix - "pdop", -- PDOP - "hdop", -- HDOP - "vdop", -- VDOP - "sc" -- checksum - } - - local err, gsa = getCropData(resp, "$GPGSA,") - if not err[1] and string.find(gsa, '2') then - GnssData.gsa = doTable(gsa, GnssData.gsa) - GnssData.warning.gsa = {false, "OK"} - else - GnssData.gsa = addDash(GnssData.gsa) - GnssData.warning.gsa = err[1] and err or {true, "Bad GSA data"} - end -end - ---GNS - GLONAS Fix data -local function getGNS(GnssData, resp) - GnssData.gns = { - "utc", -- UTC of this position report, hh is hours, mm is minutes, ss.ss is seconds. - "latitude", -- Latitude, dd is degrees, mm.mm is minutes - "ne", -- N or S (North or South) - "longitude", -- Longitude, dd is degrees, mm.mm is minutes - "ew", -- E or W (East or West) - "mi", -- Mode indicator (non-null) - "sat", -- Total number of satellites in use, 00-99 - "hdp", -- Horizontal Dilution of Precision, HDOP - "alt", -- Antenna Altitude above/below mean-sea-level (geoid) (in meters) - "gsep", -- Goeidal separation meters - "age", -- Age of differential data - "drs", -- Differential reference station ID - "nstat" --Navigational status (optional) S = Safe C = Caution U = Unsafe V = Not valid for navigation - } - - local err, gns = getCropData(resp, "$GNGNS,") - if not err[1] and string.gsub(gns, ',', '') ~= '0' and not string.find(gns, "NNN") then - GnssData.gns = doTable(gns, GnssData.gns) - GnssData.warning.gns = {false, "OK"} - else - GnssData.gns = addDash(GnssData.gns) - GnssData.warning.gns = err[1] and err or {true, "Bad GNS data"} - end -end - --- Prepares data for the web application (Some custom data) -local function getGPoint(GnssData, resp) - GnssData.gp = { - longitude = '-', - latitude = '-', - altitude = '-', - utc = '-', - date = '-', - nsat = '-', - hdop = '-', - cog = '-', - spkm = '-', - unix = '-' - } - - local err = {true, ""} - local GpsOrGlonas = false - - if not GnssData.warning.gga[1] then - GpsOrGlonas = GnssData.gga - elseif not GnssData.warning.gns[1] then - GpsOrGlonas = GnssData.gns - else - err[2] = "GGA: " .. GnssData.warning.gga[2] .. ' ' .. "GNS: " .. GnssData.warning.gns[2] .. ' ' - end - - if GpsOrGlonas then - GnssData.gp.latitude = string.format("%0.6f", nmeaCoordinatesToDouble(GpsOrGlonas.latitude)) - GnssData.gp.longitude = string.format("%0.6f", nmeaCoordinatesToDouble(GpsOrGlonas.longitude)) - GnssData.gp.altitude = GpsOrGlonas.alt - GnssData.gp.nsat = GpsOrGlonas.sat - GnssData.gp.hdop = GpsOrGlonas.hdp - end - - if not GnssData.warning.vtg[1] then - GnssData.gp.cog = GnssData.vtg.course_t - GnssData.gp.spkm = GnssData.vtg.speed - else - err[2] = err[2] .. "VTG: " .. GnssData.warning.vtg[2] .. ' ' - end - - if not GnssData.warning.rmc[1] then - local unixTime = findTimeZone(GnssData.rmc.utc, GnssData.rmc.date, nmeaCoordinatesToDouble(GnssData.rmc.longitude)) - local dateTime = os.date("*t", unixTime) - - GnssData.gp.utc = string.format("%s:%s", addZero(dateTime.hour), addZero(dateTime.min)) - GnssData.gp.date = string.format("%s.%s.%d", addZero(dateTime.day), addZero(dateTime.month), dateTime.year) - GnssData.gp.unix = unixTime - else - err[2] = err[2] .. "RMC: " .. GnssData.warning.rmc[2] - end - - if GnssData.warning.gga[1] and GnssData.warning.gns[1] and GnssData.warning.vtg[1] and GnssData.warning.rmc[1] then - err = {false, "Updating data..."} - end - - if err[2] == "" then - err = {false, "OK"} - end - - GnssData.warning.gp = err -end - ------------------------------------------------------- --- Get a certain kind of NMEA data (data parsing) ------------------------------------------------------- - -function nmea.getData(line, port) - GnssData = createGnssForm() - GnssData.warning.app, resp = serial.read(port) - - if line == "GP" then - getGGA(GnssData, resp) - getGNS(GnssData, resp) - getRMC(GnssData, resp) - getVTG(GnssData, resp) - getGPoint(GnssData, resp) - elseif line == "GGA" then - getGGA(GnssData, resp) - elseif line == "GNS" then - getGNS(GnssData, resp) - elseif line == "RMC" then - getRMC(GnssData, resp) - elseif line == "VTG" then - getVTG(GnssData, resp) - elseif line == "GSA" then - getGSA(GnssData, resp) - else - GnssData.warning.app = {true, "Bad argument..."} - end - return GnssData -end - ------------------------------------------------------- --- parsing all NMEA data ------------------------------------------------------- - -function nmea.getAllData(port) - GnssData = createGnssForm() - GnssData.warning.app, resp = serial.read(port) - - getGGA(GnssData, resp) - getGNS(GnssData, resp) - getRMC(GnssData, resp) - getVTG(GnssData, resp) - getGSA(GnssData, resp) -- rarely used - getGPoint(GnssData, resp) - - return GnssData -end - -return nmea diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/lib/serial.lua b/luci-app-gpoint-main/root/usr/share/gpoint/lib/serial.lua deleted file mode 100644 index ca6dc1381..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/lib/serial.lua +++ /dev/null @@ -1,73 +0,0 @@ -------------------------------------------------------------------- --- Wrapper for working with a modem via serial port -------------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -local rs232 = require("luars232") - -local serial = {} - -local function configSerial(port) - assert(port:set_baud_rate(rs232.RS232_BAUD_115200) == rs232.RS232_ERR_NOERROR) - assert(port:set_parity(rs232.RS232_PARITY_NONE) == rs232.RS232_ERR_NOERROR) - assert(port:set_data_bits(rs232.RS232_DATA_8) == rs232.RS232_ERR_NOERROR) - assert(port:set_stop_bits(rs232.RS232_STOP_1) == rs232.RS232_ERR_NOERROR) - assert(port:set_flow_control(rs232.RS232_FLOW_OFF) == rs232.RS232_ERR_NOERROR) -end - --- write data from modem (AT PORT) -function serial.write(serial_port, command) - local err, port = rs232.open(serial_port) - if err ~= rs232.RS232_ERR_NOERROR then - err = {true, "Error opening AT port"} - assert(port:close() == rs232.RS232_ERR_NOERROR) - return err - end - configSerial(port) - - local err, len_written = port:write(command .. "\r\n") - if err ~= rs232.RS232_ERR_NOERROR then - err = {true, "Error writing AT port"} - assert(port:close() == rs232.RS232_ERR_NOERROR) - return err - end - - err = {false, "OK"} - assert(port:close() == rs232.RS232_ERR_NOERROR) - return err -end - --- read data from modem (GNSS PORT) -function serial.read(serial_port) - local err, port = rs232.open(serial_port) - if err ~= rs232.RS232_ERR_NOERROR then - err = {true, "Error opening GNSS port"} - assert(port:close() == rs232.RS232_ERR_NOERROR) - return err, '' - end - configSerial(port) - - local READ_LEN = 1024 -- Read byte form GNSS port - local TIMEOUT = 1000 -- Timeout reading in miliseconds - - local serialData, err, read_data = {}, "", "" - while READ_LEN > 0 do - err, read_data = port:read(1, TIMEOUT) - if err ~= rs232.RS232_ERR_NOERROR then - err = {true, "Error reading GNSS port. Updating data or searching for satellites..."} - assert(port:close() == rs232.RS232_ERR_NOERROR) - return err, "" - end - if read_data ~= nil then - table.insert(serialData, read_data) - READ_LEN = READ_LEN - 1 - end - end - assert(port:close() == rs232.RS232_ERR_NOERROR) - - err = {false, "OK"} - return err, table.concat(serialData) -end - -return serial diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/modems/dell.lua b/luci-app-gpoint-main/root/usr/share/gpoint/modems/dell.lua deleted file mode 100644 index a28b63dfe..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/modems/dell.lua +++ /dev/null @@ -1,44 +0,0 @@ -common_path = '/usr/share/gpoint/lib/?.lua;' -package.path = common_path .. package.path - - -local nmea = require("nmea") -local serial = require("serial") -local nixio = require("nixio.fs") - -local dell = {} - -local DELL_BEGIN_GPS = "AT+GPS=1" -local DELL_END_GPS = "AT+GPS=0" - --- automatic activation of the NMEA port for data transmission -function dell.start(port) - local p = tonumber(string.sub(port, #port)) + 1 - p = string.gsub(port, '%d', tostring(p)) - local error, resp = true, { - warning = { - app = {true, "Port is unavailable. Check the modem connections!"}, - locator = {}, - server = {} - } - } - -- DELL DW5821 series default NMEA /dev/ttyUSB2 - local fport = nixio.glob("/dev/tty[A-Z][A-Z]*") - for name in fport do - if string.find(name, p) then - error, resp = serial.write(p, DELL_BEGIN_GPS) - end - end - return error, resp -end --- stop send data to NMEA port -function dell.stop(port) - error, resp = serial.write(port, DELL_END_GPS) - return error, resp -end --- get GNSS data for application -function dell.getGNSSdata(port) - return nmea.getAllData(port) -end - -return dell diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/modems/que.lua b/luci-app-gpoint-main/root/usr/share/gpoint/modems/que.lua deleted file mode 100644 index f837ca90e..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/modems/que.lua +++ /dev/null @@ -1,41 +0,0 @@ -common_path = '/usr/share/gpoint/lib/?.lua;' -package.path = common_path .. package.path - -local nmea = require("nmea") -local serial = require("serial") -local nixio = require("nixio.fs") - -local que = {} - -local QUECTEL_BEGIN_GPS = "AT+QGPS=1" -local QUECTEL_END_GPS = "AT+QGPSEND" - --- automatic activation of the NMEA port for data transmission -function que.start(port) - local p = tonumber(string.sub(port, #port)) + 1 - p = string.gsub(port, '%d', tostring(p)) - local error, resp = true, {warning = { - app = {true, "Port is unavailable. Check the modem connections!"}, - locator = {}, - server = {} - } - } - local fport = nixio.glob("/dev/tty[A-Z][A-Z]*") - for name in fport do - if string.find(name, p) then - error, resp = serial.write(p, QUECTEL_BEGIN_GPS) - end - end - return error, resp -end --- stop send data to NMEA port -function que.stop(port) - error, resp = serial.write(port, QUECTEL_END_GPS) - return error, resp -end --- get GNSS data for application -function que.getGNSSdata(port) - return nmea.getAllData(port) -end - -return que \ No newline at end of file diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/modems/sierra.lua b/luci-app-gpoint-main/root/usr/share/gpoint/modems/sierra.lua deleted file mode 100644 index 5d0ba6cae..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/modems/sierra.lua +++ /dev/null @@ -1,40 +0,0 @@ -common_path = '/usr/share/gpoint/lib/?.lua;' -package.path = common_path .. package.path - - -local nmea = require("nmea") -local serial = require("serial") -local nixio = require("nixio.fs") - -local sierra = {} - -local SIERRA_BEGIN_GPS = "$GPS_START" -local SIERRA_END_GPS = "$GPS_STOP" - --- automatic activation of the NMEA port for data transmission -function sierra.start(port) - local error, resp = true, {warning = { - app = {true, "Port is unavailable. Check the modem connections!"}, - locator = {}, - server = {} - } - } - local fport = nixio.glob("/dev/tty[A-Z][A-Z]*") - for name in fport do - if string.find(name, port) then - error, resp = serial.write(port, SIERRA_BEGIN_GPS) - end - end - return error, resp -end --- stop send data to NMEA port -function sierra.stop(port) - error, resp = serial.write(port, SIERRA_END_GPS) - return error, resp -end --- get GNSS data for application -function sierra.getGNSSdata(port) - return nmea.getAllData(port) -end - -return sierra \ No newline at end of file diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/modems/simcom.lua b/luci-app-gpoint-main/root/usr/share/gpoint/modems/simcom.lua deleted file mode 100644 index 02319b4e6..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/modems/simcom.lua +++ /dev/null @@ -1,44 +0,0 @@ -common_path = '/usr/share/gpoint/lib/?.lua;' -package.path = common_path .. package.path - - -local nmea = require("nmea") -local serial = require("serial") -local nixio = require("nixio.fs") - -local simcom = {} - -local SIMCOM_BEGIN_GPS = "AT+CGPS=1,1" -local SIMCOM_END_GPS = "AT+CGPS=0,1" - --- automatic activation of the NMEA port for data transmission -function simcom.start(port) - local p = tonumber(string.sub(port, #port)) + 1 - p = string.gsub(port, '%d', tostring(p)) - local error, resp = true, { - warning = { - app = {true, "Port is unavailable. Check the modem connections!"}, - locator = {}, - server = {} - } - } - -- SIM7600 series default NMEA /dev/ttyUSB1 - local fport = nixio.glob("/dev/tty[A-Z][A-Z]*") - for name in fport do - if string.find(name, p) then - error, resp = serial.write(p, SIMCOM_BEGIN_GPS) - end - end - return error, resp -end --- stop send data to NMEA port -function simcom.stop(port) - error, resp = serial.write(port, SIMCOM_END_GPS) - return error, resp -end --- get GNSS data for application -function simcom.getGNSSdata(port) - return nmea.getAllData(port) -end - -return simcom diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/modems/ublox.lua b/luci-app-gpoint-main/root/usr/share/gpoint/modems/ublox.lua deleted file mode 100644 index 9bf3898fa..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/modems/ublox.lua +++ /dev/null @@ -1,22 +0,0 @@ -common_path = '/usr/share/gpoint/lib/?.lua;' -package.path = common_path .. package.path - - -local nmea = require("nmea") - -local ublox = {} - --- Wrapper over the interface, the module does not need an implementation -function ublox.start(port) - return false, {warning = {app = {false, "GOOD!"}, locator = {}, server = {}}} -end - -function ublox.stop(port) - return {false, "OK"} -end --- get GNSS data for application -function ublox.getGNSSdata(port) - return nmea.getAllData(port) -end - -return ublox \ No newline at end of file diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/proto/traccar.lua b/luci-app-gpoint-main/root/usr/share/gpoint/proto/traccar.lua deleted file mode 100644 index 148da57f7..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/proto/traccar.lua +++ /dev/null @@ -1,31 +0,0 @@ -------------------------------------------------------------- --- Traccar Client use this protocol to report GPS data to the server side. --- OsmAnd Live Tracking web address format: --- http://demo.traccar.org:5055/?id=123456&lat={0}&lon={1}×tamp={2}&hdop={3}&altitude={4}&speed={5} -------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -local http = require("socket.http") - -local trackcar = {} - -local function OsmAnd(GnssData, serverConfig) - local unix = GnssData.warning.rmc[1] and os.time() or GnssData.gp.unix - return string.format("http://%s:%s/?id=%s&lat=%s&lon=%s×tamp=%s&hdop=%s&altitude=%s&speed=%s&satellites=%s", - serverConfig.address, serverConfig.port, serverConfig.login, - GnssData.gp.latitude or '-', GnssData.gp.longitude or '-', - unix or '-', GnssData.gp.hdop or '-', - GnssData.gp.altitude or '-', GnssData.gp.spkm or '-', - GnssData.gp.nsat or '-') -end - --- Send data to server side -function trackcar.sendData(GnssData, serverConfig) - local data = OsmAnd(GnssData, serverConfig) - http.TIMEOUT = 0.5 - http.request{ method = "POST", url = data} - return {false, "OK"} -end - -return trackcar \ No newline at end of file diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/proto/wialon_ips.lua b/luci-app-gpoint-main/root/usr/share/gpoint/proto/wialon_ips.lua deleted file mode 100644 index f6ffedd76..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/proto/wialon_ips.lua +++ /dev/null @@ -1,160 +0,0 @@ -------------------------------------------------------------- --- A module for working with the "WIALON IPS" navigation protocol. --- This module prepares and sends data to a remote server. -------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -local json = require("luci.jsonc") -local checksum = require("checksum") -local blackbox = require("wialon_ips_boof") -local socket = require("socket") -local tcp = assert(socket.tcp()) - -local wialon_ips = {} - --- Abbreviated data package -local function shortData(GnssData) - local SD = {"NA","NA","NA","NA","NA","NA","NA","NA","NA","NA"} - if not GnssData.warning.rmc[1] then - SD[1], SD[2] = GnssData.rmc.date, GnssData.rmc.utc - end - if not GnssData.warning.gga[1] then - -- Lat2[4], Lon2[6] - NA - SD[3], SD[5] = GnssData.gga.latitude, GnssData.gga.longitude - SD[9], SD[10] = GnssData.gga.alt, GnssData.gga.sat - elseif not GnssData.warning.gns[1] then - SD[3], SD[5] = GnssData.gns.latitude, GnssData.gns.longitude - SD[9], SD[10] = GnssData.gns.alt, GnssData.gns.sat - elseif not GnssData.warning.locator[1] then - SD[1], SD[2] = os.date("%d%m%y"), os.date("%H%M%S", os.time(os.date("!*t"))) .. ".00" - SD[3], SD[5] = GnssData.gga.latitude, '0' .. GnssData.gga.longitude - end - if not GnssData.warning.vtg[1] then - SD[7], SD[8] = GnssData.vtg.speed, GnssData.vtg.course_t - end - SD[11] = checksum.crc16(table.concat(SD, ";") .. ';') - return "#SD#" .. table.concat(SD, ";") .. "\r\n" -end - --- Extended Data package with CRC16 -local function bigData(GnssData, params) - local D = {"NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","","NA","NA"} - if not GnssData.warning.rmc[1] then - D[1], D[2] = GnssData.rmc.date, GnssData.rmc.utc - end - if not GnssData.warning.gga[1] then - -- Lat2[4], Lon2[6] - NA - D[3], D[5] = GnssData.gga.latitude, GnssData.gga.longitude - D[9], D[10] = GnssData.gga.alt, GnssData.gga.sat - D[11] = GnssData.gga.hdp - elseif not GnssData.warning.gns[1] then - D[3], D[5] = GnssData.gns.latitude, GnssData.gns.longitude - D[9], D[10] = GnssData.gns.alt, GnssData.gns.sat - D[11] = GnssData.gns.hdp - elseif not GnssData.warning.locator[1] then - D[1], D[2] = os.date("%d%m%y"), os.date("%H%M%S", os.time(os.date("!*t"))) .. ".00" - D[3], D[5] = GnssData.gga.latitude, '0' .. GnssData.gga.longitude - D[16] = string.format("%s:%s:%s", "yandex", '3', "Data from wi-fi scan") - end - if not GnssData.warning.vtg[1] then - D[7], D[8] = GnssData.vtg.speed, GnssData.vtg.course_t - end - if params then - -- TODO PARAMS WITH YA LOCATOR - D[16] = string.format("%s:%s:%s", params[1], params[2], params[3]) - end - D[17] = checksum.crc16(table.concat(D, ";") .. ';') - return "#D#" .. table.concat(D, ";") .. "\r\n" -end - --- Response from the server to the message -local function handlErr(resp) - local ERROR_CODE = { - ["#AL#1"] = "OK", - ["#ASD#1"] = "OK", - ["#AD#1"] = "OK", - ["#AL#0"] = "Rejected connection", - ["#AL#01"] = "Password verification error", - ["#AL#10"] = "Checksum verification error", - ["#ASD#-1"] = "Package structure error", - ["#ASD#0"] = "Incorrect time", - ["#ASD#10"] = "Error getting coordinates", - ["#ASD#11"] = "Error getting speed, course, or altitude", - ["#ASD#12"] = "Error getting the number of satellites", - ["#ASD#13"] = "Checksum verification error", - ["#AD#-1"] = "Package structure error", - ["#AD#0"] = "Incorrect time", - ["#AD#10"] = "Error getting coordinates", - ["#AD#11"] = "Error getting speed, course, or altitude", - ["#AD#12"] = "Error in getting the number of satellites or HDOP", - ["#AD#13"] = "Error getting Inputs or Outputs", - ["#AD#14"] = "Error receiving ADC", - ["#AD#15"] = "Error getting additional parameters", - ["#AD#16"] = "Checksum verification error" - } - - for k, v in pairs(ERROR_CODE) do - if k == resp then - return v - end - end - return "Unknown error" -end - --- Login Package -local function login(imei, pass) - local L = {} - L[1], L[2], L[3] = "2.0", imei, pass - L[4] = checksum.crc16(table.concat(L, ";") .. ';') - return "#L#" .. table.concat(L, ";") .. "\r\n" -end - --- Send data to server side -function wialon_ips.sendData(GnssData, serverConfig) - local r, s, e - local DATA_OK = "OK" - local err = {false, DATA_OK} - local wialonData = bigData(GnssData) - - -- Data is missing, there is nothing to send - if string.find(wialonData, "DB2D") then - return {true, "No data to send"} - end - - s, e = tcp:connect(serverConfig.address, serverConfig.port) - if not s then - blackbox.set(GnssData, serverConfig) - tcp:close() - return {true, e} - end - tcp:settimeout(2) - tcp:send(login(serverConfig.login, serverConfig.password) .. '\n') - r, e = tcp:receive() - - if handlErr(r) == DATA_OK then - tcp:send(wialonData) - r, e = tcp:receive() - if handlErr(r) == DATA_OK then - local booferSize, booferData = blackbox.get(serverConfig) - if booferSize > 0 then - tcp:send(booferData .. '\n') - r, e = tcp:receive() - local sentSize = string.gsub(r, "%D", "") - if tonumber(sentSize) and tonumber(sentSize) >= booferSize then - blackbox.clean(serverConfig) - end - end - elseif handlErr(r) ~= DATA_OK then - blackbox.set(GnssData, serverConfig) - end - else - err = {true, handlErr(r)} - blackbox.set(GnssData, serverConfig) - end - - tcp:close() - return err -end - -return wialon_ips \ No newline at end of file diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/proto/wialon_ips_boof.lua b/luci-app-gpoint-main/root/usr/share/gpoint/proto/wialon_ips_boof.lua deleted file mode 100644 index fe556f246..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/proto/wialon_ips_boof.lua +++ /dev/null @@ -1,119 +0,0 @@ -------------------------------------------------------------- --- A module for working with the "WIALON IPS" navigation protocol. --- This module saves navigation data in case of signal loss --- (if it is not possible to transfer data to the server) -------------------------------------------------------------- --- Copyright 2021-2022 Vladislav Kadulin --- Licensed to the GNU General Public License v3.0 - -local json = require("luci.jsonc") -local checksum = require("checksum") - -local wialon_ips_boof = {} - --- Extended Data package -local function transformBooferData(GnssData, params) - local D = {"NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","","NA","NA"} - if not GnssData.warning.rmc[1] then - D[1], D[2] = GnssData.rmc.date, GnssData.rmc.utc - else - D[1], D[2] = os.date("%d%m%y"), os.date("%H%M%S",os.time(os.date("!*t"))) .. ".00" - end - if not GnssData.warning.gga[1] then - -- Lat2[4], Lon2[6] - NA - D[3], D[5] = GnssData.gga.latitude, GnssData.gga.longitude - D[9], D[10] = GnssData.gga.alt, GnssData.gga.sat - D[11] = GnssData.gga.hdp - elseif not GnssData.warning.gns[1] then - D[3], D[5] = GnssData.gns.latitude, GnssData.gns.longitude - D[9], D[10] = GnssData.gns.alt, GnssData.gns.sat - D[11] = GnssData.gns.hdp - elseif not GnssData.warning.locator[1] then - D[3], D[5] = GnssData.gga.latitude, '0' .. GnssData.gga.longitude - end - if not GnssData.warning.vtg[1] then - D[7], D[8] = GnssData.vtg.speed, GnssData.vtg.course_t - end - if params then - D[16] = string.format("%s:%s:%s", params[1], params[2], params[3]) - else - D[16] = string.format("%s:%s:%s", "boof", '3', "Data from boofer") - end - - return table.concat(D, ";") -end - --- read GNSS data from file -local function readBoof() - local file = io.open("/usr/share/gpoint/tmp/blackbox.json", 'r') - if not file then return nil end - local bb_data = json.parse(file:read("*a")) - file:close() - return bb_data -end - --- write GNSS data to file -local function writeBoof(boof) - local file = io.open("/usr/share/gpoint/tmp/blackbox.json", 'w') - file:write(json.stringify(boof)) - file:close() -end - --- create boofer with data if -local function createBoof(size) - local BLACKBOX = { ["size"]=0,["max"]=tonumber(size),["data"]={} } - writeBoof(BLACKBOX) - return BLACKBOX -end - --- Package from the black box -local function parseBlackBoxData(data) - local B = "" - for _, gnss_msg in pairs(data) do - B = B .. gnss_msg .. '|' - end - return "#B#" .. B .. checksum.crc16(B) .. "\r\n" -end - --- get data from the black box -function wialon_ips_boof.get(serverConfig) - if not serverConfig.blackbox.enable then - return -1, nil - end - - local blackbox = readBoof() - if blackbox == nil or tonumber(blackbox.max) ~= tonumber(serverConfig.blackbox.size) then - blackbox = createBoof(serverConfig.blackbox.size) - end - - return blackbox.size, parseBlackBoxData(blackbox.data) -end - --- send data to the black box -function wialon_ips_boof.set(GnssData, serverConfig) - - if not serverConfig.blackbox.enable then - return -1 - end - - local blackbox = readBoof() - if blackbox == nil or tonumber(blackbox.max) ~= tonumber(serverConfig.blackbox.size) then - blackbox = createBoof(serverConfig.blackbox.size) - end - - if blackbox.size < blackbox.max then - blackbox.size = blackbox.size + 1 - elseif serverConfig.blackbox.cycle then - blackbox.size = 1 - end - - blackbox.data[blackbox.size] = transformBooferData(GnssData) - writeBoof(blackbox) -end - --- clear the black box -function wialon_ips_boof.clean(serverConfig) - createBoof(serverConfig.blackbox.size) -end - -return wialon_ips_boof \ No newline at end of file diff --git a/luci-app-gpoint-main/root/usr/share/gpoint/tmp/blackbox.json b/luci-app-gpoint-main/root/usr/share/gpoint/tmp/blackbox.json deleted file mode 100644 index bcf57a157..000000000 --- a/luci-app-gpoint-main/root/usr/share/gpoint/tmp/blackbox.json +++ /dev/null @@ -1 +0,0 @@ -{"max":1000,"data":[],"size":0} \ No newline at end of file diff --git a/luci-app-gpoint-main/test/chechsum_test.lua b/luci-app-gpoint-main/test/chechsum_test.lua deleted file mode 100644 index 9356457e1..000000000 --- a/luci-app-gpoint-main/test/chechsum_test.lua +++ /dev/null @@ -1,143 +0,0 @@ -common_path = '/usr/share/gpoint/lib/?.lua;' -package.path = common_path .. package.path - -local checksum = require("checksum") -local lu = require('luaunit') - -local goodGNSSSdata = { - "$GPRMC,113702.568,V,4154.931,N,08002.497,W,95.5,0.02,220721,,E*4E", - "$GPGGA,113703.568,4154.931,N,08002.497,W,0,00,,,M,,M,,*52", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.1,0.8,0.6*3F", - "$GPRMC,113705.568,V,4154.933,N,08002.497,W,86.0,-0.05,220721,,E*66", - "$GPGGA,113706.568,4154.933,N,08002.497,W,0,00,0.8,,M,,M,,*73", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.0,0.4*36", - "$GPRMC,113708.568,V,4154.935,N,08002.498,W,55.1,-0.10,220721,,E*69", - "$GPGGA,113709.568,4154.935,N,08002.498,W,0,00,0.0,,M,,M,,*7D", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.2,0.8*3C", - "$GPRMC,113711.568,V,4154.937,N,08002.498,W,95.0,-0.10,220721,,E*6E", - "$GPGGA,113712.568,4154.937,N,08002.498,W,0,00,0.2,,M,,M,,*77", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.7,0.6,0.3*32", - "$GPRMC,113714.568,V,4154.939,N,08002.498,W,28.0,-0.07,220721,,E*65", - "$GPGGA,113715.568,4154.939,N,08002.498,W,0,00,0.6,,M,,M,,*7A", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,1.0,1.0,0.5*34", - "$GPRMC,113717.568,V,4154.940,N,08002.498,W,30.1,0.03,220721,,E*49", - "$GPGGA,113718.568,4154.940,N,08002.498,W,0,00,1.0,,M,,M,,*7E", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.5,0.1,0.2*36", - "$GPRMC,113720.568,V,4154.942,N,08002.498,W,0.2,-0.02,220721,,E*53", - "$GPGGA,113721.568,4154.942,N,08002.498,W,0,00,0.1,,M,,M,,*76", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.5,0.7*30", - "$GPRMC,113723.568,V,4154.944,N,08002.498,W,53.6,0.05,220721,,E*4E", - "$GPGGA,113724.568,4154.944,N,08002.498,W,0,00,0.5,,M,,M,,*71", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,1.0,0.6,0.1*37", - "$GPRMC,113726.568,V,4154.946,N,08002.498,W,76.6,0.04,220721,,E*4F", - "$GPGGA,113727.568,4154.946,N,08002.498,W,0,00,0.6,,M,,M,,*73", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.2,0.3,0.7*37", - "$GPRMC,113729.568,V,4154.948,N,08002.497,W,30.9,0.12,220721,,E*4B", - "$GPGGA,113730.568,4154.948,N,08002.497,W,0,00,0.3,,M,,M,,*71", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.5,0.2,0.2*34", - "$GPRMC,113732.568,V,4154.949,N,08002.497,W,47.2,0.20,220721,,E*4A", - "$GPGGA,113733.568,4154.949,N,08002.497,W,0,00,0.2,,M,,M,,*72", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.3,0.8,0.2*39", - "$GPRMC,113735.568,V,4154.951,N,08002.496,W,31.1,0.13,220721,,E*47", - "$GPGGA,113736.568,4154.951,N,08002.496,W,0,00,0.8,,M,,M,,*75", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.6,0.1*35", - "$GPRMC,113738.568,V,4154.953,N,08002.496,W,58.2,0.10,220721,,E*47", - "$GPGGA,113739.568,4154.953,N,08002.496,W,0,00,0.6,,M,,M,,*76", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.6,0.9,0.7*39", - "$GPRMC,113741.568,V,4154.955,N,08002.496,W,88.3,0.03,220721,,E*41", - "$GPGGA,113742.568,4154.955,N,08002.496,W,0,00,0.9,,M,,M,,*73", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.8,0.8,0.1*30", - "$GPRMC,113744.568,V,4154.956,N,08002.496,W,89.3,0.10,220721,,E*44", - "$GPGGA,113745.568,4154.956,N,08002.496,W,0,00,0.8,,M,,M,,*76", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.9,0.2,1.0*3B", - "$GPRMC,113747.568,V,4154.958,N,08002.495,W,99.1,0.14,220721,,E*4D", - "$GPGGA,113748.568,4154.958,N,08002.495,W,0,00,0.2,,M,,M,,*7C", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.1,0.2*35", - "$GPRMC,113750.568,V,4154.960,N,08002.495,W,84.0,0.19,220721,,E*40", - "$GPGGA,113751.568,4154.960,N,08002.495,W,0,00,0.1,,M,,M,,*7C", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.3,1.0,0.5*36", - "$GPRMC,113753.568,V,4154.962,N,08002.495,W,24.0,0.13,220721,,E*41", - "$GPGGA,113754.568,4154.962,N,08002.495,W,0,00,1.0,,M,,M,,*7B", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.8,0.9*37", - "$GPRMC,113756.568,V,4154.963,N,08002.494,W,27.8,0.03,220721,,E*4E", - "$GPGGA,113757.568,4154.963,N,08002.494,W,0,00,0.8,,M,,M,,*71", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.5,0.4,0.7*37" -} - -local badGNSSSdata = { - "$GPRMC,113702.568,V,4154.931,N,08002.497,W,95.5,0.02,220721,,E*48", - "$GPGGA,113703.568,4154.931,N,08002.497,W,0,00,,,M,,M,,*54", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.1,0.8,0.6*33", - "$GPRMC,113720.568,V,4154.942,N,08002.498,W,0.2,-0.02,220721,,E*5F", - "$GPGGA,113721.568,4154.942,N,08002.498,W,0,00,0.1,,M,,M,,*82", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.5,0.7*35", - "$GPRMC,113723.568,V,4154.944,N,08002.498,W,53.6,0.05,220721,,E*5A", - "$GPGGA,113724.568,4154.944,N,08002.498,W,0,00,0.5,,M,,M,,*12", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,1.0,0.6,0.1*35", - "$GPRMC,113726.568,V,4154.946,N,08002.498,W,76.6,0.04,220721,,E*9E", - "$GPGGA,113727.568,4154.946,N,08002.498,W,0,00,0.6,,M,,M,,*94", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.2,0.3,0.7*32", - "$GPRMC,113729.568,V,4154.948,N,08002.497,W,30.9,0.12,220721,,E*9C", - "$GPGGA,113730.568,4154.948,N,08002.497,W,0,00,0.3,,M,,M,,*79", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.5,0.2,0.2*39", - "$GPRMC,113705.568,V,4154.933,N,08002.497,W,86.0,-0.05,220721,,E*90", - "$GPGGA,113706.568,4154.933,N,08002.497,W,0,00,0.8,,M,,M,,*42", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.0,0.4*43", - "$GPRMC,113708.568,V,4154.935,N,08002.498,W,55.1,-0.10,220721,,E*44", - "$GPGGA,113709.568,4154.935,N,08002.498,W,0,00,0.0,,M,,M,,*4A", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.2,0.8*4D", - "$GPRMC,113711.568,V,4154.937,N,08002.498,W,95.0,-0.10,220721,,E*44", - "$GPGGA,113712.568,4154.937,N,08002.498,W,0,00,0.2,,M,,M,,*44", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.7,0.6,0.3*4D", - "$GPRMC,113714.568,V,4154.939,N,08002.498,W,28.0,-0.07,220721,,E*4D", - "$GPGGA,113715.568,4154.939,N,08002.498,W,0,00,0.6,,M,,M,,*4D", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,1.0,1.0,0.5*24", - "$GPRMC,113717.568,V,4154.940,N,08002.498,W,30.1,0.03,220721,,E*59", - "$GPGGA,113718.568,4154.940,N,08002.498,W,0,00,1.0,,M,,M,,*4D", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.5,0.1,0.2*39", - "$GPGGA,113736.568,4154.951,N,08002.496,W,0,00,0.8,,M,,M,,*79", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.6,0.1*39", - "$GPRMC,113738.568,V,4154.953,N,08002.496,W,58.2,0.10,220721,,E*67", - "$GPGGA,113739.568,4154.953,N,08002.496,W,0,00,0.6,,M,,M,,*79", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.6,0.9,0.7*35", - "$GPRMC,113741.568,V,4154.955,N,08002.496,W,88.3,0.03,220721,,E*31", - "$GPGGA,113742.568,4154.955,N,08002.496,W,0,00,0.9,,M,,M,,*33", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.8,0.8,0.1*34", - "$GPRMC,113744.568,V,4154.956,N,08002.496,W,89.3,0.10,220721,,E*34", - "$GPGGA,113745.568,4154.956,N,08002.496,W,0,00,0.8,,M,,M,,*75", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.9,0.2,1.0*4B", - "$GPRMC,113747.568,V,4154.958,N,08002.495,W,99.1,0.14,220721,,E*5D", - "$GPGGA,113748.568,4154.958,N,08002.495,W,0,00,0.2,,M,,M,,*5C", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.1,0.2*55", - "$GPRMC,113750.568,V,4154.960,N,08002.495,W,84.0,0.19,220721,,E*50", - "$GPGGA,113751.568,4154.960,N,08002.495,W,0,00,0.1,,M,,M,,*5C", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.3,1.0,0.5*35", - "$GPRMC,113753.568,V,4154.962,N,08002.495,W,24.0,0.13,220721,,E*51", - "$GPGGA,113754.568,4154.962,N,08002.495,W,0,00,1.0,,M,,M,,*5B", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.8,0.9*35", - "$GPRMC,113756.568,V,4154.963,N,08002.494,W,27.8,0.03,220721,,E*5E", - "$GPGGA,113757.568,4154.963,N,08002.494,W,0,00,0.8,,M,,M,,*51", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.5,0.4,0.7*57" -} - -function testCRC8() - for i = 1, #goodGNSSSdata do - lu.assertEquals(checksum.crc8(goodGNSSSdata[i]), true) - end - for i = 1, #badGNSSSdata do - lu.assertEquals(checksum.crc8(badGNSSSdata[i]), false) - end -end -local a = checksum.crc16("$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.5,0.4,0.7*57") - -function testCRC16() - lu.assertEquals(checksum.crc16(goodGNSSSdata[1]), "E50C") - lu.assertEquals(checksum.crc16(goodGNSSSdata[2]), "CCD5") - lu.assertEquals(checksum.crc16(goodGNSSSdata[3]), "852C") - lu.assertEquals(checksum.crc16(goodGNSSSdata[4]), "EDB5") - lu.assertEquals(checksum.crc16(goodGNSSSdata[5]), "5DF0") - lu.assertEquals(checksum.crc16(goodGNSSSdata[6]), "7B29") - lu.assertEquals(checksum.crc16(goodGNSSSdata[7]), "7CC") -end - -os.exit(lu.LuaUnit.run()) diff --git a/luci-app-gpoint-main/test/gps_test.lua b/luci-app-gpoint-main/test/gps_test.lua deleted file mode 100644 index ac6d2c237..000000000 --- a/luci-app-gpoint-main/test/gps_test.lua +++ /dev/null @@ -1,96 +0,0 @@ -local gps = require("gps_lib") ---local kalman = require("kalman_lib") - -function read_lat_lon() - local file = io.open("/www/kalman_lua/matrix_c_test/testdata/gps_example_1", 'r') - - while file:read() do - local lat, lon = file:read("*n", "*n") - if lat and lon then - return lat, lon - end - end - - file:close() - print("read_lat_lon - OK") -end - -function test_read_lat_long() - local lat, lon = read_lat_lon() - assert(math.abs(lat - 39.315828) < 0.000001) - assert(math.abs(lon - -120.167838) < 0.000001) - for i = 1, 131 do - local lat, lon = read_lat_lon() - end - print("test_read_lat_long - OK") -end - -function test_bearing_north() - local kalman = gps.create_velocity2d(1.0) - for i = 1, 100 do - kalman = gps.update_velocity2d(kalman, i * 0.0001, 0.0, 1.0) - end - - local bearing = gps.get_bearing(kalman) - assert(math.abs(bearing - 0.0) < 0.01) - - local dlat, dlon = gps.get_velocity(kalman) - assert(math.abs(dlat - 0.0001) < 0.00001) - assert(math.abs(dlon) < 0.00001) - print("test_bearing_north - OK") -end - -function test_bearing_east() - local kalman = gps.create_velocity2d(1.0) - for i = 1, 100 do - kalman = gps.update_velocity2d(kalman, 0.0, i * 0.0001, 1.0) - end - - local bearing = gps.get_bearing(kalman) - assert(math.abs(bearing - 90.0) < 0.01) - --At this rate, it takes 10,000 timesteps to travel one longitude - --unit, and thus 3,600,000 timesteps to travel the circumference of - --the earth. Let's say one timestep is a second, so it takes - --3,600,000 seconds, which is 60,000 minutes, which is 1,000 - --hours. Since the earth is about 25000 miles around, this means we - --are traveling at about 25 miles per hour. - local mph = gps.get_mph(kalman) - assert(math.abs(mph - 25.0) < 2.0) - print("test_bearing_east - OK") -end - -function test_bearing_south() - local kalman = gps.create_velocity2d(1.0) - for i = 1, 100 do - kalman = gps.update_velocity2d(kalman, i * -0.0001, 0.0, 1.0) - end - - local bearing = gps.get_bearing(kalman) - assert(math.abs(bearing - 180.0) < 0.01) - print("test_bearing_south - OK") -end - -function test_bearing_west() - local kalman = gps.create_velocity2d(1.0) - for i = 1, 100 do - kalman = gps.update_velocity2d(kalman, 0.0, i * -0.0001, 1.0) - end - - local bearing = gps.get_bearing(kalman) - assert(math.abs(bearing - 270.0) < 0.01) - print("test_bearing_west - OK") -end - -function test_calculate_mph() - local mph = gps.calculate_mph(39.315842, -120.167107, -0.000031, 0.000003); - assert(math.abs(mph - 7.74) < 0.01); - print("test_calculate_mph - OK") -end - --- test start -test_read_lat_long() -test_bearing_north() -test_bearing_east() -test_bearing_south() -test_bearing_west() -test_calculate_mph() \ No newline at end of file diff --git a/luci-app-gpoint-main/test/kalman_test.lua b/luci-app-gpoint-main/test/kalman_test.lua deleted file mode 100644 index a2b5ab674..000000000 --- a/luci-app-gpoint-main/test/kalman_test.lua +++ /dev/null @@ -1,34 +0,0 @@ -local kalman = require("kalman_lib") -local matrix = require("matrix_lib") - --- Test the example of a train moving along a 1-d track -function test_train() - local k = kalman.create(2, 1) - -- The train state is a 2d vector containing position and velocity. - -- Velocity is measured in position units per timestep units. - k.state_transition = matrix.set(k.state_transition, 1.0, 1.0, - 0.0, 1.0) - -- We only observe position - k.observation_model = matrix.set(k.observation_model, 1.0, 0.0) - -- The covariance matrices are blind guesses - k.process_noise_covariance = matrix.set_identity(k.process_noise_covariance) - k.observation_noise_covariance = matrix.set_identity(k.observation_noise_covariance) - -- Our knowledge of the start position is incorrect and unconfident - local deviation = 1000.0 - k.state_estimate = matrix.set(k.state_estimate, 10 * deviation) - k.estimate_covariance = matrix.set_identity(k.estimate_covariance) - k.estimate_covariance = matrix.scale(k.estimate_covariance, deviation * deviation) - - for i = 1, 10 do - k.observation = matrix.set(k.observation, i) - k = kalman.update(k) - end - - - print("estimated position: " .. tostring(k.state_estimate[1][1])) - print("estimated position: " .. tostring(k.state_estimate[2][1])) - -end - -test_train() -print("OK") \ No newline at end of file diff --git a/luci-app-gpoint-main/test/luaunit.lua b/luci-app-gpoint-main/test/luaunit.lua deleted file mode 100644 index 7ac4b0e89..000000000 --- a/luci-app-gpoint-main/test/luaunit.lua +++ /dev/null @@ -1,3452 +0,0 @@ ---[[ - luaunit.lua - -Description: A unit testing framework -Homepage: https://github.com/bluebird75/luaunit -Development by Philippe Fremy -Based on initial work of Ryu, Gwang (http://www.gpgstudy.com/gpgiki/LuaUnit) -License: BSD License, see LICENSE.txt -]]-- - -require("math") -local M={} - --- private exported functions (for testing) -M.private = {} - -M.VERSION='3.4' -M._VERSION=M.VERSION -- For LuaUnit v2 compatibility - --- a version which distinguish between regular Lua and LuaJit -M._LUAVERSION = (jit and jit.version) or _VERSION - ---[[ Some people like assertEquals( actual, expected ) and some people prefer -assertEquals( expected, actual ). -]]-- -M.ORDER_ACTUAL_EXPECTED = true -M.PRINT_TABLE_REF_IN_ERROR_MSG = false -M.LINE_LENGTH = 80 -M.TABLE_DIFF_ANALYSIS_THRESHOLD = 10 -- display deep analysis for more than 10 items -M.LIST_DIFF_ANALYSIS_THRESHOLD = 10 -- display deep analysis for more than 10 items - --- this setting allow to remove entries from the stack-trace, for --- example to hide a call to a framework which would be calling luaunit -M.STRIP_EXTRA_ENTRIES_IN_STACK_TRACE = 0 - ---[[ EPS is meant to help with Lua's floating point math in simple corner -cases like almostEquals(1.1-0.1, 1), which may not work as-is (e.g. on numbers -with rational binary representation) if the user doesn't provide some explicit -error margin. - -The default margin used by almostEquals() in such cases is EPS; and since -Lua may be compiled with different numeric precisions (single vs. double), we -try to select a useful default for it dynamically. Note: If the initial value -is not acceptable, it can be changed by the user to better suit specific needs. - -See also: https://en.wikipedia.org/wiki/Machine_epsilon -]] -M.EPS = 2^-52 -- = machine epsilon for "double", ~2.22E-16 -if math.abs(1.1 - 1 - 0.1) > M.EPS then - -- rounding error is above EPS, assume single precision - M.EPS = 2^-23 -- = machine epsilon for "float", ~1.19E-07 -end - --- set this to false to debug luaunit -local STRIP_LUAUNIT_FROM_STACKTRACE = true - -M.VERBOSITY_DEFAULT = 10 -M.VERBOSITY_LOW = 1 -M.VERBOSITY_QUIET = 0 -M.VERBOSITY_VERBOSE = 20 -M.DEFAULT_DEEP_ANALYSIS = nil -M.FORCE_DEEP_ANALYSIS = true -M.DISABLE_DEEP_ANALYSIS = false - --- set EXPORT_ASSERT_TO_GLOBALS to have all asserts visible as global values --- EXPORT_ASSERT_TO_GLOBALS = true - --- we need to keep a copy of the script args before it is overriden -local cmdline_argv = rawget(_G, "arg") - -M.FAILURE_PREFIX = 'LuaUnit test FAILURE: ' -- prefix string for failed tests -M.SUCCESS_PREFIX = 'LuaUnit test SUCCESS: ' -- prefix string for successful tests finished early -M.SKIP_PREFIX = 'LuaUnit test SKIP: ' -- prefix string for skipped tests - - - -M.USAGE=[[Usage: lua [options] [testname1 [testname2] ... ] -Options: - -h, --help: Print this help - --version: Print version information - -v, --verbose: Increase verbosity - -q, --quiet: Set verbosity to minimum - -e, --error: Stop on first error - -f, --failure: Stop on first failure or error - -s, --shuffle: Shuffle tests before running them - -o, --output OUTPUT: Set output type to OUTPUT - Possible values: text, tap, junit, nil - -n, --name NAME: For junit only, mandatory name of xml file - -r, --repeat NUM: Execute all tests NUM times, e.g. to trig the JIT - -p, --pattern PATTERN: Execute all test names matching the Lua PATTERN - May be repeated to include several patterns - Make sure you escape magic chars like +? with % - -x, --exclude PATTERN: Exclude all test names matching the Lua PATTERN - May be repeated to exclude several patterns - Make sure you escape magic chars like +? with % - testname1, testname2, ... : tests to run in the form of testFunction, - TestClass or TestClass.testMethod - -You may also control LuaUnit options with the following environment variables: -* LUAUNIT_OUTPUT: same as --output -* LUAUNIT_JUNIT_FNAME: same as --name ]] - ----------------------------------------------------------------- --- --- general utility functions --- ----------------------------------------------------------------- - ---[[ Note on catching exit - -I have seen the case where running a big suite of test cases and one of them would -perform a os.exit(0), making the outside world think that the full test suite was executed -successfully. - -This is an attempt to mitigate this problem: we override os.exit() to now let a test -exit the framework while we are running. When we are not running, it behaves normally. -]] - -M.oldOsExit = os.exit -os.exit = function(...) - if M.LuaUnit and #M.LuaUnit.instances ~= 0 then - local msg = [[You are trying to exit but there is still a running instance of LuaUnit. -LuaUnit expects to run until the end before exiting with a complete status of successful/failed tests. - -To force exit LuaUnit while running, please call before os.exit (assuming lu is the luaunit module loaded): - - lu.unregisterCurrentSuite() - -]] - M.private.error_fmt(2, msg) - end - M.oldOsExit(...) -end - -local function pcall_or_abort(func, ...) - -- unpack is a global function for Lua 5.1, otherwise use table.unpack - local unpack = rawget(_G, "unpack") or table.unpack - local result = {pcall(func, ...)} - if not result[1] then - -- an error occurred - print(result[2]) -- error message - print() - print(M.USAGE) - os.exit(-1) - end - return unpack(result, 2) -end - -local crossTypeOrdering = { - number = 1, boolean = 2, string = 3, table = 4, other = 5 -} -local crossTypeComparison = { - number = function(a, b) return a < b end, - string = function(a, b) return a < b end, - other = function(a, b) return tostring(a) < tostring(b) end, -} - -local function crossTypeSort(a, b) - local type_a, type_b = type(a), type(b) - if type_a == type_b then - local func = crossTypeComparison[type_a] or crossTypeComparison.other - return func(a, b) - end - type_a = crossTypeOrdering[type_a] or crossTypeOrdering.other - type_b = crossTypeOrdering[type_b] or crossTypeOrdering.other - return type_a < type_b -end - -local function __genSortedIndex( t ) - -- Returns a sequence consisting of t's keys, sorted. - local sortedIndex = {} - - for key,_ in pairs(t) do - table.insert(sortedIndex, key) - end - - table.sort(sortedIndex, crossTypeSort) - return sortedIndex -end -M.private.__genSortedIndex = __genSortedIndex - -local function sortedNext(state, control) - -- Equivalent of the next() function of table iteration, but returns the - -- keys in sorted order (see __genSortedIndex and crossTypeSort). - -- The state is a temporary variable during iteration and contains the - -- sorted key table (state.sortedIdx). It also stores the last index (into - -- the keys) used by the iteration, to find the next one quickly. - local key - - --print("sortedNext: control = "..tostring(control) ) - if control == nil then - -- start of iteration - state.count = #state.sortedIdx - state.lastIdx = 1 - key = state.sortedIdx[1] - return key, state.t[key] - end - - -- normally, we expect the control variable to match the last key used - if control ~= state.sortedIdx[state.lastIdx] then - -- strange, we have to find the next value by ourselves - -- the key table is sorted in crossTypeSort() order! -> use bisection - local lower, upper = 1, state.count - repeat - state.lastIdx = math.modf((lower + upper) / 2) - key = state.sortedIdx[state.lastIdx] - if key == control then - break -- key found (and thus prev index) - end - if crossTypeSort(key, control) then - -- key < control, continue search "right" (towards upper bound) - lower = state.lastIdx + 1 - else - -- key > control, continue search "left" (towards lower bound) - upper = state.lastIdx - 1 - end - until lower > upper - if lower > upper then -- only true if the key wasn't found, ... - state.lastIdx = state.count -- ... so ensure no match in code below - end - end - - -- proceed by retrieving the next value (or nil) from the sorted keys - state.lastIdx = state.lastIdx + 1 - key = state.sortedIdx[state.lastIdx] - if key then - return key, state.t[key] - end - - -- getting here means returning `nil`, which will end the iteration -end - -local function sortedPairs(tbl) - -- Equivalent of the pairs() function on tables. Allows to iterate in - -- sorted order. As required by "generic for" loops, this will return the - -- iterator (function), an "invariant state", and the initial control value. - -- (see http://www.lua.org/pil/7.2.html) - return sortedNext, {t = tbl, sortedIdx = __genSortedIndex(tbl)}, nil -end -M.private.sortedPairs = sortedPairs - --- seed the random with a strongly varying seed -math.randomseed(math.floor((os.clock()*1E11) / 100)) -- add /100 OpenWrt some bug - -local function randomizeTable( t ) - -- randomize the item orders of the table t - for i = #t, 2, -1 do - local j = math.random(i) - if i ~= j then - t[i], t[j] = t[j], t[i] - end - end -end -M.private.randomizeTable = randomizeTable - -local function strsplit(delimiter, text) --- Split text into a list consisting of the strings in text, separated --- by strings matching delimiter (which may _NOT_ be a pattern). --- Example: strsplit(", ", "Anna, Bob, Charlie, Dolores") - if delimiter == "" or delimiter == nil then -- this would result in endless loops - error("delimiter is nil or empty string!") - end - if text == nil then - return nil - end - - local list, pos, first, last = {}, 1 - while true do - first, last = text:find(delimiter, pos, true) - if first then -- found? - table.insert(list, text:sub(pos, first - 1)) - pos = last + 1 - else - table.insert(list, text:sub(pos)) - break - end - end - return list -end -M.private.strsplit = strsplit - -local function hasNewLine( s ) - -- return true if s has a newline - return (string.find(s, '\n', 1, true) ~= nil) -end -M.private.hasNewLine = hasNewLine - -local function prefixString( prefix, s ) - -- Prefix all the lines of s with prefix - return prefix .. string.gsub(s, '\n', '\n' .. prefix) -end -M.private.prefixString = prefixString - -local function strMatch(s, pattern, start, final ) - -- return true if s matches completely the pattern from index start to index end - -- return false in every other cases - -- if start is nil, matches from the beginning of the string - -- if final is nil, matches to the end of the string - start = start or 1 - final = final or string.len(s) - - local foundStart, foundEnd = string.find(s, pattern, start, false) - return foundStart == start and foundEnd == final -end -M.private.strMatch = strMatch - -local function patternFilter(patterns, expr) - -- Run `expr` through the inclusion and exclusion rules defined in patterns - -- and return true if expr shall be included, false for excluded. - -- Inclusion pattern are defined as normal patterns, exclusions - -- patterns start with `!` and are followed by a normal pattern - - -- result: nil = UNKNOWN (not matched yet), true = ACCEPT, false = REJECT - -- default: true if no explicit "include" is found, set to false otherwise - local default, result = true, nil - - if patterns ~= nil then - for _, pattern in ipairs(patterns) do - local exclude = pattern:sub(1,1) == '!' - if exclude then - pattern = pattern:sub(2) - else - -- at least one include pattern specified, a match is required - default = false - end - -- print('pattern: ',pattern) - -- print('exclude: ',exclude) - -- print('default: ',default) - - if string.find(expr, pattern) then - -- set result to false when excluding, true otherwise - result = not exclude - end - end - end - - if result ~= nil then - return result - end - return default -end -M.private.patternFilter = patternFilter - -local function xmlEscape( s ) - -- Return s escaped for XML attributes - -- escapes table: - -- " " - -- ' ' - -- < < - -- > > - -- & & - - return string.gsub( s, '.', { - ['&'] = "&", - ['"'] = """, - ["'"] = "'", - ['<'] = "<", - ['>'] = ">", - } ) -end -M.private.xmlEscape = xmlEscape - -local function xmlCDataEscape( s ) - -- Return s escaped for CData section, escapes: "]]>" - return string.gsub( s, ']]>', ']]>' ) -end -M.private.xmlCDataEscape = xmlCDataEscape - - -local function lstrip( s ) - --[[Return s with all leading white spaces and tabs removed]] - local idx = 0 - while idx < s:len() do - idx = idx + 1 - local c = s:sub(idx,idx) - if c ~= ' ' and c ~= '\t' then - break - end - end - return s:sub(idx) -end -M.private.lstrip = lstrip - -local function extractFileLineInfo( s ) - --[[ From a string in the form "(leading spaces) dir1/dir2\dir3\file.lua:linenb: msg" - - Return the "file.lua:linenb" information - ]] - local s2 = lstrip(s) - local firstColon = s2:find(':', 1, true) - if firstColon == nil then - -- string is not in the format file:line: - return s - end - local secondColon = s2:find(':', firstColon+1, true) - if secondColon == nil then - -- string is not in the format file:line: - return s - end - - return s2:sub(1, secondColon-1) -end -M.private.extractFileLineInfo = extractFileLineInfo - - -local function stripLuaunitTrace2( stackTrace, errMsg ) - --[[ - -- Example of a traceback: - < - [C]: in function 'xpcall' - ./luaunit.lua:1449: in function 'protectedCall' - ./luaunit.lua:1508: in function 'execOneFunction' - ./luaunit.lua:1596: in function 'runSuiteByInstances' - ./luaunit.lua:1660: in function 'runSuiteByNames' - ./luaunit.lua:1736: in function 'runSuite' - example_with_luaunit.lua:140: in main chunk - [C]: in ?>> - error message: <> - - Other example: - < - [C]: in function 'xpcall' - ./luaunit.lua:1517: in function 'protectedCall' - ./luaunit.lua:1578: in function 'execOneFunction' - ./luaunit.lua:1677: in function 'runSuiteByInstances' - ./luaunit.lua:1730: in function 'runSuiteByNames' - ./luaunit.lua:1806: in function 'runSuite' - example_with_luaunit.lua:140: in main chunk - [C]: in ?>> - error message: <> - - < - [C]: in function 'xpcall' - luaunit2/luaunit.lua:1532: in function 'protectedCall' - luaunit2/luaunit.lua:1591: in function 'execOneFunction' - luaunit2/luaunit.lua:1679: in function 'runSuiteByInstances' - luaunit2/luaunit.lua:1743: in function 'runSuiteByNames' - luaunit2/luaunit.lua:1819: in function 'runSuite' - luaunit2/example_with_luaunit.lua:140: in main chunk - [C]: in ?>> - error message: <> - - - -- first line is "stack traceback": KEEP - -- next line may be luaunit line: REMOVE - -- next lines are call in the program under testOk: REMOVE - -- next lines are calls from luaunit to call the program under test: KEEP - - -- Strategy: - -- keep first line - -- remove lines that are part of luaunit - -- kepp lines until we hit a luaunit line - - The strategy for stripping is: - * keep first line "stack traceback:" - * part1: - * analyse all lines of the stack from bottom to top of the stack (first line to last line) - * extract the "file:line:" part of the line - * compare it with the "file:line" part of the error message - * if it does not match strip the line - * if it matches, keep the line and move to part 2 - * part2: - * anything NOT starting with luaunit.lua is the interesting part of the stack trace - * anything starting again with luaunit.lua is part of the test launcher and should be stripped out - ]] - - local function isLuaunitInternalLine( s ) - -- return true if line of stack trace comes from inside luaunit - return s:find('[/\\]luaunit%.lua:%d+: ') ~= nil - end - - -- print( '<<'..stackTrace..'>>' ) - - local t = strsplit( '\n', stackTrace ) - -- print( prettystr(t) ) - - local idx = 2 - - local errMsgFileLine = extractFileLineInfo(errMsg) - -- print('emfi="'..errMsgFileLine..'"') - - -- remove lines that are still part of luaunit - while t[idx] and extractFileLineInfo(t[idx]) ~= errMsgFileLine do - -- print('Removing : '..t[idx] ) - table.remove(t, idx) - end - - -- keep lines until we hit luaunit again - while t[idx] and (not isLuaunitInternalLine(t[idx])) do - -- print('Keeping : '..t[idx] ) - idx = idx + 1 - end - - -- remove remaining luaunit lines - while t[idx] do - -- print('Removing2 : '..t[idx] ) - table.remove(t, idx) - end - - -- print( prettystr(t) ) - return table.concat( t, '\n') - -end -M.private.stripLuaunitTrace2 = stripLuaunitTrace2 - - -local function prettystr_sub(v, indentLevel, printTableRefs, cycleDetectTable ) - local type_v = type(v) - if "string" == type_v then - -- use clever delimiters according to content: - -- enclose with single quotes if string contains ", but no ' - if v:find('"', 1, true) and not v:find("'", 1, true) then - return "'" .. v .. "'" - end - -- use double quotes otherwise, escape embedded " - return '"' .. v:gsub('"', '\\"') .. '"' - - elseif "table" == type_v then - --if v.__class__ then - -- return string.gsub( tostring(v), 'table', v.__class__ ) - --end - return M.private._table_tostring(v, indentLevel, printTableRefs, cycleDetectTable) - - elseif "number" == type_v then - -- eliminate differences in formatting between various Lua versions - if v ~= v then - return "#NaN" -- "not a number" - end - if v == math.huge then - return "#Inf" -- "infinite" - end - if v == -math.huge then - return "-#Inf" - end - if _VERSION == "Lua 5.3" then - local i = math.tointeger(v) - if i then - return tostring(i) - end - end - end - - return tostring(v) -end - -local function prettystr( v ) - --[[ Pretty string conversion, to display the full content of a variable of any type. - - * string are enclosed with " by default, or with ' if string contains a " - * tables are expanded to show their full content, with indentation in case of nested tables - ]]-- - local cycleDetectTable = {} - local s = prettystr_sub(v, 1, M.PRINT_TABLE_REF_IN_ERROR_MSG, cycleDetectTable) - if cycleDetectTable.detected and not M.PRINT_TABLE_REF_IN_ERROR_MSG then - -- some table contain recursive references, - -- so we must recompute the value by including all table references - -- else the result looks like crap - cycleDetectTable = {} - s = prettystr_sub(v, 1, true, cycleDetectTable) - end - return s -end -M.prettystr = prettystr - -function M.adjust_err_msg_with_iter( err_msg, iter_msg ) - --[[ Adjust the error message err_msg: trim the FAILURE_PREFIX or SUCCESS_PREFIX information if needed, - add the iteration message if any and return the result. - - err_msg: string, error message captured with pcall - iter_msg: a string describing the current iteration ("iteration N") or nil - if there is no iteration in this test. - - Returns: (new_err_msg, test_status) - new_err_msg: string, adjusted error message, or nil in case of success - test_status: M.NodeStatus.FAIL, SUCCESS or ERROR according to the information - contained in the error message. - ]] - if iter_msg then - iter_msg = iter_msg..', ' - else - iter_msg = '' - end - - local RE_FILE_LINE = '.*:%d+: ' - - -- error message is not necessarily a string, - -- so convert the value to string with prettystr() - if type( err_msg ) ~= 'string' then - err_msg = prettystr( err_msg ) - end - - if (err_msg:find( M.SUCCESS_PREFIX ) == 1) or err_msg:match( '('..RE_FILE_LINE..')' .. M.SUCCESS_PREFIX .. ".*" ) then - -- test finished early with success() - return nil, M.NodeStatus.SUCCESS - end - - if (err_msg:find( M.SKIP_PREFIX ) == 1) or (err_msg:match( '('..RE_FILE_LINE..')' .. M.SKIP_PREFIX .. ".*" ) ~= nil) then - -- substitute prefix by iteration message - err_msg = err_msg:gsub('.*'..M.SKIP_PREFIX, iter_msg, 1) - -- print("failure detected") - return err_msg, M.NodeStatus.SKIP - end - - if (err_msg:find( M.FAILURE_PREFIX ) == 1) or (err_msg:match( '('..RE_FILE_LINE..')' .. M.FAILURE_PREFIX .. ".*" ) ~= nil) then - -- substitute prefix by iteration message - err_msg = err_msg:gsub(M.FAILURE_PREFIX, iter_msg, 1) - -- print("failure detected") - return err_msg, M.NodeStatus.FAIL - end - - - - -- print("error detected") - -- regular error, not a failure - if iter_msg then - local match - -- "./test\\test_luaunit.lua:2241: some error msg - match = err_msg:match( '(.*:%d+: ).*' ) - if match then - err_msg = err_msg:gsub( match, match .. iter_msg ) - else - -- no file:line: infromation, just add the iteration info at the beginning of the line - err_msg = iter_msg .. err_msg - end - end - return err_msg, M.NodeStatus.ERROR -end - -local function tryMismatchFormatting( table_a, table_b, doDeepAnalysis, margin ) - --[[ - Prepares a nice error message when comparing tables, performing a deeper - analysis. - - Arguments: - * table_a, table_b: tables to be compared - * doDeepAnalysis: - M.DEFAULT_DEEP_ANALYSIS: (the default if not specified) perform deep analysis only for big lists and big dictionnaries - M.FORCE_DEEP_ANALYSIS : always perform deep analysis - M.DISABLE_DEEP_ANALYSIS: never perform deep analysis - * margin: supplied only for almost equality - - Returns: {success, result} - * success: false if deep analysis could not be performed - in this case, just use standard assertion message - * result: if success is true, a multi-line string with deep analysis of the two lists - ]] - - -- check if table_a & table_b are suitable for deep analysis - if type(table_a) ~= 'table' or type(table_b) ~= 'table' then - return false - end - - if doDeepAnalysis == M.DISABLE_DEEP_ANALYSIS then - return false - end - - local len_a, len_b, isPureList = #table_a, #table_b, true - - for k1, v1 in pairs(table_a) do - if type(k1) ~= 'number' or k1 > len_a then - -- this table a mapping - isPureList = false - break - end - end - - if isPureList then - for k2, v2 in pairs(table_b) do - if type(k2) ~= 'number' or k2 > len_b then - -- this table a mapping - isPureList = false - break - end - end - end - - if isPureList and math.min(len_a, len_b) < M.LIST_DIFF_ANALYSIS_THRESHOLD then - if not (doDeepAnalysis == M.FORCE_DEEP_ANALYSIS) then - return false - end - end - - if isPureList then - return M.private.mismatchFormattingPureList( table_a, table_b, margin ) - else - -- only work on mapping for the moment - -- return M.private.mismatchFormattingMapping( table_a, table_b, doDeepAnalysis ) - return false - end -end -M.private.tryMismatchFormatting = tryMismatchFormatting - -local function getTaTbDescr() - if not M.ORDER_ACTUAL_EXPECTED then - return 'expected', 'actual' - end - return 'actual', 'expected' -end - -local function extendWithStrFmt( res, ... ) - table.insert( res, string.format( ... ) ) -end - -local function mismatchFormattingMapping( table_a, table_b, doDeepAnalysis ) - --[[ - Prepares a nice error message when comparing tables which are not pure lists, performing a deeper - analysis. - - Returns: {success, result} - * success: false if deep analysis could not be performed - in this case, just use standard assertion message - * result: if success is true, a multi-line string with deep analysis of the two lists - ]] - - -- disable for the moment - --[[ - local result = {} - local descrTa, descrTb = getTaTbDescr() - - local keysCommon = {} - local keysOnlyTa = {} - local keysOnlyTb = {} - local keysDiffTaTb = {} - - local k, v - - for k,v in pairs( table_a ) do - if is_equal( v, table_b[k] ) then - table.insert( keysCommon, k ) - else - if table_b[k] == nil then - table.insert( keysOnlyTa, k ) - else - table.insert( keysDiffTaTb, k ) - end - end - end - - for k,v in pairs( table_b ) do - if not is_equal( v, table_a[k] ) and table_a[k] == nil then - table.insert( keysOnlyTb, k ) - end - end - - local len_a = #keysCommon + #keysDiffTaTb + #keysOnlyTa - local len_b = #keysCommon + #keysDiffTaTb + #keysOnlyTb - local limited_display = (len_a < 5 or len_b < 5) - - if math.min(len_a, len_b) < M.TABLE_DIFF_ANALYSIS_THRESHOLD then - return false - end - - if not limited_display then - if len_a == len_b then - extendWithStrFmt( result, 'Table A (%s) and B (%s) both have %d items', descrTa, descrTb, len_a ) - else - extendWithStrFmt( result, 'Table A (%s) has %d items and table B (%s) has %d items', descrTa, len_a, descrTb, len_b ) - end - - if #keysCommon == 0 and #keysDiffTaTb == 0 then - table.insert( result, 'Table A and B have no keys in common, they are totally different') - else - local s_other = 'other ' - if #keysCommon then - extendWithStrFmt( result, 'Table A and B have %d identical items', #keysCommon ) - else - table.insert( result, 'Table A and B have no identical items' ) - s_other = '' - end - - if #keysDiffTaTb ~= 0 then - result[#result] = string.format( '%s and %d items differing present in both tables', result[#result], #keysDiffTaTb) - else - result[#result] = string.format( '%s and no %sitems differing present in both tables', result[#result], s_other, #keysDiffTaTb) - end - end - - extendWithStrFmt( result, 'Table A has %d keys not present in table B and table B has %d keys not present in table A', #keysOnlyTa, #keysOnlyTb ) - end - - local function keytostring(k) - if "string" == type(k) and k:match("^[_%a][_%w]*$") then - return k - end - return prettystr(k) - end - - if #keysDiffTaTb ~= 0 then - table.insert( result, 'Items differing in A and B:') - for k,v in sortedPairs( keysDiffTaTb ) do - extendWithStrFmt( result, ' - A[%s]: %s', keytostring(v), prettystr(table_a[v]) ) - extendWithStrFmt( result, ' + B[%s]: %s', keytostring(v), prettystr(table_b[v]) ) - end - end - - if #keysOnlyTa ~= 0 then - table.insert( result, 'Items only in table A:' ) - for k,v in sortedPairs( keysOnlyTa ) do - extendWithStrFmt( result, ' - A[%s]: %s', keytostring(v), prettystr(table_a[v]) ) - end - end - - if #keysOnlyTb ~= 0 then - table.insert( result, 'Items only in table B:' ) - for k,v in sortedPairs( keysOnlyTb ) do - extendWithStrFmt( result, ' + B[%s]: %s', keytostring(v), prettystr(table_b[v]) ) - end - end - - if #keysCommon ~= 0 then - table.insert( result, 'Items common to A and B:') - for k,v in sortedPairs( keysCommon ) do - extendWithStrFmt( result, ' = A and B [%s]: %s', keytostring(v), prettystr(table_a[v]) ) - end - end - - return true, table.concat( result, '\n') - ]] -end -M.private.mismatchFormattingMapping = mismatchFormattingMapping - -local function mismatchFormattingPureList( table_a, table_b, margin ) - --[[ - Prepares a nice error message when comparing tables which are lists, performing a deeper - analysis. - - margin is supplied only for almost equality - - Returns: {success, result} - * success: false if deep analysis could not be performed - in this case, just use standard assertion message - * result: if success is true, a multi-line string with deep analysis of the two lists - ]] - local result, descrTa, descrTb = {}, getTaTbDescr() - - local len_a, len_b, refa, refb = #table_a, #table_b, '', '' - if M.PRINT_TABLE_REF_IN_ERROR_MSG then - refa, refb = string.format( '<%s> ', M.private.table_ref(table_a)), string.format('<%s> ', M.private.table_ref(table_b) ) - end - local longest, shortest = math.max(len_a, len_b), math.min(len_a, len_b) - local deltalv = longest - shortest - - local commonUntil = shortest - for i = 1, shortest do - if not M.private.is_table_equals(table_a[i], table_b[i], margin) then - commonUntil = i - 1 - break - end - end - - local commonBackTo = shortest - 1 - for i = 0, shortest - 1 do - if not M.private.is_table_equals(table_a[len_a-i], table_b[len_b-i], margin) then - commonBackTo = i - 1 - break - end - end - - - table.insert( result, 'List difference analysis:' ) - if len_a == len_b then - -- TODO: handle expected/actual naming - extendWithStrFmt( result, '* lists %sA (%s) and %sB (%s) have the same size', refa, descrTa, refb, descrTb ) - else - extendWithStrFmt( result, '* list sizes differ: list %sA (%s) has %d items, list %sB (%s) has %d items', refa, descrTa, len_a, refb, descrTb, len_b ) - end - - extendWithStrFmt( result, '* lists A and B start differing at index %d', commonUntil+1 ) - if commonBackTo >= 0 then - if deltalv > 0 then - extendWithStrFmt( result, '* lists A and B are equal again from index %d for A, %d for B', len_a-commonBackTo, len_b-commonBackTo ) - else - extendWithStrFmt( result, '* lists A and B are equal again from index %d', len_a-commonBackTo ) - end - end - - local function insertABValue(ai, bi) - bi = bi or ai - if M.private.is_table_equals( table_a[ai], table_b[bi], margin) then - return extendWithStrFmt( result, ' = A[%d], B[%d]: %s', ai, bi, prettystr(table_a[ai]) ) - else - extendWithStrFmt( result, ' - A[%d]: %s', ai, prettystr(table_a[ai])) - extendWithStrFmt( result, ' + B[%d]: %s', bi, prettystr(table_b[bi])) - end - end - - -- common parts to list A & B, at the beginning - if commonUntil > 0 then - table.insert( result, '* Common parts:' ) - for i = 1, commonUntil do - insertABValue( i ) - end - end - - -- diffing parts to list A & B - if commonUntil < shortest - commonBackTo - 1 then - table.insert( result, '* Differing parts:' ) - for i = commonUntil + 1, shortest - commonBackTo - 1 do - insertABValue( i ) - end - end - - -- display indexes of one list, with no match on other list - if shortest - commonBackTo <= longest - commonBackTo - 1 then - table.insert( result, '* Present only in one list:' ) - for i = shortest - commonBackTo, longest - commonBackTo - 1 do - if len_a > len_b then - extendWithStrFmt( result, ' - A[%d]: %s', i, prettystr(table_a[i]) ) - -- table.insert( result, '+ (no matching B index)') - else - -- table.insert( result, '- no matching A index') - extendWithStrFmt( result, ' + B[%d]: %s', i, prettystr(table_b[i]) ) - end - end - end - - -- common parts to list A & B, at the end - if commonBackTo >= 0 then - table.insert( result, '* Common parts at the end of the lists' ) - for i = longest - commonBackTo, longest do - if len_a > len_b then - insertABValue( i, i-deltalv ) - else - insertABValue( i-deltalv, i ) - end - end - end - - return true, table.concat( result, '\n') -end -M.private.mismatchFormattingPureList = mismatchFormattingPureList - -local function prettystrPairs(value1, value2, suffix_a, suffix_b) - --[[ - This function helps with the recurring task of constructing the "expected - vs. actual" error messages. It takes two arbitrary values and formats - corresponding strings with prettystr(). - - To keep the (possibly complex) output more readable in case the resulting - strings contain line breaks, they get automatically prefixed with additional - newlines. Both suffixes are optional (default to empty strings), and get - appended to the "value1" string. "suffix_a" is used if line breaks were - encountered, "suffix_b" otherwise. - - Returns the two formatted strings (including padding/newlines). - ]] - local str1, str2 = prettystr(value1), prettystr(value2) - if hasNewLine(str1) or hasNewLine(str2) then - -- line break(s) detected, add padding - return "\n" .. str1 .. (suffix_a or ""), "\n" .. str2 - end - return str1 .. (suffix_b or ""), str2 -end -M.private.prettystrPairs = prettystrPairs - -local UNKNOWN_REF = 'table 00-unknown ref' -local ref_generator = { value=1, [UNKNOWN_REF]=0 } - -local function table_ref( t ) - -- return the default tostring() for tables, with the table ID, even if the table has a metatable - -- with the __tostring converter - local ref = '' - local mt = getmetatable( t ) - if mt == nil then - ref = tostring(t) - else - local success, result - success, result = pcall(setmetatable, t, nil) - if not success then - -- protected table, if __tostring is defined, we can - -- not get the reference. And we can not know in advance. - ref = tostring(t) - if not ref:match( 'table: 0?x?[%x]+' ) then - return UNKNOWN_REF - end - else - ref = tostring(t) - setmetatable( t, mt ) - end - end - -- strip the "table: " part - ref = ref:sub(8) - if ref ~= UNKNOWN_REF and ref_generator[ref] == nil then - -- Create a new reference number - ref_generator[ref] = ref_generator.value - ref_generator.value = ref_generator.value+1 - end - if M.PRINT_TABLE_REF_IN_ERROR_MSG then - return string.format('table %02d-%s', ref_generator[ref], ref) - else - return string.format('table %02d', ref_generator[ref]) - end -end -M.private.table_ref = table_ref - -local TABLE_TOSTRING_SEP = ", " -local TABLE_TOSTRING_SEP_LEN = string.len(TABLE_TOSTRING_SEP) - -local function _table_tostring( tbl, indentLevel, printTableRefs, cycleDetectTable ) - printTableRefs = printTableRefs or M.PRINT_TABLE_REF_IN_ERROR_MSG - cycleDetectTable = cycleDetectTable or {} - cycleDetectTable[tbl] = true - - local result, dispOnMultLines = {}, false - - -- like prettystr but do not enclose with "" if the string is just alphanumerical - -- this is better for displaying table keys who are often simple strings - local function keytostring(k) - if "string" == type(k) and k:match("^[_%a][_%w]*$") then - return k - end - return prettystr_sub(k, indentLevel+1, printTableRefs, cycleDetectTable) - end - - local mt = getmetatable( tbl ) - - if mt and mt.__tostring then - -- if table has a __tostring() function in its metatable, use it to display the table - -- else, compute a regular table - result = tostring(tbl) - if type(result) ~= 'string' then - return string.format( '', prettystr(result) ) - end - result = strsplit( '\n', result ) - return M.private._table_tostring_format_multiline_string( result, indentLevel ) - - else - -- no metatable, compute the table representation - - local entry, count, seq_index = nil, 0, 1 - for k, v in sortedPairs( tbl ) do - - -- key part - if k == seq_index then - -- for the sequential part of tables, we'll skip the "=" output - entry = '' - seq_index = seq_index + 1 - elseif cycleDetectTable[k] then - -- recursion in the key detected - cycleDetectTable.detected = true - entry = "<"..table_ref(k)..">=" - else - entry = keytostring(k) .. "=" - end - - -- value part - if cycleDetectTable[v] then - -- recursion in the value detected! - cycleDetectTable.detected = true - entry = entry .. "<"..table_ref(v)..">" - else - entry = entry .. - prettystr_sub( v, indentLevel+1, printTableRefs, cycleDetectTable ) - end - count = count + 1 - result[count] = entry - end - return M.private._table_tostring_format_result( tbl, result, indentLevel, printTableRefs ) - end - -end -M.private._table_tostring = _table_tostring -- prettystr_sub() needs it - -local function _table_tostring_format_multiline_string( tbl_str, indentLevel ) - local indentString = '\n'..string.rep(" ", indentLevel - 1) - return table.concat( tbl_str, indentString ) - -end -M.private._table_tostring_format_multiline_string = _table_tostring_format_multiline_string - - -local function _table_tostring_format_result( tbl, result, indentLevel, printTableRefs ) - -- final function called in _table_to_string() to format the resulting list of - -- string describing the table. - - local dispOnMultLines = false - - -- set dispOnMultLines to true if the maximum LINE_LENGTH would be exceeded with the values - local totalLength = 0 - for k, v in ipairs( result ) do - totalLength = totalLength + string.len( v ) - if totalLength >= M.LINE_LENGTH then - dispOnMultLines = true - break - end - end - - -- set dispOnMultLines to true if the max LINE_LENGTH would be exceeded - -- with the values and the separators. - if not dispOnMultLines then - -- adjust with length of separator(s): - -- two items need 1 sep, three items two seps, ... plus len of '{}' - if #result > 0 then - totalLength = totalLength + TABLE_TOSTRING_SEP_LEN * (#result - 1) - end - dispOnMultLines = (totalLength + 2 >= M.LINE_LENGTH) - end - - -- now reformat the result table (currently holding element strings) - if dispOnMultLines then - local indentString = string.rep(" ", indentLevel - 1) - result = { - "{\n ", - indentString, - table.concat(result, ",\n " .. indentString), - "\n", - indentString, - "}" - } - else - result = {"{", table.concat(result, TABLE_TOSTRING_SEP), "}"} - end - if printTableRefs then - table.insert(result, 1, "<"..table_ref(tbl).."> ") -- prepend table ref - end - return table.concat(result) -end -M.private._table_tostring_format_result = _table_tostring_format_result -- prettystr_sub() needs it - -local function table_findkeyof(t, element) - -- Return the key k of the given element in table t, so that t[k] == element - -- (or `nil` if element is not present within t). Note that we use our - -- 'general' is_equal comparison for matching, so this function should - -- handle table-type elements gracefully and consistently. - if type(t) == "table" then - for k, v in pairs(t) do - if M.private.is_table_equals(v, element) then - return k - end - end - end - return nil -end - -local function _is_table_items_equals(actual, expected ) - local type_a, type_e = type(actual), type(expected) - - if type_a ~= type_e then - return false - - elseif (type_a == 'table') --[[and (type_e == 'table')]] then - for k, v in pairs(actual) do - if table_findkeyof(expected, v) == nil then - return false -- v not contained in expected - end - end - for k, v in pairs(expected) do - if table_findkeyof(actual, v) == nil then - return false -- v not contained in actual - end - end - return true - - elseif actual ~= expected then - return false - end - - return true -end - ---[[ -This is a specialized metatable to help with the bookkeeping of recursions -in _is_table_equals(). It provides an __index table that implements utility -functions for easier management of the table. The "cached" method queries -the state of a specific (actual,expected) pair; and the "store" method sets -this state to the given value. The state of pairs not "seen" / visited is -assumed to be `nil`. -]] -local _recursion_cache_MT = { - __index = { - -- Return the cached value for an (actual,expected) pair (or `nil`) - cached = function(t, actual, expected) - local subtable = t[actual] or {} - return subtable[expected] - end, - - -- Store cached value for a specific (actual,expected) pair. - -- Returns the value, so it's easy to use for a "tailcall" (return ...). - store = function(t, actual, expected, value, asymmetric) - local subtable = t[actual] - if not subtable then - subtable = {} - t[actual] = subtable - end - subtable[expected] = value - - -- Unless explicitly marked "asymmetric": Consider the recursion - -- on (expected,actual) to be equivalent to (actual,expected) by - -- default, and thus cache the value for both. - if not asymmetric then - t:store(expected, actual, value, true) - end - - return value - end - } -} - -local function _is_table_equals(actual, expected, cycleDetectTable, marginForAlmostEqual) - --[[Returns true if both table are equal. - - If argument marginForAlmostEqual is suppied, number comparison is done using alomstEqual instead - of strict equality. - - cycleDetectTable is an internal argument used during recursion on tables. - ]] - --print('_is_table_equals( \n '..prettystr(actual)..'\n , '..prettystr(expected).. - -- '\n , '..prettystr(cycleDetectTable)..'\n , '..prettystr(marginForAlmostEqual)..' )') - - local type_a, type_e = type(actual), type(expected) - - if type_a ~= type_e then - return false -- different types won't match - end - - if type_a == 'number' then - if marginForAlmostEqual ~= nil then - return M.almostEquals(actual, expected, marginForAlmostEqual) - else - return actual == expected - end - elseif type_a ~= 'table' then - -- other types compare directly - return actual == expected - end - - cycleDetectTable = cycleDetectTable or { actual={}, expected={} } - if cycleDetectTable.actual[ actual ] then - -- oh, we hit a cycle in actual - if cycleDetectTable.expected[ expected ] then - -- uh, we hit a cycle at the same time in expected - -- so the two tables have similar structure - return true - end - - -- cycle was hit only in actual, the structure differs from expected - return false - end - - if cycleDetectTable.expected[ expected ] then - -- no cycle in actual, but cycle in expected - -- the structure differ - return false - end - - -- at this point, no table cycle detected, we are - -- seeing this table for the first time - - -- mark the cycle detection - cycleDetectTable.actual[ actual ] = true - cycleDetectTable.expected[ expected ] = true - - - local actualKeysMatched = {} - for k, v in pairs(actual) do - actualKeysMatched[k] = true -- Keep track of matched keys - if not _is_table_equals(v, expected[k], cycleDetectTable, marginForAlmostEqual) then - -- table differs on this key - -- clear the cycle detection before returning - cycleDetectTable.actual[ actual ] = nil - cycleDetectTable.expected[ expected ] = nil - return false - end - end - - for k, v in pairs(expected) do - if not actualKeysMatched[k] then - -- Found a key that we did not see in "actual" -> mismatch - -- clear the cycle detection before returning - cycleDetectTable.actual[ actual ] = nil - cycleDetectTable.expected[ expected ] = nil - return false - end - -- Otherwise actual[k] was already matched against v = expected[k]. - end - - -- all key match, we have a match ! - cycleDetectTable.actual[ actual ] = nil - cycleDetectTable.expected[ expected ] = nil - return true -end -M.private._is_table_equals = _is_table_equals - -local function failure(main_msg, extra_msg_or_nil, level) - -- raise an error indicating a test failure - -- for error() compatibility we adjust "level" here (by +1), to report the - -- calling context - local msg - if type(extra_msg_or_nil) == 'string' and extra_msg_or_nil:len() > 0 then - msg = extra_msg_or_nil .. '\n' .. main_msg - else - msg = main_msg - end - error(M.FAILURE_PREFIX .. msg, (level or 1) + 1 + M.STRIP_EXTRA_ENTRIES_IN_STACK_TRACE) -end - -local function is_table_equals(actual, expected, marginForAlmostEqual) - return _is_table_equals(actual, expected, nil, marginForAlmostEqual) -end -M.private.is_table_equals = is_table_equals - -local function fail_fmt(level, extra_msg_or_nil, ...) - -- failure with printf-style formatted message and given error level - failure(string.format(...), extra_msg_or_nil, (level or 1) + 1) -end -M.private.fail_fmt = fail_fmt - -local function error_fmt(level, ...) - -- printf-style error() - error(string.format(...), (level or 1) + 1 + M.STRIP_EXTRA_ENTRIES_IN_STACK_TRACE) -end -M.private.error_fmt = error_fmt - ----------------------------------------------------------------- --- --- assertions --- ----------------------------------------------------------------- - -local function errorMsgEquality(actual, expected, doDeepAnalysis, margin) - -- margin is supplied only for almost equal verification - - if not M.ORDER_ACTUAL_EXPECTED then - expected, actual = actual, expected - end - if type(expected) == 'string' or type(expected) == 'table' then - local strExpected, strActual = prettystrPairs(expected, actual) - local result = string.format("expected: %s\nactual: %s", strExpected, strActual) - if margin then - result = result .. '\nwere not equal by the margin of: '..prettystr(margin) - end - - -- extend with mismatch analysis if possible: - local success, mismatchResult - success, mismatchResult = tryMismatchFormatting( actual, expected, doDeepAnalysis, margin ) - if success then - result = table.concat( { result, mismatchResult }, '\n' ) - end - return result - end - return string.format("expected: %s, actual: %s", - prettystr(expected), prettystr(actual)) -end - -function M.assertError(f, ...) - -- assert that calling f with the arguments will raise an error - -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error - if pcall( f, ... ) then - failure( "Expected an error when calling function but no error generated", nil, 2 ) - end -end - -function M.fail( msg ) - -- stops a test due to a failure - failure( msg, nil, 2 ) -end - -function M.failIf( cond, msg ) - -- Fails a test with "msg" if condition is true - if cond then - failure( msg, nil, 2 ) - end -end - -function M.skip(msg) - -- skip a running test - error_fmt(2, M.SKIP_PREFIX .. msg) -end - -function M.skipIf( cond, msg ) - -- skip a running test if condition is met - if cond then - error_fmt(2, M.SKIP_PREFIX .. msg) - end -end - -function M.runOnlyIf( cond, msg ) - -- continue a running test if condition is met, else skip it - if not cond then - error_fmt(2, M.SKIP_PREFIX .. prettystr(msg)) - end -end - -function M.success() - -- stops a test with a success - error_fmt(2, M.SUCCESS_PREFIX) -end - -function M.successIf( cond ) - -- stops a test with a success if condition is met - if cond then - error_fmt(2, M.SUCCESS_PREFIX) - end -end - - ------------------------------------------------------------------- --- Equality assertions ------------------------------------------------------------------- - -function M.assertEquals(actual, expected, extra_msg_or_nil, doDeepAnalysis) - if type(actual) == 'table' and type(expected) == 'table' then - if not is_table_equals(actual, expected) then - failure( errorMsgEquality(actual, expected, doDeepAnalysis), extra_msg_or_nil, 2 ) - end - elseif type(actual) ~= type(expected) then - failure( errorMsgEquality(actual, expected), extra_msg_or_nil, 2 ) - elseif actual ~= expected then - failure( errorMsgEquality(actual, expected), extra_msg_or_nil, 2 ) - end -end - -function M.almostEquals( actual, expected, margin ) - if type(actual) ~= 'number' or type(expected) ~= 'number' or type(margin) ~= 'number' then - error_fmt(3, 'almostEquals: must supply only number arguments.\nArguments supplied: %s, %s, %s', - prettystr(actual), prettystr(expected), prettystr(margin)) - end - if margin < 0 then - error_fmt(3, 'almostEquals: margin must not be negative, current value is ' .. margin) - end - return math.abs(expected - actual) <= margin -end - -function M.assertAlmostEquals( actual, expected, margin, extra_msg_or_nil ) - -- check that two floats are close by margin - margin = margin or M.EPS - if type(margin) ~= 'number' then - error_fmt(2, 'almostEquals: margin must be a number, not %s', prettystr(margin)) - end - - if type(actual) == 'table' and type(expected) == 'table' then - -- handle almost equals for table - if not is_table_equals(actual, expected, margin) then - failure( errorMsgEquality(actual, expected, nil, margin), extra_msg_or_nil, 2 ) - end - elseif type(actual) == 'number' and type(expected) == 'number' and type(margin) == 'number' then - if not M.almostEquals(actual, expected, margin) then - if not M.ORDER_ACTUAL_EXPECTED then - expected, actual = actual, expected - end - local delta = math.abs(actual - expected) - fail_fmt(2, extra_msg_or_nil, 'Values are not almost equal\n' .. - 'Actual: %s, expected: %s, delta %s above margin of %s', - actual, expected, delta, margin) - end - else - error_fmt(3, 'almostEquals: must supply only number or table arguments.\nArguments supplied: %s, %s, %s', - prettystr(actual), prettystr(expected), prettystr(margin)) - end -end - -function M.assertNotEquals(actual, expected, extra_msg_or_nil) - if type(actual) ~= type(expected) then - return - end - - if type(actual) == 'table' and type(expected) == 'table' then - if not is_table_equals(actual, expected) then - return - end - elseif actual ~= expected then - return - end - fail_fmt(2, extra_msg_or_nil, 'Received the not expected value: %s', prettystr(actual)) -end - -function M.assertNotAlmostEquals( actual, expected, margin, extra_msg_or_nil ) - -- check that two floats are not close by margin - margin = margin or M.EPS - if M.almostEquals(actual, expected, margin) then - if not M.ORDER_ACTUAL_EXPECTED then - expected, actual = actual, expected - end - local delta = math.abs(actual - expected) - fail_fmt(2, extra_msg_or_nil, 'Values are almost equal\nActual: %s, expected: %s' .. - ', delta %s below margin of %s', - actual, expected, delta, margin) - end -end - -function M.assertItemsEquals(actual, expected, extra_msg_or_nil) - -- checks that the items of table expected - -- are contained in table actual. Warning, this function - -- is at least O(n^2) - if not _is_table_items_equals(actual, expected ) then - expected, actual = prettystrPairs(expected, actual) - fail_fmt(2, extra_msg_or_nil, 'Content of the tables are not identical:\nExpected: %s\nActual: %s', - expected, actual) - end -end - ------------------------------------------------------------------- --- String assertion ------------------------------------------------------------------- - -function M.assertStrContains( str, sub, isPattern, extra_msg_or_nil ) - -- this relies on lua string.find function - -- a string always contains the empty string - -- assert( type(str) == 'string', 'Argument 1 of assertStrContains() should be a string.' ) ) - -- assert( type(sub) == 'string', 'Argument 2 of assertStrContains() should be a string.' ) ) - if not string.find(str, sub, 1, not isPattern) then - sub, str = prettystrPairs(sub, str, '\n') - fail_fmt(2, extra_msg_or_nil, 'Could not find %s %s in string %s', - isPattern and 'pattern' or 'substring', sub, str) - end -end - -function M.assertStrIContains( str, sub, extra_msg_or_nil ) - -- this relies on lua string.find function - -- a string always contains the empty string - if not string.find(str:lower(), sub:lower(), 1, true) then - sub, str = prettystrPairs(sub, str, '\n') - fail_fmt(2, extra_msg_or_nil, 'Could not find (case insensitively) substring %s in string %s', - sub, str) - end -end - -function M.assertNotStrContains( str, sub, isPattern, extra_msg_or_nil ) - -- this relies on lua string.find function - -- a string always contains the empty string - if string.find(str, sub, 1, not isPattern) then - sub, str = prettystrPairs(sub, str, '\n') - fail_fmt(2, extra_msg_or_nil, 'Found the not expected %s %s in string %s', - isPattern and 'pattern' or 'substring', sub, str) - end -end - -function M.assertNotStrIContains( str, sub, extra_msg_or_nil ) - -- this relies on lua string.find function - -- a string always contains the empty string - if string.find(str:lower(), sub:lower(), 1, true) then - sub, str = prettystrPairs(sub, str, '\n') - fail_fmt(2, extra_msg_or_nil, 'Found (case insensitively) the not expected substring %s in string %s', - sub, str) - end -end - -function M.assertStrMatches( str, pattern, start, final, extra_msg_or_nil ) - -- Verify a full match for the string - if not strMatch( str, pattern, start, final ) then - pattern, str = prettystrPairs(pattern, str, '\n') - fail_fmt(2, extra_msg_or_nil, 'Could not match pattern %s with string %s', - pattern, str) - end -end - -local function _assertErrorMsgEquals( stripFileAndLine, expectedMsg, func, ... ) - local no_error, error_msg = pcall( func, ... ) - if no_error then - failure( 'No error generated when calling function but expected error: '..M.prettystr(expectedMsg), nil, 3 ) - end - if type(expectedMsg) == "string" and type(error_msg) ~= "string" then - -- table are converted to string automatically - error_msg = tostring(error_msg) - end - local differ = false - if stripFileAndLine then - if error_msg:gsub("^.+:%d+: ", "") ~= expectedMsg then - differ = true - end - else - if error_msg ~= expectedMsg then - local tr = type(error_msg) - local te = type(expectedMsg) - if te == 'table' then - if tr ~= 'table' then - differ = true - else - local ok = pcall(M.assertItemsEquals, error_msg, expectedMsg) - if not ok then - differ = true - end - end - else - differ = true - end - end - end - - if differ then - error_msg, expectedMsg = prettystrPairs(error_msg, expectedMsg) - fail_fmt(3, nil, 'Error message expected: %s\nError message received: %s\n', - expectedMsg, error_msg) - end -end - -function M.assertErrorMsgEquals( expectedMsg, func, ... ) - -- assert that calling f with the arguments will raise an error - -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error - _assertErrorMsgEquals(false, expectedMsg, func, ...) -end - -function M.assertErrorMsgContentEquals(expectedMsg, func, ...) - _assertErrorMsgEquals(true, expectedMsg, func, ...) -end - -function M.assertErrorMsgContains( partialMsg, func, ... ) - -- assert that calling f with the arguments will raise an error - -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error - local no_error, error_msg = pcall( func, ... ) - if no_error then - failure( 'No error generated when calling function but expected error containing: '..prettystr(partialMsg), nil, 2 ) - end - if type(error_msg) ~= "string" then - error_msg = tostring(error_msg) - end - if not string.find( error_msg, partialMsg, nil, true ) then - error_msg, partialMsg = prettystrPairs(error_msg, partialMsg) - fail_fmt(2, nil, 'Error message does not contain: %s\nError message received: %s\n', - partialMsg, error_msg) - end -end - -function M.assertErrorMsgMatches( expectedMsg, func, ... ) - -- assert that calling f with the arguments will raise an error - -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error - local no_error, error_msg = pcall( func, ... ) - if no_error then - failure( 'No error generated when calling function but expected error matching: "'..expectedMsg..'"', nil, 2 ) - end - if type(error_msg) ~= "string" then - error_msg = tostring(error_msg) - end - if not strMatch( error_msg, expectedMsg ) then - expectedMsg, error_msg = prettystrPairs(expectedMsg, error_msg) - fail_fmt(2, nil, 'Error message does not match pattern: %s\nError message received: %s\n', - expectedMsg, error_msg) - end -end - ------------------------------------------------------------------- --- Type assertions ------------------------------------------------------------------- - -function M.assertEvalToTrue(value, extra_msg_or_nil) - if not value then - failure("expected: a value evaluating to true, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertEvalToFalse(value, extra_msg_or_nil) - if value then - failure("expected: false or nil, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertIsTrue(value, extra_msg_or_nil) - if value ~= true then - failure("expected: true, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertNotIsTrue(value, extra_msg_or_nil) - if value == true then - failure("expected: not true, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertIsFalse(value, extra_msg_or_nil) - if value ~= false then - failure("expected: false, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertNotIsFalse(value, extra_msg_or_nil) - if value == false then - failure("expected: not false, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertIsNil(value, extra_msg_or_nil) - if value ~= nil then - failure("expected: nil, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertNotIsNil(value, extra_msg_or_nil) - if value == nil then - failure("expected: not nil, actual: nil", extra_msg_or_nil, 2) - end -end - ---[[ -Add type assertion functions to the module table M. Each of these functions -takes a single parameter "value", and checks that its Lua type matches the -expected string (derived from the function name): - -M.assertIsXxx(value) -> ensure that type(value) conforms to "xxx" -]] -for _, funcName in ipairs( - {'assertIsNumber', 'assertIsString', 'assertIsTable', 'assertIsBoolean', - 'assertIsFunction', 'assertIsUserdata', 'assertIsThread'} -) do - local typeExpected = funcName:match("^assertIs([A-Z]%a*)$") - -- Lua type() always returns lowercase, also make sure the match() succeeded - typeExpected = typeExpected and typeExpected:lower() - or error("bad function name '"..funcName.."' for type assertion") - - M[funcName] = function(value, extra_msg_or_nil) - if type(value) ~= typeExpected then - if type(value) == 'nil' then - fail_fmt(2, extra_msg_or_nil, 'expected: a %s value, actual: nil', - typeExpected, type(value), prettystrPairs(value)) - else - fail_fmt(2, extra_msg_or_nil, 'expected: a %s value, actual: type %s, value %s', - typeExpected, type(value), prettystrPairs(value)) - end - end - end -end - ---[[ -Add shortcuts for verifying type of a variable, without failure (luaunit v2 compatibility) -M.isXxx(value) -> returns true if type(value) conforms to "xxx" -]] -for _, typeExpected in ipairs( - {'Number', 'String', 'Table', 'Boolean', - 'Function', 'Userdata', 'Thread', 'Nil' } -) do - local typeExpectedLower = typeExpected:lower() - local isType = function(value) - return (type(value) == typeExpectedLower) - end - M['is'..typeExpected] = isType - M['is_'..typeExpectedLower] = isType -end - ---[[ -Add non-type assertion functions to the module table M. Each of these functions -takes a single parameter "value", and checks that its Lua type differs from the -expected string (derived from the function name): - -M.assertNotIsXxx(value) -> ensure that type(value) is not "xxx" -]] -for _, funcName in ipairs( - {'assertNotIsNumber', 'assertNotIsString', 'assertNotIsTable', 'assertNotIsBoolean', - 'assertNotIsFunction', 'assertNotIsUserdata', 'assertNotIsThread'} -) do - local typeUnexpected = funcName:match("^assertNotIs([A-Z]%a*)$") - -- Lua type() always returns lowercase, also make sure the match() succeeded - typeUnexpected = typeUnexpected and typeUnexpected:lower() - or error("bad function name '"..funcName.."' for type assertion") - - M[funcName] = function(value, extra_msg_or_nil) - if type(value) == typeUnexpected then - fail_fmt(2, extra_msg_or_nil, 'expected: not a %s type, actual: value %s', - typeUnexpected, prettystrPairs(value)) - end - end -end - -function M.assertIs(actual, expected, extra_msg_or_nil) - if actual ~= expected then - if not M.ORDER_ACTUAL_EXPECTED then - actual, expected = expected, actual - end - local old_print_table_ref_in_error_msg = M.PRINT_TABLE_REF_IN_ERROR_MSG - M.PRINT_TABLE_REF_IN_ERROR_MSG = true - expected, actual = prettystrPairs(expected, actual, '\n', '') - M.PRINT_TABLE_REF_IN_ERROR_MSG = old_print_table_ref_in_error_msg - fail_fmt(2, extra_msg_or_nil, 'expected and actual object should not be different\nExpected: %s\nReceived: %s', - expected, actual) - end -end - -function M.assertNotIs(actual, expected, extra_msg_or_nil) - if actual == expected then - local old_print_table_ref_in_error_msg = M.PRINT_TABLE_REF_IN_ERROR_MSG - M.PRINT_TABLE_REF_IN_ERROR_MSG = true - local s_expected - if not M.ORDER_ACTUAL_EXPECTED then - s_expected = prettystrPairs(actual) - else - s_expected = prettystrPairs(expected) - end - M.PRINT_TABLE_REF_IN_ERROR_MSG = old_print_table_ref_in_error_msg - fail_fmt(2, extra_msg_or_nil, 'expected and actual object should be different: %s', s_expected ) - end -end - - ------------------------------------------------------------------- --- Scientific assertions ------------------------------------------------------------------- - - -function M.assertIsNaN(value, extra_msg_or_nil) - if type(value) ~= "number" or value == value then - failure("expected: NaN, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertNotIsNaN(value, extra_msg_or_nil) - if type(value) == "number" and value ~= value then - failure("expected: not NaN, actual: NaN", extra_msg_or_nil, 2) - end -end - -function M.assertIsInf(value, extra_msg_or_nil) - if type(value) ~= "number" or math.abs(value) ~= math.huge then - failure("expected: #Inf, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertIsPlusInf(value, extra_msg_or_nil) - if type(value) ~= "number" or value ~= math.huge then - failure("expected: #Inf, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertIsMinusInf(value, extra_msg_or_nil) - if type(value) ~= "number" or value ~= -math.huge then - failure("expected: -#Inf, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertNotIsPlusInf(value, extra_msg_or_nil) - if type(value) == "number" and value == math.huge then - failure("expected: not #Inf, actual: #Inf", extra_msg_or_nil, 2) - end -end - -function M.assertNotIsMinusInf(value, extra_msg_or_nil) - if type(value) == "number" and value == -math.huge then - failure("expected: not -#Inf, actual: -#Inf", extra_msg_or_nil, 2) - end -end - -function M.assertNotIsInf(value, extra_msg_or_nil) - if type(value) == "number" and math.abs(value) == math.huge then - failure("expected: not infinity, actual: " .. prettystr(value), extra_msg_or_nil, 2) - end -end - -function M.assertIsPlusZero(value, extra_msg_or_nil) - if type(value) ~= 'number' or value ~= 0 then - failure("expected: +0.0, actual: " ..prettystr(value), extra_msg_or_nil, 2) - else if (1/value == -math.huge) then - -- more precise error diagnosis - failure("expected: +0.0, actual: -0.0", extra_msg_or_nil, 2) - else if (1/value ~= math.huge) then - -- strange, case should have already been covered - failure("expected: +0.0, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end - end - end -end - -function M.assertIsMinusZero(value, extra_msg_or_nil) - if type(value) ~= 'number' or value ~= 0 then - failure("expected: -0.0, actual: " ..prettystr(value), extra_msg_or_nil, 2) - else if (1/value == math.huge) then - -- more precise error diagnosis - failure("expected: -0.0, actual: +0.0", extra_msg_or_nil, 2) - else if (1/value ~= -math.huge) then - -- strange, case should have already been covered - failure("expected: -0.0, actual: " ..prettystr(value), extra_msg_or_nil, 2) - end - end - end -end - -function M.assertNotIsPlusZero(value, extra_msg_or_nil) - if type(value) == 'number' and (1/value == math.huge) then - failure("expected: not +0.0, actual: +0.0", extra_msg_or_nil, 2) - end -end - -function M.assertNotIsMinusZero(value, extra_msg_or_nil) - if type(value) == 'number' and (1/value == -math.huge) then - failure("expected: not -0.0, actual: -0.0", extra_msg_or_nil, 2) - end -end - -function M.assertTableContains(t, expected, extra_msg_or_nil) - -- checks that table t contains the expected element - if table_findkeyof(t, expected) == nil then - t, expected = prettystrPairs(t, expected) - fail_fmt(2, extra_msg_or_nil, 'Table %s does NOT contain the expected element %s', - t, expected) - end -end - -function M.assertNotTableContains(t, expected, extra_msg_or_nil) - -- checks that table t doesn't contain the expected element - local k = table_findkeyof(t, expected) - if k ~= nil then - t, expected = prettystrPairs(t, expected) - fail_fmt(2, extra_msg_or_nil, 'Table %s DOES contain the unwanted element %s (at key %s)', - t, expected, prettystr(k)) - end -end - ----------------------------------------------------------------- --- Compatibility layer ----------------------------------------------------------------- - --- for compatibility with LuaUnit v2.x -function M.wrapFunctions() - -- In LuaUnit version <= 2.1 , this function was necessary to include - -- a test function inside the global test suite. Nowadays, the functions - -- are simply run directly as part of the test discovery process. - -- so just do nothing ! - io.stderr:write[[Use of WrapFunctions() is no longer needed. -Just prefix your test function names with "test" or "Test" and they -will be picked up and run by LuaUnit. -]] -end - -local list_of_funcs = { - -- { official function name , alias } - - -- general assertions - { 'assertEquals' , 'assert_equals' }, - { 'assertItemsEquals' , 'assert_items_equals' }, - { 'assertNotEquals' , 'assert_not_equals' }, - { 'assertAlmostEquals' , 'assert_almost_equals' }, - { 'assertNotAlmostEquals' , 'assert_not_almost_equals' }, - { 'assertEvalToTrue' , 'assert_eval_to_true' }, - { 'assertEvalToFalse' , 'assert_eval_to_false' }, - { 'assertStrContains' , 'assert_str_contains' }, - { 'assertStrIContains' , 'assert_str_icontains' }, - { 'assertNotStrContains' , 'assert_not_str_contains' }, - { 'assertNotStrIContains' , 'assert_not_str_icontains' }, - { 'assertStrMatches' , 'assert_str_matches' }, - { 'assertError' , 'assert_error' }, - { 'assertErrorMsgEquals' , 'assert_error_msg_equals' }, - { 'assertErrorMsgContains' , 'assert_error_msg_contains' }, - { 'assertErrorMsgMatches' , 'assert_error_msg_matches' }, - { 'assertErrorMsgContentEquals', 'assert_error_msg_content_equals' }, - { 'assertIs' , 'assert_is' }, - { 'assertNotIs' , 'assert_not_is' }, - { 'assertTableContains' , 'assert_table_contains' }, - { 'assertNotTableContains' , 'assert_not_table_contains' }, - { 'wrapFunctions' , 'WrapFunctions' }, - { 'wrapFunctions' , 'wrap_functions' }, - - -- type assertions: assertIsXXX -> assert_is_xxx - { 'assertIsNumber' , 'assert_is_number' }, - { 'assertIsString' , 'assert_is_string' }, - { 'assertIsTable' , 'assert_is_table' }, - { 'assertIsBoolean' , 'assert_is_boolean' }, - { 'assertIsNil' , 'assert_is_nil' }, - { 'assertIsTrue' , 'assert_is_true' }, - { 'assertIsFalse' , 'assert_is_false' }, - { 'assertIsNaN' , 'assert_is_nan' }, - { 'assertIsInf' , 'assert_is_inf' }, - { 'assertIsPlusInf' , 'assert_is_plus_inf' }, - { 'assertIsMinusInf' , 'assert_is_minus_inf' }, - { 'assertIsPlusZero' , 'assert_is_plus_zero' }, - { 'assertIsMinusZero' , 'assert_is_minus_zero' }, - { 'assertIsFunction' , 'assert_is_function' }, - { 'assertIsThread' , 'assert_is_thread' }, - { 'assertIsUserdata' , 'assert_is_userdata' }, - - -- type assertions: assertIsXXX -> assertXxx - { 'assertIsNumber' , 'assertNumber' }, - { 'assertIsString' , 'assertString' }, - { 'assertIsTable' , 'assertTable' }, - { 'assertIsBoolean' , 'assertBoolean' }, - { 'assertIsNil' , 'assertNil' }, - { 'assertIsTrue' , 'assertTrue' }, - { 'assertIsFalse' , 'assertFalse' }, - { 'assertIsNaN' , 'assertNaN' }, - { 'assertIsInf' , 'assertInf' }, - { 'assertIsPlusInf' , 'assertPlusInf' }, - { 'assertIsMinusInf' , 'assertMinusInf' }, - { 'assertIsPlusZero' , 'assertPlusZero' }, - { 'assertIsMinusZero' , 'assertMinusZero'}, - { 'assertIsFunction' , 'assertFunction' }, - { 'assertIsThread' , 'assertThread' }, - { 'assertIsUserdata' , 'assertUserdata' }, - - -- type assertions: assertIsXXX -> assert_xxx (luaunit v2 compat) - { 'assertIsNumber' , 'assert_number' }, - { 'assertIsString' , 'assert_string' }, - { 'assertIsTable' , 'assert_table' }, - { 'assertIsBoolean' , 'assert_boolean' }, - { 'assertIsNil' , 'assert_nil' }, - { 'assertIsTrue' , 'assert_true' }, - { 'assertIsFalse' , 'assert_false' }, - { 'assertIsNaN' , 'assert_nan' }, - { 'assertIsInf' , 'assert_inf' }, - { 'assertIsPlusInf' , 'assert_plus_inf' }, - { 'assertIsMinusInf' , 'assert_minus_inf' }, - { 'assertIsPlusZero' , 'assert_plus_zero' }, - { 'assertIsMinusZero' , 'assert_minus_zero' }, - { 'assertIsFunction' , 'assert_function' }, - { 'assertIsThread' , 'assert_thread' }, - { 'assertIsUserdata' , 'assert_userdata' }, - - -- type assertions: assertNotIsXXX -> assert_not_is_xxx - { 'assertNotIsNumber' , 'assert_not_is_number' }, - { 'assertNotIsString' , 'assert_not_is_string' }, - { 'assertNotIsTable' , 'assert_not_is_table' }, - { 'assertNotIsBoolean' , 'assert_not_is_boolean' }, - { 'assertNotIsNil' , 'assert_not_is_nil' }, - { 'assertNotIsTrue' , 'assert_not_is_true' }, - { 'assertNotIsFalse' , 'assert_not_is_false' }, - { 'assertNotIsNaN' , 'assert_not_is_nan' }, - { 'assertNotIsInf' , 'assert_not_is_inf' }, - { 'assertNotIsPlusInf' , 'assert_not_plus_inf' }, - { 'assertNotIsMinusInf' , 'assert_not_minus_inf' }, - { 'assertNotIsPlusZero' , 'assert_not_plus_zero' }, - { 'assertNotIsMinusZero' , 'assert_not_minus_zero' }, - { 'assertNotIsFunction' , 'assert_not_is_function' }, - { 'assertNotIsThread' , 'assert_not_is_thread' }, - { 'assertNotIsUserdata' , 'assert_not_is_userdata' }, - - -- type assertions: assertNotIsXXX -> assertNotXxx (luaunit v2 compat) - { 'assertNotIsNumber' , 'assertNotNumber' }, - { 'assertNotIsString' , 'assertNotString' }, - { 'assertNotIsTable' , 'assertNotTable' }, - { 'assertNotIsBoolean' , 'assertNotBoolean' }, - { 'assertNotIsNil' , 'assertNotNil' }, - { 'assertNotIsTrue' , 'assertNotTrue' }, - { 'assertNotIsFalse' , 'assertNotFalse' }, - { 'assertNotIsNaN' , 'assertNotNaN' }, - { 'assertNotIsInf' , 'assertNotInf' }, - { 'assertNotIsPlusInf' , 'assertNotPlusInf' }, - { 'assertNotIsMinusInf' , 'assertNotMinusInf' }, - { 'assertNotIsPlusZero' , 'assertNotPlusZero' }, - { 'assertNotIsMinusZero' , 'assertNotMinusZero' }, - { 'assertNotIsFunction' , 'assertNotFunction' }, - { 'assertNotIsThread' , 'assertNotThread' }, - { 'assertNotIsUserdata' , 'assertNotUserdata' }, - - -- type assertions: assertNotIsXXX -> assert_not_xxx - { 'assertNotIsNumber' , 'assert_not_number' }, - { 'assertNotIsString' , 'assert_not_string' }, - { 'assertNotIsTable' , 'assert_not_table' }, - { 'assertNotIsBoolean' , 'assert_not_boolean' }, - { 'assertNotIsNil' , 'assert_not_nil' }, - { 'assertNotIsTrue' , 'assert_not_true' }, - { 'assertNotIsFalse' , 'assert_not_false' }, - { 'assertNotIsNaN' , 'assert_not_nan' }, - { 'assertNotIsInf' , 'assert_not_inf' }, - { 'assertNotIsPlusInf' , 'assert_not_plus_inf' }, - { 'assertNotIsMinusInf' , 'assert_not_minus_inf' }, - { 'assertNotIsPlusZero' , 'assert_not_plus_zero' }, - { 'assertNotIsMinusZero' , 'assert_not_minus_zero' }, - { 'assertNotIsFunction' , 'assert_not_function' }, - { 'assertNotIsThread' , 'assert_not_thread' }, - { 'assertNotIsUserdata' , 'assert_not_userdata' }, - - -- all assertions with Coroutine duplicate Thread assertions - { 'assertIsThread' , 'assertIsCoroutine' }, - { 'assertIsThread' , 'assertCoroutine' }, - { 'assertIsThread' , 'assert_is_coroutine' }, - { 'assertIsThread' , 'assert_coroutine' }, - { 'assertNotIsThread' , 'assertNotIsCoroutine' }, - { 'assertNotIsThread' , 'assertNotCoroutine' }, - { 'assertNotIsThread' , 'assert_not_is_coroutine' }, - { 'assertNotIsThread' , 'assert_not_coroutine' }, -} - --- Create all aliases in M -for _,v in ipairs( list_of_funcs ) do - local funcname, alias = v[1], v[2] - M[alias] = M[funcname] - - if EXPORT_ASSERT_TO_GLOBALS then - _G[funcname] = M[funcname] - _G[alias] = M[funcname] - end -end - ----------------------------------------------------------------- --- --- Outputters --- ----------------------------------------------------------------- - --- A common "base" class for outputters --- For concepts involved (class inheritance) see http://www.lua.org/pil/16.2.html - -local genericOutput = { __class__ = 'genericOutput' } -- class -local genericOutput_MT = { __index = genericOutput } -- metatable -M.genericOutput = genericOutput -- publish, so that custom classes may derive from it - -function genericOutput.new(runner, default_verbosity) - -- runner is the "parent" object controlling the output, usually a LuaUnit instance - local t = { runner = runner } - if runner then - t.result = runner.result - t.verbosity = runner.verbosity or default_verbosity - t.fname = runner.fname - else - t.verbosity = default_verbosity - end - return setmetatable( t, genericOutput_MT) -end - --- abstract ("empty") methods -function genericOutput:startSuite() - -- Called once, when the suite is started -end - -function genericOutput:startClass(className) - -- Called each time a new test class is started -end - -function genericOutput:startTest(testName) - -- called each time a new test is started, right before the setUp() - -- the current test status node is already created and available in: self.result.currentNode -end - -function genericOutput:updateStatus(node) - -- called with status failed or error as soon as the error/failure is encountered - -- this method is NOT called for a successful test because a test is marked as successful by default - -- and does not need to be updated -end - -function genericOutput:endTest(node) - -- called when the test is finished, after the tearDown() method -end - -function genericOutput:endClass() - -- called when executing the class is finished, before moving on to the next class of at the end of the test execution -end - -function genericOutput:endSuite() - -- called at the end of the test suite execution -end - - ----------------------------------------------------------------- --- class TapOutput ----------------------------------------------------------------- - -local TapOutput = genericOutput.new() -- derived class -local TapOutput_MT = { __index = TapOutput } -- metatable -TapOutput.__class__ = 'TapOutput' - - -- For a good reference for TAP format, check: http://testanything.org/tap-specification.html - - function TapOutput.new(runner) - local t = genericOutput.new(runner, M.VERBOSITY_LOW) - return setmetatable( t, TapOutput_MT) - end - function TapOutput:startSuite() - print("1.."..self.result.selectedCount) - print('# Started on '..self.result.startDate) - end - function TapOutput:startClass(className) - if className ~= '[TestFunctions]' then - print('# Starting class: '..className) - end - end - - function TapOutput:updateStatus( node ) - if node:isSkipped() then - io.stdout:write("ok ", self.result.currentTestNumber, "\t# SKIP ", node.msg, "\n" ) - return - end - - io.stdout:write("not ok ", self.result.currentTestNumber, "\t", node.testName, "\n") - if self.verbosity > M.VERBOSITY_LOW then - print( prefixString( '# ', node.msg ) ) - end - if (node:isFailure() or node:isError()) and self.verbosity > M.VERBOSITY_DEFAULT then - print( prefixString( '# ', node.stackTrace ) ) - end - end - - function TapOutput:endTest( node ) - if node:isSuccess() then - io.stdout:write("ok ", self.result.currentTestNumber, "\t", node.testName, "\n") - end - end - - function TapOutput:endSuite() - print( '# '..M.LuaUnit.statusLine( self.result ) ) - return self.result.notSuccessCount - end - - --- class TapOutput end - ----------------------------------------------------------------- --- class JUnitOutput ----------------------------------------------------------------- - --- See directory junitxml for more information about the junit format -local JUnitOutput = genericOutput.new() -- derived class -local JUnitOutput_MT = { __index = JUnitOutput } -- metatable -JUnitOutput.__class__ = 'JUnitOutput' - - function JUnitOutput.new(runner) - local t = genericOutput.new(runner, M.VERBOSITY_LOW) - t.testList = {} - return setmetatable( t, JUnitOutput_MT ) - end - - function JUnitOutput:startSuite() - -- open xml file early to deal with errors - if self.fname == nil then - error('With Junit, an output filename must be supplied with --name!') - end - if string.sub(self.fname,-4) ~= '.xml' then - self.fname = self.fname..'.xml' - end - self.fd = io.open(self.fname, "w") - if self.fd == nil then - error("Could not open file for writing: "..self.fname) - end - - print('# XML output to '..self.fname) - print('# Started on '..self.result.startDate) - end - function JUnitOutput:startClass(className) - if className ~= '[TestFunctions]' then - print('# Starting class: '..className) - end - end - function JUnitOutput:startTest(testName) - print('# Starting test: '..testName) - end - - function JUnitOutput:updateStatus( node ) - if node:isFailure() then - print( '# Failure: ' .. prefixString( '# ', node.msg ):sub(4, nil) ) - -- print('# ' .. node.stackTrace) - elseif node:isError() then - print( '# Error: ' .. prefixString( '# ' , node.msg ):sub(4, nil) ) - -- print('# ' .. node.stackTrace) - end - end - - function JUnitOutput:endSuite() - print( '# '..M.LuaUnit.statusLine(self.result)) - - -- XML file writing - self.fd:write('\n') - self.fd:write('\n') - self.fd:write(string.format( - ' \n', - self.result.runCount, self.result.startIsodate, self.result.duration, self.result.errorCount, self.result.failureCount, self.result.skippedCount )) - self.fd:write(" \n") - self.fd:write(string.format(' \n', _VERSION ) ) - self.fd:write(string.format(' \n', M.VERSION) ) - -- XXX please include system name and version if possible - self.fd:write(" \n") - - for i,node in ipairs(self.result.allTests) do - self.fd:write(string.format(' \n', - node.className, node.testName, node.duration ) ) - if node:isNotSuccess() then - self.fd:write(node:statusXML()) - end - self.fd:write(' \n') - end - - -- Next two lines are needed to validate junit ANT xsd, but really not useful in general: - self.fd:write(' \n') - self.fd:write(' \n') - - self.fd:write(' \n') - self.fd:write('\n') - self.fd:close() - return self.result.notSuccessCount - end - - --- class TapOutput end - ----------------------------------------------------------------- --- class TextOutput ----------------------------------------------------------------- - ---[[ Example of other unit-tests suite text output - --- Python Non verbose: - -For each test: . or F or E - -If some failed tests: - ============== - ERROR / FAILURE: TestName (testfile.testclass) - --------- - Stack trace - - -then -------------- -then "Ran x tests in 0.000s" -then OK or FAILED (failures=1, error=1) - --- Python Verbose: -testname (filename.classname) ... ok -testname (filename.classname) ... FAIL -testname (filename.classname) ... ERROR - -then -------------- -then "Ran x tests in 0.000s" -then OK or FAILED (failures=1, error=1) - --- Ruby: -Started - . - Finished in 0.002695 seconds. - - 1 tests, 2 assertions, 0 failures, 0 errors - --- Ruby: ->> ruby tc_simple_number2.rb -Loaded suite tc_simple_number2 -Started -F.. -Finished in 0.038617 seconds. - - 1) Failure: -test_failure(TestSimpleNumber) [tc_simple_number2.rb:16]: -Adding doesn't work. -<3> expected but was -<4>. - -3 tests, 4 assertions, 1 failures, 0 errors - --- Java Junit -.......F. -Time: 0,003 -There was 1 failure: -1) testCapacity(junit.samples.VectorTest)junit.framework.AssertionFailedError - at junit.samples.VectorTest.testCapacity(VectorTest.java:87) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - -FAILURES!!! -Tests run: 8, Failures: 1, Errors: 0 - - --- Maven - -# mvn test -------------------------------------------------------- - T E S T S -------------------------------------------------------- -Running math.AdditionTest -Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: -0.03 sec <<< FAILURE! - -Results : - -Failed tests: - testLireSymbole(math.AdditionTest) - -Tests run: 2, Failures: 1, Errors: 0, Skipped: 0 - - --- LuaUnit ----- non verbose -* display . or F or E when running tests ----- verbose -* display test name + ok/fail ----- -* blank line -* number) ERROR or FAILURE: TestName - Stack trace -* blank line -* number) ERROR or FAILURE: TestName - Stack trace - -then -------------- -then "Ran x tests in 0.000s (%d not selected, %d skipped)" -then OK or FAILED (failures=1, error=1) - - -]] - -local TextOutput = genericOutput.new() -- derived class -local TextOutput_MT = { __index = TextOutput } -- metatable -TextOutput.__class__ = 'TextOutput' - - function TextOutput.new(runner) - local t = genericOutput.new(runner, M.VERBOSITY_DEFAULT) - t.errorList = {} - return setmetatable( t, TextOutput_MT ) - end - - function TextOutput:startSuite() - if self.verbosity > M.VERBOSITY_DEFAULT then - print( 'Started on '.. self.result.startDate ) - end - end - - function TextOutput:startTest(testName) - if self.verbosity > M.VERBOSITY_DEFAULT then - io.stdout:write( " ", self.result.currentNode.testName, " ... " ) - end - end - - function TextOutput:endTest( node ) - if node:isSuccess() then - if self.verbosity > M.VERBOSITY_DEFAULT then - io.stdout:write("Ok\n") - else - io.stdout:write(".") - io.stdout:flush() - end - else - if self.verbosity > M.VERBOSITY_DEFAULT then - print( node.status ) - print( node.msg ) - --[[ - -- find out when to do this: - if self.verbosity > M.VERBOSITY_DEFAULT then - print( node.stackTrace ) - end - ]] - else - -- write only the first character of status E, F or S - io.stdout:write(string.sub(node.status, 1, 1)) - io.stdout:flush() - end - end - end - - function TextOutput:displayOneFailedTest( index, fail ) - print(index..") "..fail.testName ) - print( fail.msg ) - print( fail.stackTrace ) - print() - end - - function TextOutput:displayErroredTests() - if #self.result.errorTests ~= 0 then - print("Tests with errors:") - print("------------------") - for i, v in ipairs(self.result.errorTests) do - self:displayOneFailedTest(i, v) - end - end - end - - function TextOutput:displayFailedTests() - if #self.result.failedTests ~= 0 then - print("Failed tests:") - print("-------------") - for i, v in ipairs(self.result.failedTests) do - self:displayOneFailedTest(i, v) - end - end - end - - function TextOutput:endSuite() - if self.verbosity > M.VERBOSITY_DEFAULT then - print("=========================================================") - else - print() - end - self:displayErroredTests() - self:displayFailedTests() - print( M.LuaUnit.statusLine( self.result ) ) - if self.result.notSuccessCount == 0 then - print('OK') - end - end - --- class TextOutput end - - ----------------------------------------------------------------- --- class NilOutput ----------------------------------------------------------------- - -local function nopCallable() - --print(42) - return nopCallable -end - -local NilOutput = { __class__ = 'NilOuptut' } -- class -local NilOutput_MT = { __index = nopCallable } -- metatable - -function NilOutput.new(runner) - return setmetatable( { __class__ = 'NilOutput' }, NilOutput_MT ) -end - ----------------------------------------------------------------- --- --- class LuaUnit --- ----------------------------------------------------------------- - -M.LuaUnit = { - outputType = TextOutput, - verbosity = M.VERBOSITY_DEFAULT, - __class__ = 'LuaUnit', - instances = {} -} -local LuaUnit_MT = { __index = M.LuaUnit } - -if EXPORT_ASSERT_TO_GLOBALS then - LuaUnit = M.LuaUnit -end - - function M.LuaUnit.new() - local newInstance = setmetatable( {}, LuaUnit_MT ) - return newInstance - end - - -----------------[[ Utility methods ]]--------------------- - - function M.LuaUnit.asFunction(aObject) - -- return "aObject" if it is a function, and nil otherwise - if 'function' == type(aObject) then - return aObject - end - end - - function M.LuaUnit.splitClassMethod(someName) - --[[ - Return a pair of className, methodName strings for a name in the form - "class.method". If no class part (or separator) is found, will return - nil, someName instead (the latter being unchanged). - - This convention thus also replaces the older isClassMethod() test: - You just have to check for a non-nil className (return) value. - ]] - local separator = string.find(someName, '.', 1, true) - if separator then - return someName:sub(1, separator - 1), someName:sub(separator + 1) - end - return nil, someName - end - - function M.LuaUnit.isMethodTestName( s ) - -- return true is the name matches the name of a test method - -- default rule is that is starts with 'Test' or with 'test' - return string.sub(s, 1, 4):lower() == 'test' - end - - function M.LuaUnit.isTestName( s ) - -- return true is the name matches the name of a test - -- default rule is that is starts with 'Test' or with 'test' - return string.sub(s, 1, 4):lower() == 'test' - end - - function M.LuaUnit.collectTests() - -- return a list of all test names in the global namespace - -- that match LuaUnit.isTestName - - local testNames = {} - for k, _ in pairs(_G) do - if type(k) == "string" and M.LuaUnit.isTestName( k ) then - table.insert( testNames , k ) - end - end - table.sort( testNames ) - return testNames - end - - function M.LuaUnit.parseCmdLine( cmdLine ) - -- parse the command line - -- Supported command line parameters: - -- --verbose, -v: increase verbosity - -- --quiet, -q: silence output - -- --error, -e: treat errors as fatal (quit program) - -- --output, -o, + name: select output type - -- --pattern, -p, + pattern: run test matching pattern, may be repeated - -- --exclude, -x, + pattern: run test not matching pattern, may be repeated - -- --shuffle, -s, : shuffle tests before reunning them - -- --name, -n, + fname: name of output file for junit, default to stdout - -- --repeat, -r, + num: number of times to execute each test - -- [testnames, ...]: run selected test names - -- - -- Returns a table with the following fields: - -- verbosity: nil, M.VERBOSITY_DEFAULT, M.VERBOSITY_QUIET, M.VERBOSITY_VERBOSE - -- output: nil, 'tap', 'junit', 'text', 'nil' - -- testNames: nil or a list of test names to run - -- exeRepeat: num or 1 - -- pattern: nil or a list of patterns - -- exclude: nil or a list of patterns - - local result, state = {}, nil - local SET_OUTPUT = 1 - local SET_PATTERN = 2 - local SET_EXCLUDE = 3 - local SET_FNAME = 4 - local SET_REPEAT = 5 - - if cmdLine == nil then - return result - end - - local function parseOption( option ) - if option == '--help' or option == '-h' then - result['help'] = true - return - elseif option == '--version' then - result['version'] = true - return - elseif option == '--verbose' or option == '-v' then - result['verbosity'] = M.VERBOSITY_VERBOSE - return - elseif option == '--quiet' or option == '-q' then - result['verbosity'] = M.VERBOSITY_QUIET - return - elseif option == '--error' or option == '-e' then - result['quitOnError'] = true - return - elseif option == '--failure' or option == '-f' then - result['quitOnFailure'] = true - return - elseif option == '--shuffle' or option == '-s' then - result['shuffle'] = true - return - elseif option == '--output' or option == '-o' then - state = SET_OUTPUT - return state - elseif option == '--name' or option == '-n' then - state = SET_FNAME - return state - elseif option == '--repeat' or option == '-r' then - state = SET_REPEAT - return state - elseif option == '--pattern' or option == '-p' then - state = SET_PATTERN - return state - elseif option == '--exclude' or option == '-x' then - state = SET_EXCLUDE - return state - end - error('Unknown option: '..option,3) - end - - local function setArg( cmdArg, state ) - if state == SET_OUTPUT then - result['output'] = cmdArg - return - elseif state == SET_FNAME then - result['fname'] = cmdArg - return - elseif state == SET_REPEAT then - result['exeRepeat'] = tonumber(cmdArg) - or error('Malformed -r argument: '..cmdArg) - return - elseif state == SET_PATTERN then - if result['pattern'] then - table.insert( result['pattern'], cmdArg ) - else - result['pattern'] = { cmdArg } - end - return - elseif state == SET_EXCLUDE then - local notArg = '!'..cmdArg - if result['pattern'] then - table.insert( result['pattern'], notArg ) - else - result['pattern'] = { notArg } - end - return - end - error('Unknown parse state: '.. state) - end - - - for i, cmdArg in ipairs(cmdLine) do - if state ~= nil then - setArg( cmdArg, state, result ) - state = nil - else - if cmdArg:sub(1,1) == '-' then - state = parseOption( cmdArg ) - else - if result['testNames'] then - table.insert( result['testNames'], cmdArg ) - else - result['testNames'] = { cmdArg } - end - end - end - end - - if result['help'] then - M.LuaUnit.help() - end - - if result['version'] then - M.LuaUnit.version() - end - - if state ~= nil then - error('Missing argument after '..cmdLine[ #cmdLine ],2 ) - end - - return result - end - - function M.LuaUnit.help() - print(M.USAGE) - os.exit(0) - end - - function M.LuaUnit.version() - print('LuaUnit v'..M.VERSION..' by Philippe Fremy ') - os.exit(0) - end - ----------------------------------------------------------------- --- class NodeStatus ----------------------------------------------------------------- - - local NodeStatus = { __class__ = 'NodeStatus' } -- class - local NodeStatus_MT = { __index = NodeStatus } -- metatable - M.NodeStatus = NodeStatus - - -- values of status - NodeStatus.SUCCESS = 'SUCCESS' - NodeStatus.SKIP = 'SKIP' - NodeStatus.FAIL = 'FAIL' - NodeStatus.ERROR = 'ERROR' - - function NodeStatus.new( number, testName, className ) - -- default constructor, test are PASS by default - local t = { number = number, testName = testName, className = className } - setmetatable( t, NodeStatus_MT ) - t:success() - return t - end - - function NodeStatus:success() - self.status = self.SUCCESS - -- useless because lua does this for us, but it helps me remembering the relevant field names - self.msg = nil - self.stackTrace = nil - end - - function NodeStatus:skip(msg) - self.status = self.SKIP - self.msg = msg - self.stackTrace = nil - end - - function NodeStatus:fail(msg, stackTrace) - self.status = self.FAIL - self.msg = msg - self.stackTrace = stackTrace - end - - function NodeStatus:error(msg, stackTrace) - self.status = self.ERROR - self.msg = msg - self.stackTrace = stackTrace - end - - function NodeStatus:isSuccess() - return self.status == NodeStatus.SUCCESS - end - - function NodeStatus:isNotSuccess() - -- Return true if node is either failure or error or skip - return (self.status == NodeStatus.FAIL or self.status == NodeStatus.ERROR or self.status == NodeStatus.SKIP) - end - - function NodeStatus:isSkipped() - return self.status == NodeStatus.SKIP - end - - function NodeStatus:isFailure() - return self.status == NodeStatus.FAIL - end - - function NodeStatus:isError() - return self.status == NodeStatus.ERROR - end - - function NodeStatus:statusXML() - if self:isError() then - return table.concat( - {' \n', - ' \n'}) - elseif self:isFailure() then - return table.concat( - {' \n', - ' \n'}) - elseif self:isSkipped() then - return table.concat({' ', xmlEscape(self.msg),'\n' } ) - end - return ' \n' -- (not XSD-compliant! normally shouldn't get here) - end - - --------------[[ Output methods ]]------------------------- - - local function conditional_plural(number, singular) - -- returns a grammatically well-formed string "%d " - local suffix = '' - if number ~= 1 then -- use plural - suffix = (singular:sub(-2) == 'ss') and 'es' or 's' - end - return string.format('%d %s%s', number, singular, suffix) - end - - function M.LuaUnit.statusLine(result) - -- return status line string according to results - local s = { - string.format('Ran %d tests in %0.3f seconds', - result.runCount, result.duration), - conditional_plural(result.successCount, 'success'), - } - if result.notSuccessCount > 0 then - if result.failureCount > 0 then - table.insert(s, conditional_plural(result.failureCount, 'failure')) - end - if result.errorCount > 0 then - table.insert(s, conditional_plural(result.errorCount, 'error')) - end - else - table.insert(s, '0 failures') - end - if result.skippedCount > 0 then - table.insert(s, string.format("%d skipped", result.skippedCount)) - end - if result.nonSelectedCount > 0 then - table.insert(s, string.format("%d non-selected", result.nonSelectedCount)) - end - return table.concat(s, ', ') - end - - function M.LuaUnit:startSuite(selectedCount, nonSelectedCount) - self.result = { - selectedCount = selectedCount, - nonSelectedCount = nonSelectedCount, - successCount = 0, - runCount = 0, - currentTestNumber = 0, - currentClassName = "", - currentNode = nil, - suiteStarted = true, - startTime = os.clock(), - startDate = os.date(os.getenv('LUAUNIT_DATEFMT')), - startIsodate = os.date('%Y-%m-%dT%H:%M:%S'), - patternIncludeFilter = self.patternIncludeFilter, - - -- list of test node status - allTests = {}, - failedTests = {}, - errorTests = {}, - skippedTests = {}, - - failureCount = 0, - errorCount = 0, - notSuccessCount = 0, - skippedCount = 0, - } - - self.outputType = self.outputType or TextOutput - self.output = self.outputType.new(self) - self.output:startSuite() - end - - function M.LuaUnit:startClass( className, classInstance ) - self.result.currentClassName = className - self.output:startClass( className ) - self:setupClass( className, classInstance ) - end - - function M.LuaUnit:startTest( testName ) - self.result.currentTestNumber = self.result.currentTestNumber + 1 - self.result.runCount = self.result.runCount + 1 - self.result.currentNode = NodeStatus.new( - self.result.currentTestNumber, - testName, - self.result.currentClassName - ) - self.result.currentNode.startTime = os.clock() - table.insert( self.result.allTests, self.result.currentNode ) - self.output:startTest( testName ) - end - - function M.LuaUnit:updateStatus( err ) - -- "err" is expected to be a table / result from protectedCall() - if err.status == NodeStatus.SUCCESS then - return - end - - local node = self.result.currentNode - - --[[ As a first approach, we will report only one error or one failure for one test. - - However, we can have the case where the test is in failure, and the teardown is in error. - In such case, it's a good idea to report both a failure and an error in the test suite. This is - what Python unittest does for example. However, it mixes up counts so need to be handled carefully: for - example, there could be more (failures + errors) count that tests. What happens to the current node ? - - We will do this more intelligent version later. - ]] - - -- if the node is already in failure/error, just don't report the new error (see above) - if node.status ~= NodeStatus.SUCCESS then - return - end - - if err.status == NodeStatus.FAIL then - node:fail( err.msg, err.trace ) - table.insert( self.result.failedTests, node ) - elseif err.status == NodeStatus.ERROR then - node:error( err.msg, err.trace ) - table.insert( self.result.errorTests, node ) - elseif err.status == NodeStatus.SKIP then - node:skip( err.msg ) - table.insert( self.result.skippedTests, node ) - else - error('No such status: ' .. prettystr(err.status)) - end - - self.output:updateStatus( node ) - end - - function M.LuaUnit:endTest() - local node = self.result.currentNode - -- print( 'endTest() '..prettystr(node)) - -- print( 'endTest() '..prettystr(node:isNotSuccess())) - node.duration = os.clock() - node.startTime - node.startTime = nil - self.output:endTest( node ) - - if node:isSuccess() then - self.result.successCount = self.result.successCount + 1 - elseif node:isError() then - if self.quitOnError or self.quitOnFailure then - -- Runtime error - abort test execution as requested by - -- "--error" option. This is done by setting a special - -- flag that gets handled in internalRunSuiteByInstances(). - print("\nERROR during LuaUnit test execution:\n" .. node.msg) - self.result.aborted = true - end - elseif node:isFailure() then - if self.quitOnFailure then - -- Failure - abort test execution as requested by - -- "--failure" option. This is done by setting a special - -- flag that gets handled in internalRunSuiteByInstances(). - print("\nFailure during LuaUnit test execution:\n" .. node.msg) - self.result.aborted = true - end - elseif node:isSkipped() then - self.result.runCount = self.result.runCount - 1 - else - error('No such node status: ' .. prettystr(node.status)) - end - self.result.currentNode = nil - end - - function M.LuaUnit:endClass() - self:teardownClass( self.lastClassName, self.lastClassInstance ) - self.output:endClass() - end - - function M.LuaUnit:endSuite() - if self.result.suiteStarted == false then - error('LuaUnit:endSuite() -- suite was already ended' ) - end - self.result.duration = os.clock()-self.result.startTime - self.result.suiteStarted = false - - -- Expose test counts for outputter's endSuite(). This could be managed - -- internally instead by using the length of the lists of failed tests - -- but unit tests rely on these fields being present. - self.result.failureCount = #self.result.failedTests - self.result.errorCount = #self.result.errorTests - self.result.notSuccessCount = self.result.failureCount + self.result.errorCount - self.result.skippedCount = #self.result.skippedTests - - self.output:endSuite() - end - - function M.LuaUnit:setOutputType(outputType, fname) - -- Configures LuaUnit runner output - -- outputType is one of: NIL, TAP, JUNIT, TEXT - -- when outputType is junit, the additional argument fname is used to set the name of junit output file - -- for other formats, fname is ignored - if outputType:upper() == "NIL" then - self.outputType = NilOutput - return - end - if outputType:upper() == "TAP" then - self.outputType = TapOutput - return - end - if outputType:upper() == "JUNIT" then - self.outputType = JUnitOutput - if fname then - self.fname = fname - end - return - end - if outputType:upper() == "TEXT" then - self.outputType = TextOutput - return - end - error( 'No such format: '..outputType,2) - end - - --------------[[ Runner ]]----------------- - - function M.LuaUnit:protectedCall(classInstance, methodInstance, prettyFuncName) - -- if classInstance is nil, this is just a function call - -- else, it's method of a class being called. - - local function err_handler(e) - -- transform error into a table, adding the traceback information - return { - status = NodeStatus.ERROR, - msg = e, - trace = string.sub(debug.traceback("", 1), 2) - } - end - - local ok, err - if classInstance then - -- stupid Lua < 5.2 does not allow xpcall with arguments so let's use a workaround - ok, err = xpcall( function () methodInstance(classInstance) end, err_handler ) - else - ok, err = xpcall( function () methodInstance() end, err_handler ) - end - if ok then - return {status = NodeStatus.SUCCESS} - end - -- print('ok="'..prettystr(ok)..'" err="'..prettystr(err)..'"') - - local iter_msg - iter_msg = self.exeRepeat and 'iteration '..self.currentCount - - err.msg, err.status = M.adjust_err_msg_with_iter( err.msg, iter_msg ) - - if err.status == NodeStatus.SUCCESS or err.status == NodeStatus.SKIP then - err.trace = nil - return err - end - - -- reformat / improve the stack trace - if prettyFuncName then -- we do have the real method name - err.trace = err.trace:gsub("in (%a+) 'methodInstance'", "in %1 '"..prettyFuncName.."'") - end - if STRIP_LUAUNIT_FROM_STACKTRACE then - err.trace = stripLuaunitTrace2(err.trace, err.msg) - end - - return err -- return the error "object" (table) - end - - - function M.LuaUnit:execOneFunction(className, methodName, classInstance, methodInstance) - -- When executing a test function, className and classInstance must be nil - -- When executing a class method, all parameters must be set - - if type(methodInstance) ~= 'function' then - self:unregisterSuite() - error( tostring(methodName)..' must be a function, not '..type(methodInstance)) - end - - local prettyFuncName - if className == nil then - className = '[TestFunctions]' - prettyFuncName = methodName - else - prettyFuncName = className..'.'..methodName - end - - if self.lastClassName ~= className then - if self.lastClassName ~= nil then - self:endClass() - end - self:startClass( className, classInstance ) - self.lastClassName = className - self.lastClassInstance = classInstance - end - - self:startTest(prettyFuncName) - - local node = self.result.currentNode - for iter_n = 1, self.exeRepeat or 1 do - if node:isNotSuccess() then - break - end - self.currentCount = iter_n - - -- run setUp first (if any) - if classInstance then - local func = self.asFunction( classInstance.setUp ) or - self.asFunction( classInstance.Setup ) or - self.asFunction( classInstance.setup ) or - self.asFunction( classInstance.SetUp ) - if func then - self:updateStatus(self:protectedCall(classInstance, func, className..'.setUp')) - end - end - - -- run testMethod() - if node:isSuccess() then - self:updateStatus(self:protectedCall(classInstance, methodInstance, prettyFuncName)) - end - - -- lastly, run tearDown (if any) - if classInstance then - local func = self.asFunction( classInstance.tearDown ) or - self.asFunction( classInstance.TearDown ) or - self.asFunction( classInstance.teardown ) or - self.asFunction( classInstance.Teardown ) - if func then - self:updateStatus(self:protectedCall(classInstance, func, className..'.tearDown')) - end - end - end - - self:endTest() - end - - function M.LuaUnit.expandOneClass( result, className, classInstance ) - --[[ - Input: a list of { name, instance }, a class name, a class instance - Ouptut: modify result to add all test method instance in the form: - { className.methodName, classInstance } - ]] - for methodName, methodInstance in sortedPairs(classInstance) do - if M.LuaUnit.asFunction(methodInstance) and M.LuaUnit.isMethodTestName( methodName ) then - table.insert( result, { className..'.'..methodName, classInstance } ) - end - end - end - - function M.LuaUnit.expandClasses( listOfNameAndInst ) - --[[ - -- expand all classes (provided as {className, classInstance}) to a list of {className.methodName, classInstance} - -- functions and methods remain untouched - - Input: a list of { name, instance } - - Output: - * { function name, function instance } : do nothing - * { class.method name, class instance }: do nothing - * { class name, class instance } : add all method names in the form of (className.methodName, classInstance) - ]] - local result = {} - - for i,v in ipairs( listOfNameAndInst ) do - local name, instance = v[1], v[2] - if M.LuaUnit.asFunction(instance) then - table.insert( result, { name, instance } ) - else - if type(instance) ~= 'table' then - error( 'Instance must be a table or a function, not a '..type(instance)..' with value '..prettystr(instance)) - end - local className, methodName = M.LuaUnit.splitClassMethod( name ) - if className then - local methodInstance = instance[methodName] - if methodInstance == nil then - error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) ) - end - table.insert( result, { name, instance } ) - else - M.LuaUnit.expandOneClass( result, name, instance ) - end - end - end - - return result - end - - function M.LuaUnit.applyPatternFilter( patternIncFilter, listOfNameAndInst ) - local included, excluded = {}, {} - for i, v in ipairs( listOfNameAndInst ) do - -- local name, instance = v[1], v[2] - if patternFilter( patternIncFilter, v[1] ) then - table.insert( included, v ) - else - table.insert( excluded, v ) - end - end - return included, excluded - end - - local function getKeyInListWithGlobalFallback( key, listOfNameAndInst ) - local result = nil - for i,v in ipairs( listOfNameAndInst ) do - if(listOfNameAndInst[i][1] == key) then - result = listOfNameAndInst[i][2] - break - end - end - if(not M.LuaUnit.asFunction( result ) ) then - result = _G[key] - end - return result - end - - function M.LuaUnit:setupSuite( listOfNameAndInst ) - local setupSuite = getKeyInListWithGlobalFallback("setupSuite", listOfNameAndInst) - if self.asFunction( setupSuite ) then - self:updateStatus( self:protectedCall( nil, setupSuite, 'setupSuite' ) ) - end - end - - function M.LuaUnit:teardownSuite(listOfNameAndInst) - local teardownSuite = getKeyInListWithGlobalFallback("teardownSuite", listOfNameAndInst) - if self.asFunction( teardownSuite ) then - self:updateStatus( self:protectedCall( nil, teardownSuite, 'teardownSuite') ) - end - end - - function M.LuaUnit:setupClass( className, instance ) - if type( instance ) == 'table' and self.asFunction( instance.setupClass ) then - self:updateStatus( self:protectedCall( instance, instance.setupClass, className..'.setupClass' ) ) - end - end - - function M.LuaUnit:teardownClass( className, instance ) - if type( instance ) == 'table' and self.asFunction( instance.teardownClass ) then - self:updateStatus( self:protectedCall( instance, instance.teardownClass, className..'.teardownClass' ) ) - end - end - - function M.LuaUnit:internalRunSuiteByInstances( listOfNameAndInst ) - --[[ Run an explicit list of tests. Each item of the list must be one of: - * { function name, function instance } - * { class name, class instance } - * { class.method name, class instance } - - This function is internal to LuaUnit. The official API to perform this action is runSuiteByInstances() - ]] - - local expandedList = self.expandClasses( listOfNameAndInst ) - if self.shuffle then - randomizeTable( expandedList ) - end - local filteredList, filteredOutList = self.applyPatternFilter( - self.patternIncludeFilter, expandedList ) - - self:startSuite( #filteredList, #filteredOutList ) - self:setupSuite( listOfNameAndInst ) - - for i,v in ipairs( filteredList ) do - local name, instance = v[1], v[2] - if M.LuaUnit.asFunction(instance) then - self:execOneFunction( nil, name, nil, instance ) - else - -- expandClasses() should have already taken care of sanitizing the input - assert( type(instance) == 'table' ) - local className, methodName = M.LuaUnit.splitClassMethod( name ) - assert( className ~= nil ) - local methodInstance = instance[methodName] - assert(methodInstance ~= nil) - self:execOneFunction( className, methodName, instance, methodInstance ) - end - if self.result.aborted then - break -- "--error" or "--failure" option triggered - end - end - - if self.lastClassName ~= nil then - self:endClass() - end - - self:teardownSuite( listOfNameAndInst ) - self:endSuite() - - if self.result.aborted then - print("LuaUnit ABORTED (as requested by --error or --failure option)") - self:unregisterSuite() - os.exit(-2) - end - end - - function M.LuaUnit:internalRunSuiteByNames( listOfName ) - --[[ Run LuaUnit with a list of generic names, coming either from command-line or from global - namespace analysis. Convert the list into a list of (name, valid instances (table or function)) - and calls internalRunSuiteByInstances. - ]] - - local instanceName, instance - local listOfNameAndInst = {} - - for i,name in ipairs( listOfName ) do - local className, methodName = M.LuaUnit.splitClassMethod( name ) - if className then - instanceName = className - instance = _G[instanceName] - - if instance == nil then - self:unregisterSuite() - error( "No such name in global space: "..instanceName ) - end - - if type(instance) ~= 'table' then - self:unregisterSuite() - error( 'Instance of '..instanceName..' must be a table, not '..type(instance)) - end - - local methodInstance = instance[methodName] - if methodInstance == nil then - self:unregisterSuite() - error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) ) - end - - else - -- for functions and classes - instanceName = name - instance = _G[instanceName] - end - - if instance == nil then - self:unregisterSuite() - error( "No such name in global space: "..instanceName ) - end - - if (type(instance) ~= 'table' and type(instance) ~= 'function') then - self:unregisterSuite() - error( 'Name must match a function or a table: '..instanceName ) - end - - table.insert( listOfNameAndInst, { name, instance } ) - end - - self:internalRunSuiteByInstances( listOfNameAndInst ) - end - - function M.LuaUnit.run(...) - -- Run some specific test classes. - -- If no arguments are passed, run the class names specified on the - -- command line. If no class name is specified on the command line - -- run all classes whose name starts with 'Test' - -- - -- If arguments are passed, they must be strings of the class names - -- that you want to run or generic command line arguments (-o, -p, -v, ...) - local runner = M.LuaUnit.new() - return runner:runSuite(...) - end - - function M.LuaUnit:registerSuite() - -- register the current instance into our global array of instances - -- print('-> Register suite') - M.LuaUnit.instances[ #M.LuaUnit.instances+1 ] = self - end - - function M.unregisterCurrentSuite() - -- force unregister the last registered suite - table.remove(M.LuaUnit.instances, #M.LuaUnit.instances) - end - - function M.LuaUnit:unregisterSuite() - -- print('<- Unregister suite') - -- remove our current instqances from the global array of instances - local instanceIdx = nil - for i, instance in ipairs(M.LuaUnit.instances) do - if instance == self then - instanceIdx = i - break - end - end - - if instanceIdx ~= nil then - table.remove(M.LuaUnit.instances, instanceIdx) - -- print('Unregister done') - end - - end - - function M.LuaUnit:initFromArguments( ... ) - --[[Parses all arguments from either command-line or direct call and set internal - flags of LuaUnit runner according to it. - - Return the list of names which were possibly passed on the command-line or as arguments - ]] - local args = {...} - if type(args[1]) == 'table' and args[1].__class__ == 'LuaUnit' then - -- run was called with the syntax M.LuaUnit:runSuite() - -- we support both M.LuaUnit.run() and M.LuaUnit:run() - -- strip out the first argument self to make it a command-line argument list - table.remove(args,1) - end - - if #args == 0 then - args = cmdline_argv - end - - local options = pcall_or_abort( M.LuaUnit.parseCmdLine, args ) - - -- We expect these option fields to be either `nil` or contain - -- valid values, so it's safe to always copy them directly. - self.verbosity = options.verbosity - self.quitOnError = options.quitOnError - self.quitOnFailure = options.quitOnFailure - - self.exeRepeat = options.exeRepeat - self.patternIncludeFilter = options.pattern - self.shuffle = options.shuffle - - options.output = options.output or os.getenv('LUAUNIT_OUTPUT') - options.fname = options.fname or os.getenv('LUAUNIT_JUNIT_FNAME') - - if options.output then - if options.output:lower() == 'junit' and options.fname == nil then - print('With junit output, a filename must be supplied with -n or --name') - os.exit(-1) - end - pcall_or_abort(self.setOutputType, self, options.output, options.fname) - end - - return options.testNames - end - - function M.LuaUnit:runSuite( ... ) - testNames = self:initFromArguments(...) - self:registerSuite() - self:internalRunSuiteByNames( testNames or M.LuaUnit.collectTests() ) - self:unregisterSuite() - return self.result.notSuccessCount - end - - function M.LuaUnit:runSuiteByInstances( listOfNameAndInst, commandLineArguments ) - --[[ - Run all test functions or tables provided as input. - - Input: a list of { name, instance } - instance can either be a function or a table containing test functions starting with the prefix "test" - - return the number of failures and errors, 0 meaning success - ]] - -- parse the command-line arguments - testNames = self:initFromArguments( commandLineArguments ) - self:registerSuite() - self:internalRunSuiteByInstances( listOfNameAndInst ) - self:unregisterSuite() - return self.result.notSuccessCount - end - - - --- class LuaUnit - --- For compatbility with LuaUnit v2 -M.run = M.LuaUnit.run -M.Run = M.LuaUnit.run - -function M:setVerbosity( verbosity ) - -- set the verbosity value (as integer) - M.LuaUnit.verbosity = verbosity -end -M.set_verbosity = M.setVerbosity -M.SetVerbosity = M.setVerbosity - - -return M \ No newline at end of file diff --git a/luci-app-gpoint-main/test/matrix_test.lua b/luci-app-gpoint-main/test/matrix_test.lua deleted file mode 100644 index a4b615a0c..000000000 --- a/luci-app-gpoint-main/test/matrix_test.lua +++ /dev/null @@ -1,46 +0,0 @@ - -local matrix = require("matrix_lib") - - -function test_copy() - local foo = matrix.create(3, 3) - local bar = matrix.create(3, 3) - foo[1][1] = 1337.0 - bar = matrix.copy(foo, bar) - - assert(bar[1][1] == 1337.0) -end - -function test_inverse() - local foo = matrix.create(4, 4) - foo = matrix.set(foo, 1.0, 2.0, 3.0, 4.0, - 4.0, 1.0, 7.0, 9.0, - 0.0, 0.0, -4.0, -4.0, - 2.3, 3.4, 3.1, 0.0) - - local foo_copy = matrix.copy(foo) - local bar = matrix.create(4, 4) - local identity = matrix.create(4, 4) - - identity = matrix.set_identity(identity) - - matrix.print(foo) - print("--------------") - matrix.print(bar) - print("--------------") - assert(matrix.destructive_invert(foo, bar)) - matrix.print(foo) - print("--------------") - matrix.print(bar) - print("--------------") - - assert(matrix.equal(foo, identity, 0.0001)) - foo = matrix.multiply(foo_copy, bar, foo) - assert(matrix.equal(foo, identity, 0.0001)) - foo = matrix.multiply(bar, foo_copy, foo) - assert(matrix.equal(foo, identity, 0.0001)) -end - -test_copy() -test_inverse() -print("OK") \ No newline at end of file diff --git a/luci-app-gpoint-main/test/nmea_test.lua b/luci-app-gpoint-main/test/nmea_test.lua deleted file mode 100644 index b6e4721ee..000000000 --- a/luci-app-gpoint-main/test/nmea_test.lua +++ /dev/null @@ -1,547 +0,0 @@ -common_path = '/usr/share/gpoint/tests/luaunitlib/?.lua;' -package.path = common_path .. package.path - -lu = require('luaunit') ----------------------------------------------------------------------------- --- nmea test - --- Bitxor --- checkcrc --- getcropdata ----------------------------------------------------------------------------- - -function createGnssForm() - local GnssData = { - warning = {app, gga, rmc, vtg, gsa, gp} - } - return GnssData -end --- To calculate the checksum --- Bitwise xor -local function BitXOR(a, b) - local p, c = 1, 0 - while a > 0 and b > 0 do - local ra, rb = a % 2, b % 2 - if ra ~= rb then c = c + p end - a, b, p = (a - ra) / 2, (b - rb) / 2, p * 2 - end - - if a < b then a = b end - while a > 0 do - local ra = a % 2 - if ra > 0 then c = c + p end - a, p = (a - ra) / 2, p * 2 - end - return c -end - --- To calculate the checksum -function decimalToHex(num) - if num == 0 then - return '0' - end - - local neg = false - if num < 0 then - neg = true - num = num * -1 - end - - local hexstr = "0123456789ABCDEF" - local result = "" - while num > 0 do - local n = math.mod(num, 16) - result = string.sub(hexstr, n + 1, n + 1) .. result - num = math.floor(num / 16) - end - - if neg then - result = '-' .. result - end - return result -end - --- Сalculate the checksum (CRC-8) -function checkCRC(data) - local crc8 = string.sub(data, #data - 1) - data = string.sub(data, 2, #data - 3) - - local b_sum = string.byte(data, 1) - for i = 2, #data do - b_sum = BitXOR(b_sum, string.byte(data, i)) - end - - return decimalToHex(b_sum) == crc8 and true or false -end - ---Converting coordinates from the NMEA protocol to degrees -function nmeaCoordinatesToDouble(coord) - local deg = math.floor(coord / 100) - return deg + (coord - 100 * deg) / 60 -end - ---We are looking for the desired data line in the line received from the device -function findInResp(data, begin) - local err = true - local b = string.find(data, begin) - local e = string.find(data, "\r\n", b) - - if b and e then - err = false - else - b = nil - e = nil - end - return err, b, e -end - -function getCropData(data, msg) - local err, b, e = findInResp(data, msg) - if not err then - data = string.gsub(string.sub(data, b, e), '%c', "") - if checkCRC(data) then - data = string.gsub(data, msg, '', 1) - data = string.gsub(data, "*%d+%w+", '', 1) - err = {false, "OK"} - else - err = {true, "Checksum error"} - data = nil - end - else - err = {true, "No data found"} - data = nil - end - return err, data -end - --- Creating a table with data before adding data to a single space -function doTable(data, keys) - local tabl = {} - - while string.find(data, ',,') do - data = string.gsub(data, ',,', ",-,") - end - - local i = 1 - for val in string.gmatch(data, "[^,]+") do - tabl[keys[i]] = val - i = i + 1 - end - return tabl -end - --- The function of searching the time zone by the received coordinates -function findTimeZone(time, date, lon) - local datetime = { year,month,day,hour,min,sec } - -- calculate the time zone by coordinates - local timeZone = math.floor((tonumber(lon) + (7.5 * (tonumber(lon) > 0 and 1.0 or -1.0))) / 15.0) - - datetime.hour, datetime.min, datetime.sec = string.match(time, "(%d%d)(%d%d)(%d%d)") - datetime.day, datetime.month, datetime.year = string.match(date,"(%d%d)(%d%d)(%d%d)") - datetime.year = "20" .. datetime.year -- Someone change this to 21 in the 2100 year - - --we request the unix time and then add the time zone - local unix = os.time(datetime) - unix = unix + ((math.floor(timeZone* 100)) % 100) * 36 - unix = unix + math.floor(timeZone) * 3600 - - return os.date("*t", unix) -end --- Add 0 for the time and date values if < 10 -function addZero(val) - return tonumber(val) > 9 and tostring(val) or '0' .. tostring(val) -end - ---------------------------------------------------------------------------------------------------------------- --- GGA - Global Positioning System Fix Data -function getGGA(resp) - local err, gga = getCropData(resp, "$GPGGA,") - if not err[1] then - local ggakeys = { - "utc", -- UTC of this position report, hh is hours, mm is minutes, ss.ss is seconds. - "latitude", -- Latitude, dd is degrees, mm.mm is minutes - "ne", -- N or S (North or South) - "longitude", -- Longitude, dd is degrees, mm.mm is minutes - "ew", -- E or W (East or West) - "qual", -- GPS Quality Indicator (non null) - "sat", -- Number of satellites in use, 00 - 12 - "hdp", -- Horizontal Dilution of precision (meters) - "alt", -- Antenna Altitude above/below mean-sea-level (geoid) (in meters) - "ualt", -- Units of antenna altitude, meters - "gsep", -- Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level - "ugsep", -- Units of geoidal separation, meters - "age", -- Age of differential GPS data, time in seconds since last SC104 type 1 or 9 update, null field when DGPS is not used - "drs" -- Differential reference station ID, 0000-1023 - } - - if string.gsub(gga, ',', '') ~= '0' then - gga = doTable(gga, ggakeys) - else - err = {true, "Bad GGA data"} - gga = nil - end - end - return err, gga -end - --- RMC - Recommended Minimum Navigation Information -function getRMC(resp) - local err, rmc = getCropData(resp, "$GPRMC,") - if not err[1] then - local rmckeys = { - "utc", -- UTC of position fix, hh is hours, mm is minutes, ss.ss is seconds. - "valid", -- Status, A = Valid, V = Warning - "latitude", -- Latitude, dd is degrees. mm.mm is minutes. - "ns", -- N or S - "longitude", -- Longitude, ddd is degrees. mm.mm is minutes. - "ew", -- E or W - "knots", -- Speed over ground, knots - "tmgdt", -- Track made good, degrees true - "date", -- Date, ddmmyy - "mv", -- Magnetic Variation, degrees - "ewm", -- E or W - "nstat" -- Nav Status (NMEA 4.1 and later) A=autonomous, D=differential, E=Estimated, -> - -- -> M=Manual input mode N=not valid, S=Simulator, V = Valid - } - - if not string.find(rmc, 'V') then - rmc = doTable(rmc, rmckeys) - else - err = {true, "Bad RMC data"} - rmc = nil - end - end - return err, rmc -end - --- VTG - Track made good and Ground speed -function getVTG(resp) - local err, vtg = getCropData(resp, "$GPVTG,") - if not err[1] then - local vtgkeys = { - "course_t", -- Course over ground, degrees True - 't', -- T = True - "course_m", -- Course over ground, degrees Magnetic - 'm', -- M = Magnetic - "knots", -- Speed over ground, knots - 'n', -- N = Knots - "speed", -- Speed over ground, km/hr - 'k', -- K = Kilometers Per Hour - "faa" -- FAA mode indicator (NMEA 2.3 and later) - } - - if string.find(vtg, 'A') or string.find(vtg, 'D') then - vtg = doTable(vtg, vtgkeys) - else - err = {true, "Bad VTG data"} - vtg = nil - end - end - return err, vtg -end - ---GSA - GPS DOP and active satellites -function getGSA(resp) - local err, gsa = getCropData(resp, "$GPGSA,") - if not err[1] then - local gsakeys = { - "smode", -- Selection mode: M=Manual, forced to operate in 2D or 3D, A=Automatic, 2D/3D - "mode", -- Mode (1 = no fix, 2 = 2D fix, 3 = 3D fix) - "id1", -- ID of 1st satellite used for fix - "id2", -- ID of 2nd satellite used for fix - "id3", -- ID of 3rd satellite used for fix - "id4", -- ID of 4th satellite used for fix - "id5", -- ID of 5th satellite used for fix - "id6", -- ID of 6th satellite used for fix - "id7", -- ID of 7th satellite used for fix - "id8", -- ID of 8th satellite used for fix - "id9", -- ID of 9th satellite used for fix - "id10", -- ID of 10th satellite used for fix - "id11", -- ID of 11th satellite used for fix - "id12", -- ID of 12th satellite used for fix - "pdop", -- PDOP - "hdop", -- HDOP - "vdop" -- VDOP - } - - if string.find(gsa, '2') then - gsa = doTable(gsa, gsakeys) - else - err = {true, "Bad GSA data"} - gsa = nil - end - end - return err, gsa -end - -function parseAllData(resp) - local GnssData = createGnssForm() - GnssData.warning.gga, GnssData["GGA"] = getGGA(resp) - GnssData.warning.rmc, GnssData["RMC"] = getRMC(resp) - GnssData.warning.vtg, GnssData["VTG"] = getVTG(resp) - GnssData.warning.gsa, GnssData["GSA"] = getGSA(resp) - return GnssData -end - --- This function prepares data for the web application (Some custom data) -function getGPoint(resp) - - local web = { - longitude = '-', - latitude = '-', - altitude = '-', - utc = '-', - date = '-', - nsat = '-', - hdop = '-', - cog = '-', - spkm = '-' - } - - local GnssData = parseAllData(resp) - local err = {true, ""} - - if not GnssData.warning.gga[1] then - web.latitude = string.format("%0.6f", nmeaCoordinatesToDouble(GnssData.GGA.latitude)) - web.longitude = string.format("%0.6f",nmeaCoordinatesToDouble(GnssData.GGA.longitude)) - web.altitude = GnssData.GGA.alt - web.nsat = GnssData.GGA.sat - web.hdop = GnssData.GGA.hdp - else - err[2] = "GGA: " .. GnssData.warning.gga[2] .. ' ' - end - - if not GnssData.warning.vtg[1] then - web.cog = GnssData.VTG.course_t - web.spkm = GnssData.VTG.speed - else - err[2] = err[2] .. "VTG: " .. GnssData.warning.vtg[2] .. ' ' - end - - if not GnssData.warning.rmc[1] then - local dateTime = findTimeZone(GnssData.RMC.utc, GnssData.RMC.date, nmeaCoordinatesToDouble(GnssData.RMC.longitude)) - - web.utc = string.format("%s:%s", addZero(dateTime.hour), addZero(dateTime.min)) - web.date = string.format("%s.%s.%d", addZero(dateTime.day), addZero(dateTime.month), dateTime.year) - else - err[2] = err[2] .. "RMC: " .. GnssData.warning.vtg[2] - end - - if GnssData.warning.gga[1] and GnssData.warning.vtg[1] and GnssData.warning.rmc[1] then - err[2] = "Updating data..." - else - err = {false, "OK"} - end - - return err, web -end - ------------------------------------------------------------------------------------ --- public ------------------------------------------------------------------------------------ - -function getData(line, port) - local err, resp = serial.read(port) - local GnssData = createGnssForm() - if err[1] then - GnssData.warning.app = {true, err[2]} - return GnssData - end - - GnssData.warning.app = {false, "OK"} - - if line == "GP" then - GnssData.warning.gp, GnssData["gp"] = getGPoint(resp) - elseif line == "GGA" then - GnssData.warning.gga, GnssData["gga"] = getGGA(resp) - elseif line == "RMC" then - GnssData.warning.rmc, GnssData["rmc"] = getRMC(resp) - elseif line == "VTG" then - GnssData.warning.vtg, GnssData["vtg"] = getVTG(resp) - elseif line == "GSA" then - GnssData.warning.gsa, GnssData["gsa"] = getGSA(resp) - else - GnssData.warning.app = {true, "Bad argument..."} - end - return GnssData -end - -function getAllData(port) - local err, resp = serial.read(port) - local GnssData = createGnssForm() - if err[1] then - GnssData.warning.app = {true, err[2]} - return GnssData - end - - GnssData = parseAllData(resp) - GnssData.warning.gp, GnssData["gp"] = getGPoint(resp) - GnssData.warning.app = {false, "OK"} - return GnssData -end - ------------------------------------------------------------------------------- - -local goodGNSSSdata = { - "$GPRMC,113702.568,V,4154.931,N,08002.497,W,95.5,0.02,220721,,E*4E", - "$GPGGA,113703.568,4154.931,N,08002.497,W,0,00,,,M,,M,,*52", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.1,0.8,0.6*3F", - "$GPRMC,113705.568,V,4154.933,N,08002.497,W,86.0,-0.05,220721,,E*66", - "$GPGGA,113706.568,4154.933,N,08002.497,W,0,00,0.8,,M,,M,,*73", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.0,0.4*36", - "$GPRMC,113708.568,V,4154.935,N,08002.498,W,55.1,-0.10,220721,,E*69", - "$GPGGA,113709.568,4154.935,N,08002.498,W,0,00,0.0,,M,,M,,*7D", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.2,0.8*3C", - "$GPRMC,113711.568,V,4154.937,N,08002.498,W,95.0,-0.10,220721,,E*6E", - "$GPGGA,113712.568,4154.937,N,08002.498,W,0,00,0.2,,M,,M,,*77", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.7,0.6,0.3*32", - "$GPRMC,113714.568,V,4154.939,N,08002.498,W,28.0,-0.07,220721,,E*65", - "$GPGGA,113715.568,4154.939,N,08002.498,W,0,00,0.6,,M,,M,,*7A", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,1.0,1.0,0.5*34", - "$GPRMC,113717.568,V,4154.940,N,08002.498,W,30.1,0.03,220721,,E*49", - "$GPGGA,113718.568,4154.940,N,08002.498,W,0,00,1.0,,M,,M,,*7E", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.5,0.1,0.2*36", - "$GPRMC,113720.568,V,4154.942,N,08002.498,W,0.2,-0.02,220721,,E*53", - "$GPGGA,113721.568,4154.942,N,08002.498,W,0,00,0.1,,M,,M,,*76", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.5,0.7*30", - "$GPRMC,113723.568,V,4154.944,N,08002.498,W,53.6,0.05,220721,,E*4E", - "$GPGGA,113724.568,4154.944,N,08002.498,W,0,00,0.5,,M,,M,,*71", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,1.0,0.6,0.1*37", - "$GPRMC,113726.568,V,4154.946,N,08002.498,W,76.6,0.04,220721,,E*4F", - "$GPGGA,113727.568,4154.946,N,08002.498,W,0,00,0.6,,M,,M,,*73", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.2,0.3,0.7*37", - "$GPRMC,113729.568,V,4154.948,N,08002.497,W,30.9,0.12,220721,,E*4B", - "$GPGGA,113730.568,4154.948,N,08002.497,W,0,00,0.3,,M,,M,,*71", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.5,0.2,0.2*34", - "$GPRMC,113732.568,V,4154.949,N,08002.497,W,47.2,0.20,220721,,E*4A", - "$GPGGA,113733.568,4154.949,N,08002.497,W,0,00,0.2,,M,,M,,*72", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.3,0.8,0.2*39", - "$GPRMC,113735.568,V,4154.951,N,08002.496,W,31.1,0.13,220721,,E*47", - "$GPGGA,113736.568,4154.951,N,08002.496,W,0,00,0.8,,M,,M,,*75", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.6,0.1*35", - "$GPRMC,113738.568,V,4154.953,N,08002.496,W,58.2,0.10,220721,,E*47", - "$GPGGA,113739.568,4154.953,N,08002.496,W,0,00,0.6,,M,,M,,*76", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.6,0.9,0.7*39", - "$GPRMC,113741.568,V,4154.955,N,08002.496,W,88.3,0.03,220721,,E*41", - "$GPGGA,113742.568,4154.955,N,08002.496,W,0,00,0.9,,M,,M,,*73", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.8,0.8,0.1*30", - "$GPRMC,113744.568,V,4154.956,N,08002.496,W,89.3,0.10,220721,,E*44", - "$GPGGA,113745.568,4154.956,N,08002.496,W,0,00,0.8,,M,,M,,*76", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.9,0.2,1.0*3B", - "$GPRMC,113747.568,V,4154.958,N,08002.495,W,99.1,0.14,220721,,E*4D", - "$GPGGA,113748.568,4154.958,N,08002.495,W,0,00,0.2,,M,,M,,*7C", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.1,0.2*35", - "$GPRMC,113750.568,V,4154.960,N,08002.495,W,84.0,0.19,220721,,E*40", - "$GPGGA,113751.568,4154.960,N,08002.495,W,0,00,0.1,,M,,M,,*7C", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.3,1.0,0.5*36", - "$GPRMC,113753.568,V,4154.962,N,08002.495,W,24.0,0.13,220721,,E*41", - "$GPGGA,113754.568,4154.962,N,08002.495,W,0,00,1.0,,M,,M,,*7B", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.8,0.9*37", - "$GPRMC,113756.568,V,4154.963,N,08002.494,W,27.8,0.03,220721,,E*4E", - "$GPGGA,113757.568,4154.963,N,08002.494,W,0,00,0.8,,M,,M,,*71", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.5,0.4,0.7*37" -} - -local badGNSSSdata = { - "$GPRMC,113702.568,V,4154.931,N,08002.497,W,95.5,0.02,220721,,E*48", - "$GPGGA,113703.568,4154.931,N,08002.497,W,0,00,,,M,,M,,*54", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.1,0.8,0.6*33", - "$GPRMC,113720.568,V,4154.942,N,08002.498,W,0.2,-0.02,220721,,E*5F", - "$GPGGA,113721.568,4154.942,N,08002.498,W,0,00,0.1,,M,,M,,*82", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.5,0.7*35", - "$GPRMC,113723.568,V,4154.944,N,08002.498,W,53.6,0.05,220721,,E*5A", - "$GPGGA,113724.568,4154.944,N,08002.498,W,0,00,0.5,,M,,M,,*12", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,1.0,0.6,0.1*35", - "$GPRMC,113726.568,V,4154.946,N,08002.498,W,76.6,0.04,220721,,E*9E", - "$GPGGA,113727.568,4154.946,N,08002.498,W,0,00,0.6,,M,,M,,*94", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.2,0.3,0.7*32", - "$GPRMC,113729.568,V,4154.948,N,08002.497,W,30.9,0.12,220721,,E*9C", - "$GPGGA,113730.568,4154.948,N,08002.497,W,0,00,0.3,,M,,M,,*79", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.5,0.2,0.2*39", - "$GPRMC,113705.568,V,4154.933,N,08002.497,W,86.0,-0.05,220721,,E*90", - "$GPGGA,113706.568,4154.933,N,08002.497,W,0,00,0.8,,M,,M,,*42", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.0,0.4*43", - "$GPRMC,113708.568,V,4154.935,N,08002.498,W,55.1,-0.10,220721,,E*44", - "$GPGGA,113709.568,4154.935,N,08002.498,W,0,00,0.0,,M,,M,,*4A", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.2,0.8*4D", - "$GPRMC,113711.568,V,4154.937,N,08002.498,W,95.0,-0.10,220721,,E*44", - "$GPGGA,113712.568,4154.937,N,08002.498,W,0,00,0.2,,M,,M,,*44", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.7,0.6,0.3*4D", - "$GPRMC,113714.568,V,4154.939,N,08002.498,W,28.0,-0.07,220721,,E*4D", - "$GPGGA,113715.568,4154.939,N,08002.498,W,0,00,0.6,,M,,M,,*4D", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,1.0,1.0,0.5*24", - "$GPRMC,113717.568,V,4154.940,N,08002.498,W,30.1,0.03,220721,,E*59", - "$GPGGA,113718.568,4154.940,N,08002.498,W,0,00,1.0,,M,,M,,*4D", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.5,0.1,0.2*39", - "$GPGGA,113736.568,4154.951,N,08002.496,W,0,00,0.8,,M,,M,,*79", - "$GPGSA,A,3,09,02,08,05,11,15,,,,,,,0.2,0.6,0.1*39", - "$GPRMC,113738.568,V,4154.953,N,08002.496,W,58.2,0.10,220721,,E*67", - "$GPGGA,113739.568,4154.953,N,08002.496,W,0,00,0.6,,M,,M,,*79", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.6,0.9,0.7*35", - "$GPRMC,113741.568,V,4154.955,N,08002.496,W,88.3,0.03,220721,,E*31", - "$GPGGA,113742.568,4154.955,N,08002.496,W,0,00,0.9,,M,,M,,*33", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.8,0.8,0.1*34", - "$GPRMC,113744.568,V,4154.956,N,08002.496,W,89.3,0.10,220721,,E*34", - "$GPGGA,113745.568,4154.956,N,08002.496,W,0,00,0.8,,M,,M,,*75", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.9,0.2,1.0*4B", - "$GPRMC,113747.568,V,4154.958,N,08002.495,W,99.1,0.14,220721,,E*5D", - "$GPGGA,113748.568,4154.958,N,08002.495,W,0,00,0.2,,M,,M,,*5C", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.1,0.2*55", - "$GPRMC,113750.568,V,4154.960,N,08002.495,W,84.0,0.19,220721,,E*50", - "$GPGGA,113751.568,4154.960,N,08002.495,W,0,00,0.1,,M,,M,,*5C", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.3,1.0,0.5*35", - "$GPRMC,113753.568,V,4154.962,N,08002.495,W,24.0,0.13,220721,,E*51", - "$GPGGA,113754.568,4154.962,N,08002.495,W,0,00,1.0,,M,,M,,*5B", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.7,0.8,0.9*35", - "$GPRMC,113756.568,V,4154.963,N,08002.494,W,27.8,0.03,220721,,E*5E", - "$GPGGA,113757.568,4154.963,N,08002.494,W,0,00,0.8,,M,,M,,*51", - "$GPGSA,A,2,09,02,08,05,11,15,,,,,,,0.5,0.4,0.7*57" -} - -local GNSStr = "$GPRMC,143753.498,V,3854.930,N,07902.496,W,91.3,0.75,220721,,E*4B\r\n\ - $GPGGA,143754.498,3854.930,N,07902.496,W,0,00,,,M,,M,,*53\r\n\ - $GPGSA,A,2,13,09,13,09,18,16,,,,,,,0.1,0.0,0.2*3E\r\n\ - $GPRMC,143756.498,V,3854.931,N,07902.494,W,92.7,0.76,220721,,E*49\r\n\ - $GPGGA,143757.498,3854.931,N,07902.494,W,0,00,0.0,,M,,M,,*7D\r\n\ - $GPGSA,A,2,13,09,13,09,18,16,,,,,,,0.4,0.4,0.5*38\r\n\ - $GPRMC,143759.498,V,3854.932,N,07902.492,W,15.5,0.75,220721,,E*4D\r\n" - -local badCRC = "$GPRMC,143753.498,V,3854.930,N,07902.496,W,91.3,0.75,220721,,E*6B\r\n\ - $GPGGA,143754.498,3854.930,N,07902.496,W,0,00,,,M,,M,,*43\r\n\ - $GPGSA,A,2,13,09,13,09,18,16,,,,,,,0.1,0.0,0.2*5E\r\n\ - $GPRMC,143756.498,V,3854.931,N,07902.494,W,92.7,0.76,220721,,E*48\r\n\ - $GPGGA,143757.498,3854.931,N,07902.494,W,0,00,0.0,,M,,M,,*4D\r\n\ - $GPGSA,A,2,13,09,13,09,18,16,,,,,,,0.4,0.4,0.5*39\r\n\ - $GPRMC,143759.498,V,3854.932,N,07902.492,W,15.5,0.75,220721,,E*3D\r\n" - -local nmeaDataType = {"$GPGSA,", "$GPRMC,", "$GPGGA,"} -local badString = "oskdsajdij232391i*&^^&7^&^(*&*YDUDHJSBDNBNVyywfdywf" - -function testBitXOR() - lu.assertEquals(BitXOR(string.byte('q'), string.byte('r')), 3) - lu.assertEquals(BitXOR(string.byte('a'), string.byte('b')), 3) - lu.assertEquals(BitXOR(string.byte('1'), string.byte('5')), 4) - lu.assertEquals(BitXOR(string.byte('0'), string.byte('0')), 0) - lu.assertEquals(BitXOR(string.byte('9'), string.byte('1')), 8) - lu.assertEquals(BitXOR(string.byte('f'), string.byte('w')), 17) -end - -function testCRC() - for i = 1, #goodGNSSSdata do - lu.assertEquals(checkCRC(goodGNSSSdata[i]), true) - end - for i = 1, #badGNSSSdata do - lu.assertEquals(checkCRC(badGNSSSdata[i]), false) - end -end - -function testCropData() - for i = 1, #nmeaDataType do - lu.assertEquals(getCropData("", nmeaDataType[i]), {true, "No data found"}) - lu.assertEquals(getCropData(badString, nmeaDataType[i]), {true, "No data found"}) - lu.assertEquals(getCropData(badCRC, nmeaDataType[i]), {true, "Checksum error"}) - lu.assertEquals(getCropData(GNSStr, nmeaDataType[i]), {false, "OK"}) - end -end - -os.exit(lu.LuaUnit.run()) \ No newline at end of file diff --git a/luci-app-gpoint-main/test/nmea_test2.lua b/luci-app-gpoint-main/test/nmea_test2.lua deleted file mode 100644 index fc8121981..000000000 --- a/luci-app-gpoint-main/test/nmea_test2.lua +++ /dev/null @@ -1,56 +0,0 @@ -common_path = '/usr/share/gpoint/lib/?.lua;' -package.path = common_path .. package.path - - -function printData(data, key) - for i, j in pairs(data) do - if i == key then - print("----->",i) - for k, v in pairs(j) do - print(k, v) - print("*********************") - end - end - end - print("----------------------------------------------") -end - -function printError(data) - for i, j in pairs(data) do - print(i) - for k, v in pairs(j) do - if k == "app" then - for m, n in pairs(v) do - print(m, n) - end - end - end - end -end - -local nmea = require("nmea") -local port = "/dev/ttyUSB1" - --- test get NMEA data (GGA) ---local GGA = nmea.getData("GGA", port) ---printData(GGA, "gga") - --- test get NMEA data (GNS) ---local GNS = nmea.getData("GNS", port) ---printData(GNS, "gns") - --- test get RMC data (RMC) ---local RMC = nmea.getData("RMC", port) ---printData(RMC, "rmc") - --- test get NMEA data (VTG) ---local VTG = nmea.getData("VTG", port) ---printData(VTG, "vtg") - --- test get NMEA data (GSA) ---local GSA = nmea.getData("GSA", port) ---printData(GSA, "gsa") - --- test get NMEA data (BAD STRING) ---local AAA = nmea.getData("AAA", port) ---printError(AAA) \ No newline at end of file diff --git a/luci-app-gpoint-main/test/serial_test.lua b/luci-app-gpoint-main/test/serial_test.lua deleted file mode 100644 index 8529ff9e1..000000000 --- a/luci-app-gpoint-main/test/serial_test.lua +++ /dev/null @@ -1,16 +0,0 @@ -common_path = '/usr/share/gpoint/lib/?.lua;' -package.path = common_path .. package.path - -serial = require("serial") - -function serial_read(port) - local err, data = serial.read(port) - assert(err, data) - print("Error data: OK") - assert(data) - print("Data from serial: OK") -end -local port = "/dev/ttyUSB1" -serial_read(port) - -print("OK") \ No newline at end of file